diff --git a/cert/ca_pool.go b/cert/ca_pool.go index 40043f4de..d262d62ad 100644 --- a/cert/ca_pool.go +++ b/cert/ca_pool.go @@ -82,12 +82,12 @@ func (ncp *CAPool) AddCA(c Certificate) error { sum, err := c.Fingerprint() if err != nil { - return fmt.Errorf("could not calculate shasum for provided CA; error: %s; %s", err, c.Name()) + return fmt.Errorf("could not calculate fingerprint for provided CA; error: %w; %s", err, c.Name()) } cc := &CachedCertificate{ Certificate: c, - ShaSum: sum, + Fingerprint: sum, InvertedGroups: make(map[string]struct{}), } @@ -131,21 +131,21 @@ func (ncp *CAPool) VerifyCertificate(now time.Time, c Certificate) (*CachedCerti if c == nil { return nil, fmt.Errorf("no certificate") } - sha, err := c.Fingerprint() + fp, err := c.Fingerprint() if err != nil { - return nil, fmt.Errorf("could not calculate shasum to verify: %w", err) + return nil, fmt.Errorf("could not calculate fingerprint to verify: %w", err) } - signer, err := ncp.verify(c, now, sha, "") + signer, err := ncp.verify(c, now, fp, "") if err != nil { return nil, err } cc := CachedCertificate{ - Certificate: c, - InvertedGroups: make(map[string]struct{}), - ShaSum: sha, - signerShaSum: signer.ShaSum, + Certificate: c, + InvertedGroups: make(map[string]struct{}), + Fingerprint: fp, + signerFingerprint: signer.Fingerprint, } for _, g := range c.Groups() { @@ -158,12 +158,12 @@ func (ncp *CAPool) VerifyCertificate(now time.Time, c Certificate) (*CachedCerti // VerifyCachedCertificate is the same as VerifyCertificate other than it operates on a pre-verified structure and // is a cheaper operation to perform as a result. func (ncp *CAPool) VerifyCachedCertificate(now time.Time, c *CachedCertificate) error { - _, err := ncp.verify(c.Certificate, now, c.ShaSum, c.signerShaSum) + _, err := ncp.verify(c.Certificate, now, c.Fingerprint, c.signerFingerprint) return err } -func (ncp *CAPool) verify(c Certificate, now time.Time, certSha string, signerSha string) (*CachedCertificate, error) { - if ncp.IsBlocklisted(certSha) { +func (ncp *CAPool) verify(c Certificate, now time.Time, certFp string, signerFp string) (*CachedCertificate, error) { + if ncp.IsBlocklisted(certFp) { return nil, ErrBlockListed } @@ -185,9 +185,9 @@ func (ncp *CAPool) verify(c Certificate, now time.Time, certSha string, signerSh //TODO: this is slightly different than v1.9.3 and earlier where we were matching the public key // The reason to switch is that the public key can be reused and the constraints in the ca can change // but there may be history here, double check - if len(signerSha) > 0 { - if signerSha != signer.ShaSum { - return nil, ErrSignatureMismatch + if len(signerFp) > 0 { + if signerFp != signer.Fingerprint { + return nil, ErrFingerprintMismatch } return signer, nil } @@ -206,11 +206,12 @@ func (ncp *CAPool) verify(c Certificate, now time.Time, certSha string, signerSh // GetCAForCert attempts to return the signing certificate for the provided certificate. // No signature validation is performed func (ncp *CAPool) GetCAForCert(c Certificate) (*CachedCertificate, error) { - if c.Issuer() == "" { + issuer := c.Issuer() + if issuer == "" { return nil, fmt.Errorf("no issuer in certificate") } - signer, ok := ncp.CAs[c.Issuer()] + signer, ok := ncp.CAs[issuer] if ok { return signer, nil } @@ -253,7 +254,6 @@ func checkCAConstraints(signer Certificate, notBefore, notAfter time.Time, group if len(signerGroups) > 0 { for _, g := range groups { if !slices.Contains(signerGroups, g) { - //TODO: since we no longer pre-compute the inverted groups then this is kind of slow return fmt.Errorf("certificate contained a group not present on the signing ca: %s", g) } } @@ -262,17 +262,17 @@ func checkCAConstraints(signer Certificate, notBefore, notAfter time.Time, group // If the signer has a limited set of ip ranges to issue from make sure the cert only contains a subset signingNetworks := signer.Networks() if len(signingNetworks) > 0 { - for _, subNetwork := range networks { + for _, certNetwork := range networks { found := false for _, signingNetwork := range signingNetworks { - if signingNetwork.Contains(subNetwork.Addr()) && signingNetwork.Bits() <= subNetwork.Bits() { + if signingNetwork.Contains(certNetwork.Addr()) && signingNetwork.Bits() <= certNetwork.Bits() { found = true break } } if !found { - return fmt.Errorf("certificate contained an ip assignment outside the limitations of the signing ca: %s", subNetwork.String()) + return fmt.Errorf("certificate contained an network assignment outside the limitations of the signing ca: %s", certNetwork.String()) } } } @@ -280,17 +280,17 @@ func checkCAConstraints(signer Certificate, notBefore, notAfter time.Time, group // If the signer has a limited set of subnet ranges to issue from make sure the cert only contains a subset signingUnsafeNetworks := signer.UnsafeNetworks() if len(signingUnsafeNetworks) > 0 { - for _, subUnsafeNetwork := range unsafeNetworks { + for _, certUnsafeNetwork := range unsafeNetworks { found := false for _, caNetwork := range signingUnsafeNetworks { - if caNetwork.Contains(subUnsafeNetwork.Addr()) && caNetwork.Bits() <= subUnsafeNetwork.Bits() { + if caNetwork.Contains(certUnsafeNetwork.Addr()) && caNetwork.Bits() <= certUnsafeNetwork.Bits() { found = true break } } if !found { - return fmt.Errorf("certificate contained a subnet assignment outside the limitations of the signing ca: %s", subUnsafeNetwork.String()) + return fmt.Errorf("certificate contained an unsafe network assignment outside the limitations of the signing ca: %s", certUnsafeNetwork.String()) } } } diff --git a/cert/cert.go b/cert/cert.go index 4e41c4349..8874745a8 100644 --- a/cert/cert.go +++ b/cert/cert.go @@ -101,10 +101,10 @@ type Certificate interface { // CachedCertificate represents a verified certificate with some cached fields to improve // performance. type CachedCertificate struct { - Certificate Certificate - InvertedGroups map[string]struct{} - ShaSum string - signerShaSum string + Certificate Certificate + InvertedGroups map[string]struct{} + Fingerprint string + signerFingerprint string } // UnmarshalCertificate will attempt to unmarshal a wire protocol level certificate. diff --git a/cert/errors.go b/cert/errors.go index 06ce99612..da0d1be3f 100644 --- a/cert/errors.go +++ b/cert/errors.go @@ -11,6 +11,7 @@ var ( ErrNotCA = errors.New("certificate is not a CA") ErrNotSelfSigned = errors.New("certificate is not self-signed") ErrBlockListed = errors.New("certificate is in the block list") + ErrFingerprintMismatch = errors.New("certificate fingerprint did not match") ErrSignatureMismatch = errors.New("certificate signature did not match") ErrInvalidPublicKeyLength = errors.New("invalid public key length") ErrInvalidPrivateKeyLength = errors.New("invalid private key length") diff --git a/connection_manager.go b/connection_manager.go index a0de842db..77182523f 100644 --- a/connection_manager.go +++ b/connection_manager.go @@ -448,7 +448,7 @@ func (n *connectionManager) isInvalidCertificate(now time.Time, hostinfo *HostIn } hostinfo.logger(n.l).WithError(err). - WithField("fingerprint", remoteCert.ShaSum). + WithField("fingerprint", remoteCert.Fingerprint). Info("Remote certificate is no longer valid, tearing down the tunnel") return true diff --git a/handshake_ix.go b/handshake_ix.go index 24c423d64..73e8541b9 100644 --- a/handshake_ix.go +++ b/handshake_ix.go @@ -113,7 +113,7 @@ func ixHandshakeStage1(f *Interface, addr netip.AddrPort, via *ViaSender, packet vpnIp := remoteCert.Certificate.Networks()[0].Addr().Unmap() certName := remoteCert.Certificate.Name() - fingerprint := remoteCert.ShaSum + fingerprint := remoteCert.Fingerprint issuer := remoteCert.Certificate.Issuer() if vpnIp == f.myVpnNet.Addr() { @@ -415,7 +415,7 @@ func ixHandshakeStage2(f *Interface, addr netip.AddrPort, via *ViaSender, hh *Ha vpnIp := remoteCert.Certificate.Networks()[0].Addr().Unmap() certName := remoteCert.Certificate.Name() - fingerprint := remoteCert.ShaSum + fingerprint := remoteCert.Fingerprint issuer := remoteCert.Certificate.Issuer() // Ensure the right host responded