Skip to content

Commit

Permalink
Add support for intermediate certificates when verifiying
Browse files Browse the repository at this point in the history
This adds an intermediate CA certificate pool to CheckOpts, allowing for
those using the Cosign library to pass intermediate CA certificates to
validate a certificate chain.

Signed-off-by: Hayden Blauzvern <[email protected]>
  • Loading branch information
haydentherapper committed Mar 17, 2022
1 parent d0aa73b commit 1d05695
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 4 deletions.
11 changes: 7 additions & 4 deletions pkg/cosign/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ type CheckOpts struct {

// RootCerts are the root CA certs used to verify a signature's chained certificate.
RootCerts *x509.CertPool
// IntermediateCerts are the optional intermediate CA certs used to verify a certificate chain.
IntermediateCerts *x509.CertPool
// CertEmail is the email expected for a certificate to be valid. The empty string means any certificate can be valid.
CertEmail string
// CertOidcIssuer is the OIDC issuer expected for a certificate to be valid. The empty string means any certificate can be valid.
Expand Down Expand Up @@ -149,7 +151,7 @@ func ValidateAndUnpackCert(cert *x509.Certificate, co *CheckOpts) (signature.Ver
}

// Now verify the cert, then the signature.
if err := TrustedCert(cert, co.RootCerts); err != nil {
if err := TrustedCert(cert, co.RootCerts, co.IntermediateCerts); err != nil {
return nil, err
}
if co.CertEmail != "" {
Expand Down Expand Up @@ -783,13 +785,14 @@ func VerifySET(bundlePayload cbundle.RekorPayload, signature []byte, pub *ecdsa.
return nil
}

func TrustedCert(cert *x509.Certificate, roots *x509.CertPool) error {
func TrustedCert(cert *x509.Certificate, roots *x509.CertPool, interemdiates *x509.CertPool) error {
if _, err := cert.Verify(x509.VerifyOptions{
// THIS IS IMPORTANT: WE DO NOT CHECK TIMES HERE
// THE CERTIFICATE IS TREATED AS TRUSTED FOREVER
// WE CHECK THAT THE SIGNATURES WERE CREATED DURING THIS WINDOW
CurrentTime: cert.NotBefore,
Roots: roots,
CurrentTime: cert.NotBefore,
Roots: roots,
Intermediates: interemdiates,
KeyUsages: []x509.ExtKeyUsage{
x509.ExtKeyUsageCodeSigning,
},
Expand Down
47 changes: 47 additions & 0 deletions pkg/cosign/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,50 @@ func TestCompareSigs(t *testing.T) {
})
}
}

func TestTrustedCertSuccess(t *testing.T) {
rootCert, rootKey, _ := test.GenerateRootCa()
subCert, subKey, _ := test.GenerateSubordinateCa(rootCert, rootKey)
leafCert, _, _ := test.GenerateLeafCert("subject", "oidc-issuer", subCert, subKey)

rootPool := x509.NewCertPool()
rootPool.AddCert(rootCert)
subPool := x509.NewCertPool()
subPool.AddCert(subCert)

err := TrustedCert(leafCert, rootPool, subPool)
if err != nil {
t.Fatalf("expected no error verifying certificate, got %v", err)
}
}

func TestTrustedCertSuccessNoIntermediates(t *testing.T) {
rootCert, rootKey, _ := test.GenerateRootCa()
leafCert, _, _ := test.GenerateLeafCert("subject", "oidc-issuer", rootCert, rootKey)

rootPool := x509.NewCertPool()
rootPool.AddCert(rootCert)

err := TrustedCert(leafCert, rootPool, nil)
if err != nil {
t.Fatalf("expected no error verifying certificate, got %v", err)
}
}

// Tests that verification succeeds if both a root and subordinate pool are
// present, but a chain is built with only the leaf and root certificates.
func TestTrustedCertSuccessChainFromRoot(t *testing.T) {
rootCert, rootKey, _ := test.GenerateRootCa()
leafCert, _, _ := test.GenerateLeafCert("subject", "oidc-issuer", rootCert, rootKey)
subCert, _, _ := test.GenerateSubordinateCa(rootCert, rootKey)

rootPool := x509.NewCertPool()
rootPool.AddCert(rootCert)
subPool := x509.NewCertPool()
subPool.AddCert(subCert)

err := TrustedCert(leafCert, rootPool, subPool)
if err != nil {
t.Fatalf("expected no error verifying certificate, got %v", err)
}
}

0 comments on commit 1d05695

Please sign in to comment.