Skip to content

Commit

Permalink
Print message when verifying with old TUF targets (#1468)
Browse files Browse the repository at this point in the history
* Verify tlog entries using the Rekor public keys from TUF

Typical verification used VerifyBundle, which called
GetRekorKeys, which fetches keys from the TUF repo.
If the bundle was not present or for a specific error
when a duplicate log entry was present, then the tlog
entry would be verified using a public key fetched from
Rekor's API. This key was not verified using TUF metadata.

This change simply removes the API call and uses Rekor
public keys from the TUF repo.

Tested locally by not including the Rekor bundle in
the OCI signature, which will hit the code path to
fetch the entry from the log.

Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>

* Print message when verifying with old TUF targets

This adds console messages when the TUF metadata
used for Rekor or the CTFE key is marked as expired.

I haven't added a log message for Fulcio yet. The way
that certificates are verified is different. Instead of
multiple verifications where we can easily determine
which key successfully verified an object, the x509
library uses a CertPool and returns a valid chain.
I'll need to plumb through the TUF information.

Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>
  • Loading branch information
haydentherapper committed Feb 16, 2022
1 parent a05d3b6 commit 18d2ce0
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 23 deletions.
11 changes: 7 additions & 4 deletions cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go
Expand Up @@ -52,7 +52,7 @@ const altCTLogPublicKeyLocation = "SIGSTORE_CT_LOG_PUBLIC_KEY_FILE"
// the certificate issued by Fulcio was also added to the public CT log within
// some defined time period
func verifySCT(ctx context.Context, certPEM, rawSCT []byte) error {
var pubKeys []crypto.PublicKey
pubKeys := make(map[crypto.PublicKey]tuf.StatusKind)
rootEnv := os.Getenv(altCTLogPublicKeyLocation)
if rootEnv == "" {
tufClient, err := tuf.NewFromEnv(ctx)
Expand All @@ -70,7 +70,7 @@ func verifySCT(ctx context.Context, certPEM, rawSCT []byte) error {
if err != nil {
return errors.Wrap(err, "converting Public CT to ECDSAKey")
}
pubKeys = append(pubKeys, ctPub)
pubKeys[ctPub] = t.Status
}
} else {
fmt.Fprintf(os.Stderr, "**Warning** Using a non-standard public key for verifying SCT: %s\n", rootEnv)
Expand All @@ -82,7 +82,7 @@ func verifySCT(ctx context.Context, certPEM, rawSCT []byte) error {
if err != nil {
return errors.Wrap(err, "error parsing alternate public key from the file")
}
pubKeys = append(pubKeys, pubKey)
pubKeys[pubKey] = tuf.Active
}
if len(pubKeys) == 0 {
return errors.New("none of the CTFE keys have been found")
Expand All @@ -96,10 +96,13 @@ func verifySCT(ctx context.Context, certPEM, rawSCT []byte) error {
return errors.Wrap(err, "unmarshal")
}
var verifySctErr error
for _, pubKey := range pubKeys {
for pubKey, status := range pubKeys {
verifySctErr = ctutil.VerifySCT(pubKey, []*ctx509.Certificate{cert}, &sct, false)
// Exit after successful verification of the SCT
if verifySctErr == nil {
if status != tuf.Active {
fmt.Fprintf(os.Stderr, "**Info** Successfully verified SCT using an expired verification key\n")
}
return nil
}
}
Expand Down
6 changes: 5 additions & 1 deletion cmd/cosign/cli/verify/verify_blob.go
Expand Up @@ -40,6 +40,7 @@ import (
"github.com/sigstore/cosign/pkg/cosign"
"github.com/sigstore/cosign/pkg/cosign/pivkey"
"github.com/sigstore/cosign/pkg/cosign/pkcs11key"
"github.com/sigstore/cosign/pkg/cosign/tuf"
sigs "github.com/sigstore/cosign/pkg/signature"

ctypes "github.com/sigstore/cosign/pkg/types"
Expand Down Expand Up @@ -297,9 +298,12 @@ func verifyRekorBundle(ctx context.Context, bundlePath string, cert *x509.Certif

var entryVerError error
for _, pubKey := range publicKeys {
entryVerError = cosign.VerifySET(b.Bundle.Payload, b.Bundle.SignedEntryTimestamp, pubKey)
entryVerError = cosign.VerifySET(b.Bundle.Payload, b.Bundle.SignedEntryTimestamp, pubKey.PubKey)
// Exit early with successful verification
if entryVerError == nil {
if pubKey.Status != tuf.Active {
fmt.Fprintf(os.Stderr, "**Info** Successfully verified Rekor entry using an expired verification key\n")
}
break
}
}
Expand Down
44 changes: 27 additions & 17 deletions pkg/cosign/tlog.go
Expand Up @@ -21,6 +21,7 @@ import (
"encoding/base64"
"encoding/hex"
"fmt"
"os"
"strings"

"github.com/go-openapi/strfmt"
Expand All @@ -34,7 +35,6 @@ import (

"github.com/sigstore/rekor/pkg/generated/client"
"github.com/sigstore/rekor/pkg/generated/client/entries"
"github.com/sigstore/rekor/pkg/generated/client/pubkey"
"github.com/sigstore/rekor/pkg/generated/models"
hashedrekord_v001 "github.com/sigstore/rekor/pkg/types/hashedrekord/v0.0.1"
intoto_v001 "github.com/sigstore/rekor/pkg/types/intoto/v0.0.1"
Expand All @@ -43,9 +43,16 @@ import (
// This is the rekor public key target name
var rekorTargetStr = `rekor.pub`

// RekorPubKey contains the ECDSA verification key and the current status
// of the key according to TUF metadata, whether it's active or expired.
type RekorPubKey struct {
PubKey *ecdsa.PublicKey
Status tuf.StatusKind
}

// GetRekorPubs retrieves trusted Rekor public keys from the embedded or cached
// TUF root. If expired, makes a network call to retrieve the updated targets.
func GetRekorPubs(ctx context.Context) ([]*ecdsa.PublicKey, error) {
func GetRekorPubs(ctx context.Context) ([]RekorPubKey, error) {
tufClient, err := tuf.NewFromEnv(ctx)
if err != nil {
return nil, err
Expand All @@ -55,13 +62,13 @@ func GetRekorPubs(ctx context.Context) ([]*ecdsa.PublicKey, error) {
if err != nil {
return nil, err
}
publicKeys := make([]*ecdsa.PublicKey, 0, len(targets))
publicKeys := make([]RekorPubKey, 0, len(targets))
for _, t := range targets {
rekorPubKey, err := PemToECDSAKey(t.Target)
if err != nil {
return nil, errors.Wrap(err, "pem to ecdsa")
}
publicKeys = append(publicKeys, rekorPubKey)
publicKeys = append(publicKeys, RekorPubKey{PubKey: rekorPubKey, Status: t.Status})
}
if len(publicKeys) == 0 {
return nil, errors.New("none of the Rekor public keys have been found")
Expand Down Expand Up @@ -269,24 +276,27 @@ func verifyTLogEntry(ctx context.Context, rekorClient *client.Rekor, uuid string
}

// Verify rekor's signature over the SET.
resp, err := rekorClient.Pubkey.GetPublicKey(pubkey.NewGetPublicKeyParamsWithContext(ctx))
if err != nil {
return nil, errors.Wrap(err, "rekor public key")
}
rekorPubKey, err := PemToECDSAKey([]byte(resp.Payload))
if err != nil {
return nil, errors.Wrap(err, "rekor public key pem to ecdsa")
}

payload := bundle.RekorPayload{
Body: e.Body,
IntegratedTime: *e.IntegratedTime,
LogIndex: *e.LogIndex,
LogID: *e.LogID,
}
if err := VerifySET(payload, []byte(e.Verification.SignedEntryTimestamp), rekorPubKey); err != nil {
return nil, errors.Wrap(err, "verifying signedEntryTimestamp")
}

return &e, nil
rekorPubKeys, err := GetRekorPubs(ctx)
if err != nil {
return nil, errors.Wrap(err, "unable to fetch Rekor public keys from TUF repository")
}
var entryVerError error
for _, pubKey := range rekorPubKeys {
entryVerError = VerifySET(payload, []byte(e.Verification.SignedEntryTimestamp), pubKey.PubKey)
// Return once the SET is verified successfully.
if entryVerError == nil {
if pubKey.Status != tuf.Active {
fmt.Fprintf(os.Stderr, "**Info** Successfully verified Rekor entry using an expired verification key\n")
}
return &e, nil
}
}
return nil, errors.Wrap(entryVerError, "verifying signedEntryTimestamp")
}
6 changes: 5 additions & 1 deletion pkg/cosign/verify.go
Expand Up @@ -31,6 +31,7 @@ import (
"time"

cbundle "github.com/sigstore/cosign/pkg/cosign/bundle"
"github.com/sigstore/cosign/pkg/cosign/tuf"

"github.com/sigstore/cosign/pkg/blob"
"github.com/sigstore/cosign/pkg/oci/static"
Expand Down Expand Up @@ -592,9 +593,12 @@ func VerifyBundle(ctx context.Context, sig oci.Signature) (bool, error) {

var entryVerError error
for _, pubKey := range publicKeys {
entryVerError = VerifySET(bundle.Payload, bundle.SignedEntryTimestamp, pubKey)
entryVerError = VerifySET(bundle.Payload, bundle.SignedEntryTimestamp, pubKey.PubKey)
// Exit early with successful verification
if entryVerError == nil {
if pubKey.Status != tuf.Active {
fmt.Fprintf(os.Stderr, "**Info** Successfully verified Rekor entry using an expired verification key\n")
}
break
}
}
Expand Down

0 comments on commit 18d2ce0

Please sign in to comment.