1
0
mirror of https://git.sr.ht/~adnano/go-gemini synced 2024-11-23 08:32:02 +01:00

Implement server certificate store

This commit is contained in:
adnano 2020-10-11 23:48:18 -04:00
parent cdf49622e2
commit 8de7f5d8c4
7 changed files with 58 additions and 25 deletions

35
cert.go

@ -15,7 +15,40 @@ import (
)
// CertificateStore maps hostnames to certificates.
type CertificateStore map[string]*tls.Certificate
type CertificateStore struct {
store map[string]tls.Certificate
}
// Add adds a certificate for the given hostname to the store.
func (c *CertificateStore) Add(hostname string, cert tls.Certificate) {
if c.store == nil {
c.store = map[string]tls.Certificate{}
}
c.store[hostname] = cert
}
// Lookup returns the certificate for the given hostname.
func (c *CertificateStore) Lookup(hostname string) (*tls.Certificate, error) {
cert, ok := c.store[hostname]
if !ok {
return nil, ErrUnknownCertificate
}
// TODO: Ensure that the certificate is not expired
// if expired {
// return nil, ErrInvalidCertificate
// }
return &cert, nil
}
// Load loads certificates from the given path.
// The path should lead to a directory containing certificates and private keys
// in the form hostname.crt and hostname.key.
// For example, the hostname "localhost" would have the corresponding files
// localhost.crt (certificate) and localhost.key (private key).
func (c *CertificateStore) Load(path string) error {
// TODO: Implement this
return nil
}
// NewCertificate creates and returns a new parsed certificate.
func NewCertificate(host string, duration time.Duration) (tls.Certificate, error) {

@ -218,10 +218,8 @@ func (c *Client) Send(req *Request) (*Response, error) {
return req.Certificate, nil
}
// If we have already stored the certificate, return it
if c.CertificateStore != nil {
if cert, ok := c.CertificateStore[req.Hostname()]; ok {
return cert, nil
}
if cert, err := c.CertificateStore.Lookup(req.Hostname()); err == nil {
return cert, nil
}
return &tls.Certificate{}, nil
},
@ -280,10 +278,6 @@ func (c *Client) Send(req *Request) (*Response, error) {
if req.Certificate != nil {
return resp, nil
}
// Create the certificate store if it does not exist
if c.CertificateStore == nil {
c.CertificateStore = CertificateStore{}
}
if c.GetCertificate != nil {
if cert := c.GetCertificate(req.Hostname(), c.CertificateStore); cert != nil {
req.Certificate = cert

@ -52,9 +52,8 @@ func main() {
handler.HandleFunc("/admin", admin)
handler.HandleFunc("/logout", logout)
server := &gmi.Server{
Certificate: cert,
}
server := &gmi.Server{}
server.CertificateStore.Add("localhost", cert)
server.Handle("localhost", handler)
if err := server.ListenAndServe(); err != nil {

@ -48,7 +48,7 @@ func init() {
}
client.GetCertificate = func(hostname string, store gmi.CertificateStore) *tls.Certificate {
// If the certificate is in the store, return it
if cert, ok := store[hostname]; ok {
if cert, err := store.Lookup(hostname); err == nil {
return cert
}
// Otherwise, generate a certificate
@ -59,7 +59,7 @@ func init() {
return nil
}
// Store and return the certificate
store[hostname] = &cert
store.Add(hostname, cert)
return &cert
}
}

@ -23,9 +23,8 @@ func main() {
mux := &gmi.ServeMux{}
mux.Handle("/", gmi.FileServer(gmi.Dir("/var/www")))
server := gmi.Server{
Certificate: cert,
}
server := gmi.Server{}
server.CertificateStore.Add("localhost", cert)
server.Handle("localhost", mux)
server.ListenAndServe()
}

@ -58,7 +58,7 @@ func init() {
}
DefaultClient.GetCertificate = func(hostname string, store CertificateStore) *tls.Certificate {
// If the certificate is in the store, return it
if cert, ok := store[hostname]; ok {
if cert, err := store.Lookup(hostname); err == nil {
return cert
}
// Otherwise, generate a certificate
@ -68,7 +68,7 @@ func init() {
return nil
}
// Store and return the certificate
store[hostname] = &cert
store.Add(hostname, cert)
return &cert
}
}

@ -27,9 +27,13 @@ type Server struct {
// If Addr is empty, the server will listen on the address ":1965".
Addr string
// Certificate provides a TLS certificate for use by the server.
// A self-signed certificate is recommended.
Certificate tls.Certificate
// CertificateStore contains the certificates used by the server.
CertificateStore CertificateStore
// GetCertificate, if not nil, will be called to retrieve the certificate
// to use for a given hostname.
// If the certificate is nil, the connection will be aborted.
GetCertificate func(hostname string) *tls.Certificate
// registered handlers
handlers []handlerEntry
@ -44,7 +48,6 @@ func (s *Server) Handle(host string, handler Handler) {
if handler == nil {
panic("gmi: nil handler")
}
s.HandleScheme("gemini", host, handler)
}
@ -79,8 +82,13 @@ func (s *Server) ListenAndServe() error {
config := &tls.Config{
InsecureSkipVerify: true,
MinVersion: tls.VersionTLS12,
Certificates: []tls.Certificate{s.Certificate},
ClientAuth: tls.RequestClientCert,
GetCertificate: func(h *tls.ClientHelloInfo) (*tls.Certificate, error) {
if s.GetCertificate != nil {
return s.GetCertificate(h.ServerName), nil
}
return s.CertificateStore.Lookup(h.ServerName)
},
ClientAuth: tls.RequestClientCert,
}
tlsListener := tls.NewListener(ln, config)
return s.Serve(tlsListener)