Skip to content

Commit

Permalink
fix: fix cert chain validation for verify-blob in non-experimental mo…
Browse files Browse the repository at this point in the history
…de (#2256)

* fix!: fix cert chain validation for verify-blob in non-experimental mode (#2256)

Signed-off-by: Asra Ali <[email protected]>
  • Loading branch information
asraa authored Sep 16, 2022
1 parent f43839b commit 63fe875
Show file tree
Hide file tree
Showing 2 changed files with 190 additions and 6 deletions.
34 changes: 30 additions & 4 deletions cmd/cosign/cli/verify/verify_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func VerifyBlobCmd(ctx context.Context, ko options.KeyOpts, certRef, certEmail,
co.RekorClient = rekorClient
}
}
if certRef == "" || options.EnableExperimental() {
if options.EnableExperimental() {
co.RootCerts, err = fulcio.GetRoots()
if err != nil {
return fmt.Errorf("getting Fulcio roots: %w", err)
Expand Down Expand Up @@ -145,9 +145,18 @@ func VerifyBlobCmd(ctx context.Context, ko options.KeyOpts, certRef, certEmail,
return err
}
if certChain == "" {
co.RootCerts, err = fulcio.GetRoots()
if err != nil {
return fmt.Errorf("getting Fulcio roots: %w", err)
}

co.IntermediateCerts, err = fulcio.GetIntermediates()
if err != nil {
return fmt.Errorf("getting Fulcio intermediates: %w", err)
}
co.SigVerifier, err = cosign.ValidateAndUnpackCert(cert, co)
if err != nil {
return err
return fmt.Errorf("validating certRef: %w", err)
}
} else {
// Verify certificate with chain
Expand Down Expand Up @@ -178,10 +187,27 @@ func VerifyBlobCmd(ctx context.Context, ko options.KeyOpts, certRef, certEmail,
// check if cert is actually a public key
co.SigVerifier, err = sigs.LoadPublicKeyRaw(certBytes, crypto.SHA256)
} else {
co.SigVerifier, err = cosign.ValidateAndUnpackCert(cert, co)
if certChain == "" {
co.RootCerts, err = fulcio.GetRoots()
if err != nil {
return fmt.Errorf("getting Fulcio roots: %w", err)
}
co.IntermediateCerts, err = fulcio.GetIntermediates()
if err != nil {
return fmt.Errorf("getting Fulcio intermediates: %w", err)
}
co.SigVerifier, err = cosign.ValidateAndUnpackCert(cert, co)
} else {
// Verify certificate with chain
chain, err := loadCertChainFromFileOrURL(certChain)
if err != nil {
return err
}
co.SigVerifier, err = cosign.ValidateAndUnpackCertWithChain(cert, chain, co)
}
}
if err != nil {
return err
return fmt.Errorf("loading verifier from bundle: %w", err)
}
bundle = b.Bundle
// No certificate is provided: search by artifact sha in the TLOG.
Expand Down
162 changes: 160 additions & 2 deletions cmd/cosign/cli/verify/verify_blob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,6 @@ func TestVerifyBlob(t *testing.T) {
experimental: false,
shouldErr: true,
},

{
name: "valid signature with expired certificate - experimental good rekor lookup",
blob: blobBytes,
Expand All @@ -446,7 +445,6 @@ func TestVerifyBlob(t *testing.T) {
expiredLeafPem, true),
shouldErr: false,
},

{
name: "valid signature with expired certificate - experimental bad rekor integrated time",
blob: blobBytes,
Expand Down Expand Up @@ -957,6 +955,166 @@ func TestVerifyBlobCmdWithBundle(t *testing.T) {
t.Fatalf("expected error with mismatched issuer, got %v", err)
}
})
t.Run("Implicit Fulcio chain with bundle in non-experimental mode", func(t *testing.T) {
identity := "[email protected]"
issuer := "issuer"
leafCert, _, leafPemCert, signer := keyless.genLeafCert(t, identity, issuer)

// Create blob
blob := "someblob"

// Sign blob with private key
sig, err := signer.SignMessage(bytes.NewReader([]byte(blob)))
if err != nil {
t.Fatal(err)
}

// Create bundle
entry := genRekorEntry(t, hashedrekord.KIND, hashedrekord.New().DefaultVersion(), []byte(blob), leafPemCert, sig)
b := createBundle(t, sig, leafPemCert, keyless.rekorLogID, leafCert.NotBefore.Unix()+1, entry)
b.Bundle.SignedEntryTimestamp = keyless.rekorSignPayload(t, b.Bundle.Payload)
bundlePath := writeBundleFile(t, keyless.td, b, "bundle.json")
blobPath := writeBlobFile(t, keyless.td, blob, "blob.txt")
certPath := writeBlobFile(t, keyless.td, string(leafPemCert), "cert.pem")

// Verify command
err = VerifyBlobCmd(context.Background(),
options.KeyOpts{BundlePath: bundlePath},
certPath, /*certRef*/
identity, /*certEmail*/
issuer, /*certOidcIssuer*/
"", /*certChain*/ // Chain is fetched from TUF/SIGSTORE_ROOT_FILE
"", /*sigRef*/ // Sig is fetched from bundle
blobPath, /*blobRef*/
// GitHub identity flags start
"", "", "", "", "",
// GitHub identity flags end
false /*enforceSCT*/)
if err != nil {
t.Fatalf("expected success without specifying the intermediates, got %v", err)
}
})
t.Run("Explicit Fulcio chain with bundle in non-experimental mode", func(t *testing.T) {
identity := "[email protected]"
issuer := "issuer"
leafCert, _, leafPemCert, signer := keyless.genLeafCert(t, identity, issuer)

// Create blob
blob := "someblob"

// Sign blob with private key
sig, err := signer.SignMessage(bytes.NewReader([]byte(blob)))
if err != nil {
t.Fatal(err)
}

// Create bundle
entry := genRekorEntry(t, hashedrekord.KIND, hashedrekord.New().DefaultVersion(), []byte(blob), leafPemCert, sig)
b := createBundle(t, sig, leafPemCert, keyless.rekorLogID, leafCert.NotBefore.Unix()+1, entry)
b.Bundle.SignedEntryTimestamp = keyless.rekorSignPayload(t, b.Bundle.Payload)
bundlePath := writeBundleFile(t, keyless.td, b, "bundle.json")
blobPath := writeBlobFile(t, keyless.td, blob, "blob.txt")

// Verify command
err = VerifyBlobCmd(context.Background(),
options.KeyOpts{BundlePath: bundlePath},
"", /*certRef*/
identity, /*certEmail*/
issuer, /*certOidcIssuer*/
os.Getenv("SIGSTORE_ROOT_FILE"), /*certChain*/
"", /*sigRef*/ // Sig is fetched from bundle
blobPath, /*blobRef*/
// GitHub identity flags start
"", "", "", "", "",
// GitHub identity flags end
false /*enforceSCT*/)
if err != nil {
t.Fatalf("expected success specifying the intermediates, got %v", err)
}
})
}

func TestVerifyBlobCmdInvalidRootCA(t *testing.T) {
keyless := newKeylessStack(t)
// Change the keyless stack.
_ = newKeylessStack(t)
t.Run("Invalid certificate root when specifying cert via certRef", func(t *testing.T) {
identity := "[email protected]"
issuer := "issuer"
leafCert, _, leafPemCert, signer := keyless.genLeafCert(t, identity, issuer)

// Create blob
blob := "someblob"

// Sign blob with private key
sig, err := signer.SignMessage(bytes.NewReader([]byte(blob)))
if err != nil {
t.Fatal(err)
}

// Create bundle
entry := genRekorEntry(t, hashedrekord.KIND, hashedrekord.New().DefaultVersion(), []byte(blob), leafPemCert, sig)
b := createBundle(t, sig, leafPemCert, keyless.rekorLogID, leafCert.NotBefore.Unix()+1, entry)
b.Bundle.SignedEntryTimestamp = keyless.rekorSignPayload(t, b.Bundle.Payload)
bundlePath := writeBundleFile(t, keyless.td, b, "bundle.json")
blobPath := writeBlobFile(t, keyless.td, blob, "blob.txt")
certPath := writeBlobFile(t, keyless.td, string(leafPemCert), "cert.pem")

// Verify command
err = VerifyBlobCmd(context.Background(),
options.KeyOpts{BundlePath: bundlePath},
certPath, /*certRef*/
identity, /*certEmail*/
issuer, /*certOidcIssuer*/
"", /*certChain*/ // Chain is fetched from TUF/SIGSTORE_ROOT_FILE
"", /*sigRef*/ // Sig is fetched from bundle
blobPath, /*blobRef*/
// GitHub identity flags start
"", "", "", "", "",
// GitHub identity flags end
false /*enforceSCT*/)
if err == nil || !strings.Contains(err.Error(), "certificate signed by unknown authority") {
t.Fatalf("expected error with invalid root CA, got %v", err)
}
})
t.Run("Invalid certificate root when specifying cert in bundle", func(t *testing.T) {
identity := "[email protected]"
issuer := "issuer"
leafCert, _, leafPemCert, signer := keyless.genLeafCert(t, identity, issuer)

// Create blob
blob := "someblob"

// Sign blob with private key
sig, err := signer.SignMessage(bytes.NewReader([]byte(blob)))
if err != nil {
t.Fatal(err)
}

// Create bundle
entry := genRekorEntry(t, hashedrekord.KIND, hashedrekord.New().DefaultVersion(), []byte(blob), leafPemCert, sig)
b := createBundle(t, sig, leafPemCert, keyless.rekorLogID, leafCert.NotBefore.Unix()+1, entry)
b.Bundle.SignedEntryTimestamp = keyless.rekorSignPayload(t, b.Bundle.Payload)
bundlePath := writeBundleFile(t, keyless.td, b, "bundle.json")
blobPath := writeBlobFile(t, keyless.td, blob, "blob.txt")

// Verify command
err = VerifyBlobCmd(context.Background(),
options.KeyOpts{BundlePath: bundlePath},
"", /*certRef*/ // Fetched from bundle
identity, /*certEmail*/
issuer, /*certOidcIssuer*/
"", /*certChain*/ // Chain is fetched from TUF/SIGSTORE_ROOT_FILE
"", /*sigRef*/ // Sig is fetched from bundle
blobPath, /*blobRef*/
// GitHub identity flags start
"", "", "", "", "",
// GitHub identity flags end
false /*enforceSCT*/)
if err == nil || !strings.Contains(err.Error(), "certificate signed by unknown authority") {
t.Fatalf("expected error with invalid root CA, got %v", err)
}
})
}

type keylessStack struct {
Expand Down

0 comments on commit 63fe875

Please sign in to comment.