Skip to content

Commit

Permalink
adds verify to root capability and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewpmartinez committed Aug 15, 2024
1 parent 2bbf2fe commit 61ea2c6
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 4 deletions.
41 changes: 41 additions & 0 deletions ca_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"crypto/x509"
"encoding/hex"
"github.com/pkg/errors"
"time"
)

type CaPool struct {
Expand Down Expand Up @@ -163,6 +164,46 @@ func (self *CaPool) GetChain(cert *x509.Certificate, additionalCerts ...*x509.Ce
return assembleChain(cert, chainCandidates)
}

// VerifyToRoot will obtain a chain and verify it to a root CA. This is similar to the requirements that
// OpenSSL has for TLS.
func (self *CaPool) VerifyToRoot(cert *x509.Certificate) ([][]*x509.Certificate, error) {
if cert == nil {
return nil, errors.New("cannot verify a nil certificate")
}

opts := x509.VerifyOptions{
Intermediates: self.IntermediatesAsStdPool(),
Roots: self.RootsAsStdPool(),
CurrentTime: time.Now(),
}

return cert.Verify(opts)
}

// IntermediatesAsStdPool returns all intermediates in an *x509.CertPool. Useful for calling standard x509 package
// functions.
func (self *CaPool) IntermediatesAsStdPool() *x509.CertPool {
pool := x509.NewCertPool()

for _, cert := range self.intermediates {
pool.AddCert(cert)
}

return pool
}

// RootsAsStdPool returns all intermediates in an *x509.CertPool. Useful for calling standard x509 package
// functions.
func (self *CaPool) RootsAsStdPool() *x509.CertPool {
pool := x509.NewCertPool()

for _, cert := range self.roots {
pool.AddCert(cert)
}

return pool
}

// assembleChain starts at `startCert` and build the longest chain up through ancestor signing certs as it can from `chainCandidates`.
func assembleChain(startCert *x509.Certificate, chainCandidates map[string]*x509.Certificate) []*x509.Certificate {
if startCert == nil {
Expand Down
33 changes: 33 additions & 0 deletions ca_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,39 @@ func TestCaPool(t *testing.T) {
req.Equal(pki.IntermediateA1.cert, chain[2])
req.Equal(pki.RootA.cert, chain[3])
})

t.Run("a chain can be built and verified from a nested intermediate", func(t *testing.T) {
req = require.New(t)

chains, err := pool.VerifyToRoot(pki.LeafA3.cert)

req.NoError(err)
req.Len(chains, 1)
req.Len(chains[0], 5)
req.Equal(chains[0][0], pki.LeafA3.cert)
req.Equal(chains[0][1], pki.IntermediateA3.cert)
req.Equal(chains[0][2], pki.IntermediateA2.cert)
req.Equal(chains[0][3], pki.IntermediateA1.cert)
req.Equal(chains[0][4], pki.RootA.cert)
})

t.Run("an error is returned attempting to verify a nil cert", func(t *testing.T) {
req = require.New(t)

chains, err := pool.VerifyToRoot(nil)

req.Error(err)
req.Nil(chains)
})

t.Run("an error is returned attempting to verify a leaf not in the pool", func(t *testing.T) {
req = require.New(t)

chains, err := pool.VerifyToRoot(pki.LeafC.cert)

req.Error(err)
req.Nil(chains)
})
})

}
Expand Down
7 changes: 3 additions & 4 deletions chains_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ func newRootCa() *testCa {
ExtKeyUsage: []x509.ExtKeyUsage{},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
BasicConstraintsValid: true,
MaxPathLen: -1,
}

rootBytes, err := x509.CreateCertificate(rand.Reader, root, root, &rootKey.PublicKey, rootKey)
Expand Down Expand Up @@ -488,8 +489,7 @@ func (ca *testCa) NewIntermediateWithAKID() *testCa {
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
BasicConstraintsValid: true,
AuthorityKeyId: ca.cert.SubjectKeyId,
MaxPathLen: 0,
MaxPathLenZero: true,
MaxPathLen: 5,
}

intermediateKey, err := rsa.GenerateKey(rand.Reader, 4096)
Expand Down Expand Up @@ -537,8 +537,7 @@ func (ca *testCa) NewIntermediateWithoutAKID() *testCa {
ExtKeyUsage: []x509.ExtKeyUsage{},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
BasicConstraintsValid: true,
MaxPathLen: 0,
MaxPathLenZero: true,
MaxPathLen: 5,
}

intermediateKey, err := rsa.GenerateKey(rand.Reader, 4096)
Expand Down

0 comments on commit 61ea2c6

Please sign in to comment.