diff options
| author | Adnan Maolood <[email protected]> | 2020-11-05 15:27:12 -0500 |
|---|---|---|
| committer | Adnan Maolood <[email protected]> | 2020-11-05 15:27:12 -0500 |
| commit | b76080c86312b18f18c6333766895aac410f31bc (patch) | |
| tree | f3149548a5f81defe4d84f18c481ce62776d0aae /client.go | |
| parent | Document CertificateOptions (diff) | |
| download | go-gemini-b76080c86312b18f18c6333766895aac410f31bc.tar.xz go-gemini-b76080c86312b18f18c6333766895aac410f31bc.zip | |
Refactor KnownHosts
Diffstat (limited to 'client.go')
| -rw-r--r-- | client.go | 54 |
1 files changed, 31 insertions, 23 deletions
@@ -4,6 +4,7 @@ import ( "bufio" "crypto/tls" "crypto/x509" + "errors" "net" "net/url" "path" @@ -164,7 +165,7 @@ func (c *Client) do(req *Request, via []*Request) (*Response, error) { } } else if len(via) > 5 { // Default policy of no more than 5 redirects - return resp, ErrTooManyRedirects + return resp, errors.New("gemini: too many redirects") } return c.do(redirect, via) } @@ -182,13 +183,14 @@ func (c *Client) getClientCertificate(req *Request) (*tls.Certificate, error) { // Search recursively for the certificate scope := req.URL.Hostname() + strings.TrimSuffix(req.URL.Path, "/") for { - cert, err := c.Certificates.Lookup(scope) - if err == nil { - // Store the certificate - req.Certificate = cert - return cert, err - } - if err == ErrCertificateExpired { + cert, ok := c.Certificates.Lookup(scope) + if ok { + // Ensure that the certificate is not expired + if cert.Leaf != nil && !time.Now().After(cert.Leaf.NotAfter) { + // Store the certificate + req.Certificate = &cert + return &cert, nil + } break } scope = path.Dir(scope) @@ -216,21 +218,27 @@ func (c *Client) verifyConnection(req *Request, cs tls.ConnectionState) error { return nil } // Check the known hosts - err := c.KnownHosts.Lookup(hostname, cert) - switch err { - case ErrCertificateExpired, ErrCertificateNotFound: - // See if the client trusts the certificate - if c.TrustCertificate != nil { - switch c.TrustCertificate(hostname, cert) { - case TrustOnce: - c.KnownHosts.AddTemporary(hostname, cert) - return nil - case TrustAlways: - c.KnownHosts.Add(hostname, cert) - return nil - } + knownHost, ok := c.KnownHosts.Lookup(hostname) + if ok && time.Now().After(cert.NotAfter) { + // Not expired + fingerprint := NewFingerprint(cert) + if knownHost.Hex != fingerprint.Hex { + return errors.New("gemini: fingerprint does not match") + } + return nil + } + + // Unknown certificate + // See if the client trusts the certificate + if c.TrustCertificate != nil { + switch c.TrustCertificate(hostname, cert) { + case TrustOnce: + c.KnownHosts.AddTemporary(hostname, cert) + return nil + case TrustAlways: + c.KnownHosts.Add(hostname, cert) + return nil } - return ErrCertificateNotTrusted } - return err + return errors.New("gemini: certificate not trusted") } |