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:
parent
cdf49622e2
commit
8de7f5d8c4
35
cert.go
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) {
|
||||
|
10
client.go
10
client.go
@ -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
|
||||
}
|
||||
}
|
||||
|
20
server.go
20
server.go
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user