aboutsummaryrefslogtreecommitdiff
path: root/client.go
diff options
context:
space:
mode:
authorAdnan Maolood <[email protected]>2020-11-05 15:27:12 -0500
committerAdnan Maolood <[email protected]>2020-11-05 15:27:12 -0500
commitb76080c86312b18f18c6333766895aac410f31bc (patch)
treef3149548a5f81defe4d84f18c481ce62776d0aae /client.go
parentDocument CertificateOptions (diff)
downloadgo-gemini-b76080c86312b18f18c6333766895aac410f31bc.tar.xz
go-gemini-b76080c86312b18f18c6333766895aac410f31bc.zip
Refactor KnownHosts
Diffstat (limited to 'client.go')
-rw-r--r--client.go54
1 files changed, 31 insertions, 23 deletions
diff --git a/client.go b/client.go
index 306e758..7dd7b35 100644
--- a/client.go
+++ b/client.go
@@ -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")
}