Skip to content

Commit

Permalink
verify the SET when getting a log entry (#371)
Browse files Browse the repository at this point in the history
* verify the SET when getting a log entry

Signed-off-by: Asra Ali <asraa@google.com>

* fix verification

Signed-off-by: Asra Ali <asraa@google.com>

* retrieve the pubkey

Signed-off-by: Asra Ali <asraa@google.com>
  • Loading branch information
asraa authored Jun 17, 2021
1 parent 52cd652 commit 0d61e85
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 16 deletions.
5 changes: 1 addition & 4 deletions KEYLESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,12 @@ $ cosign sign --identity-token=$(gcloud auth print-identity-token --audiences=fu

### Timestamps

Signature timestamps are checked in the [rekor](https://github.com/sigstore/rekor) transparency log.
Signatures without timestamps are still validated, but show up with a warning because we cannot verify that the signature
was created while the certificate was valid.
Signature timestamps are checked in the [rekor](https://github.com/sigstore/rekor) transparency log. Rekor's `IntegratedTime` is signed as part of its `signedEntryTimestamp`. Cosign verifies the signature over the timestamp and checks that the signature was created while the certificate was valid.

## Upcoming work

* Root CA hardening: We should use intermediate certs rather than the root, and support chained verification.
* Root CA configuration: We should allow users to change the roots and add their own.
* Other timestamps: We should allow for other timestamp attestations, including attached [RFC3161](https://www.ietf.org/rfc/rfc3161.txt) signatures.
* Better timestamp validation in Rekor: We rely on the Rekor `IntegratedTime`, which is not as verifiable as a `STH` timestamp.
* Probably a lot more: This is very experimental.
* More OIDC providers: Obvious.
57 changes: 45 additions & 12 deletions pkg/cosign/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (
"github.com/sigstore/rekor/cmd/rekor-cli/app"
"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"
"github.com/sigstore/sigstore/pkg/signature"
"github.com/sigstore/sigstore/pkg/signature/payload"
Expand Down Expand Up @@ -135,6 +136,21 @@ func VerifyTLogEntry(rekorClient *client.Rekor, uuid string) (*models.LogEntryAn
if err := v.VerifyInclusionProof(*e.Verification.InclusionProof.LogIndex, *e.Verification.InclusionProof.TreeSize, hashes, rootHash, leafHash); err != nil {
return nil, errors.Wrap(err, "verifying inclusion proof")
}

// Verify rekor's signature over the SET.
resp, err := rekorClient.Pubkey.GetPublicKey(pubkey.NewGetPublicKeyParams())
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")
}

if err := VerifySET(&e, []byte(e.Verification.SignedEntryTimestamp), rekorPubKey); err != nil {
return nil, errors.Wrap(err, "verifying signedEntryTimestamp")
}

return &e, nil
}

Expand Down Expand Up @@ -244,12 +260,14 @@ func Verify(ctx context.Context, ref name.Reference, co *CheckOpts, rekorServerU
}

// if we have a cert, we should check expiry
// The IntegratedTime verified in VerifyTlog
if sp.Cert != nil {
e, err := getTlogEntry(rekorClient, uuid)
if err != nil {
validationErrs = append(validationErrs, err.Error())
continue
}

// Expiry check is only enabled with Tlog support
if err := checkExpiry(sp.Cert, time.Unix(*e.IntegratedTime, 0)); err != nil {
validationErrs = append(validationErrs, err.Error())
Expand Down Expand Up @@ -311,18 +329,9 @@ func (sp *SignedPayload) VerifyBundle() (bool, error) {
IntegratedTime: &sp.Bundle.IntegratedTime,
LogID: &sp.Bundle.LogID,
}
contents, err := le.MarshalBinary()
if err != nil {
return false, errors.Wrap(err, "marshaling")
}
canonicalized, err := jsoncanonicalizer.Transform(contents)
if err != nil {
return false, errors.Wrap(err, "canonicalizing")
}
// verify the SET against the public key
hash := sha256.Sum256(canonicalized)
if !ecdsa.VerifyASN1(rekorPubKey, hash[:], []byte(sp.Bundle.SignedEntryTimestamp)) {
return false, fmt.Errorf("unable to verify")

if err := VerifySET(le, []byte(sp.Bundle.SignedEntryTimestamp), rekorPubKey); err != nil {
return false, err
}

if sp.Cert == nil {
Expand All @@ -336,6 +345,30 @@ func (sp *SignedPayload) VerifyBundle() (bool, error) {
return true, nil
}

func VerifySET(entry *models.LogEntryAnon, signature []byte, pub *ecdsa.PublicKey) error {
// need to exclude entry.Verification
le := &models.LogEntryAnon{
IntegratedTime: entry.IntegratedTime,
LogIndex: entry.LogIndex,
Body: entry.Body,
LogID: entry.LogID,
}
contents, err := le.MarshalBinary()
if err != nil {
return errors.Wrap(err, "marshaling")
}
canonicalized, err := jsoncanonicalizer.Transform(contents)
if err != nil {
return errors.Wrap(err, "canonicalizing")
}
// verify the SET against the public key
hash := sha256.Sum256(canonicalized)
if !ecdsa.VerifyASN1(pub, hash[:], signature) {
return fmt.Errorf("unable to verify")
}
return nil
}

func (sp *SignedPayload) VerifyTlog(rc *client.Rekor, publicKeyPem []byte) (uuid string, index int64, err error) {
return FindTlogEntry(rc, sp.Base64Signature, sp.Payload, publicKeyPem)
}
Expand Down

0 comments on commit 0d61e85

Please sign in to comment.