Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include URI for CA verified timestamps #270

Merged
merged 1 commit into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion pkg/root/trusted_root.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,9 @@ func ParseCertificateAuthority(certAuthority *prototrustroot.CertificateAuthorit
}
}

// TODO: Should we inspect/enforce ca.Subject and ca.Uri?
certificateAuthority.URI = certAuthority.Uri

// TODO: Should we inspect/enforce ca.Subject?
// TODO: Handle validity period (ca.ValidFor)

return certificateAuthority, nil
Expand Down
6 changes: 3 additions & 3 deletions pkg/verify/signed_entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ func (v *SignedEntityVerifier) VerifyTransparencyLogInclusion(entity SignedEntit
}

for _, vts := range verifiedTlogTimestamps {
verifiedTimestamps = append(verifiedTimestamps, TimestampVerificationResult{Type: "Tlog", URI: "TODO", Timestamp: vts})
verifiedTimestamps = append(verifiedTimestamps, TimestampVerificationResult{Type: "Tlog", URI: vts.URI, Timestamp: vts.Time})
}
}

Expand All @@ -692,7 +692,7 @@ func (v *SignedEntityVerifier) VerifyObserverTimestamps(entity SignedEntity, log
return nil, err
}
for _, vts := range verifiedSignedTimestamps {
verifiedTimestamps = append(verifiedTimestamps, TimestampVerificationResult{Type: "TimestampAuthority", URI: "TODO", Timestamp: vts})
verifiedTimestamps = append(verifiedTimestamps, TimestampVerificationResult{Type: "TimestampAuthority", URI: vts.URI, Timestamp: vts.Time})
}
}

Expand All @@ -719,7 +719,7 @@ func (v *SignedEntityVerifier) VerifyObserverTimestamps(entity SignedEntity, log
// append all timestamps
verifiedTimestamps = append(verifiedTimestamps, logTimestamps...)
for _, vts := range verifiedSignedTimestamps {
verifiedTimestamps = append(verifiedTimestamps, TimestampVerificationResult{Type: "TimestampAuthority", URI: "TODO", Timestamp: vts})
verifiedTimestamps = append(verifiedTimestamps, TimestampVerificationResult{Type: "TimestampAuthority", URI: vts.URI, Timestamp: vts.Time})
}
}

Expand Down
1 change: 1 addition & 0 deletions pkg/verify/signed_entity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ func TestEntitySignedByPublicGoodWithTlogVerifiesSuccessfully(t *testing.T) {
assert.NotNil(t, res.Signature.Certificate)
assert.Equal(t, "https://github.com/sigstore/sigstore-js/.github/workflows/release.yml@refs/heads/main", res.Signature.Certificate.SubjectAlternativeName)
assert.NotEmpty(t, res.VerifiedTimestamps)
assert.Equal(t, "https://rekor.sigstore.dev", res.VerifiedTimestamps[0].URI)

// verifies with integrated timestamp threshold too
v, err = verify.NewSignedEntityVerifier(tr, verify.WithTransparencyLog(1), verify.WithIntegratedTimestamps(1))
Expand Down
35 changes: 13 additions & 22 deletions pkg/verify/tlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"encoding/hex"
"errors"
"fmt"
"time"

rekorClient "github.com/sigstore/rekor/pkg/client"
rekorGeneratedClient "github.com/sigstore/rekor/pkg/generated/client"
Expand All @@ -43,7 +42,7 @@ const maxAllowedTlogEntries = 32
// that must be verified.
//
// If online is true, the log entry is verified against the Rekor server.
func VerifyArtifactTransparencyLog(entity SignedEntity, trustedMaterial root.TrustedMaterial, logThreshold int, trustIntegratedTime, online bool) ([]time.Time, error) { //nolint:revive
func VerifyArtifactTransparencyLog(entity SignedEntity, trustedMaterial root.TrustedMaterial, logThreshold int, trustIntegratedTime, online bool) ([]Timestamp, error) { //nolint:revive
entries, err := entity.TlogEntries()
if err != nil {
return nil, err
Expand Down Expand Up @@ -75,7 +74,7 @@ func VerifyArtifactTransparencyLog(entity SignedEntity, trustedMaterial root.Tru
return nil, err
}

verifiedTimestamps := []time.Time{}
verifiedTimestamps := []Timestamp{}
logEntriesVerified := 0

for _, entry := range entries {
Expand All @@ -84,29 +83,29 @@ func VerifyArtifactTransparencyLog(entity SignedEntity, trustedMaterial root.Tru
return nil, err
}

rekorLogs := trustedMaterial.RekorLogs()
keyID := entry.LogKeyID()
hex64Key := hex.EncodeToString([]byte(keyID))
tlogVerifier, ok := trustedMaterial.RekorLogs()[hex64Key]
if !ok {
// skip entries the trust root cannot verify
continue
}
if !online {
if !entry.HasInclusionPromise() && !entry.HasInclusionProof() {
return nil, fmt.Errorf("entry must contain an inclusion proof and/or promise")
}
if entry.HasInclusionPromise() {
err = tlog.VerifySET(entry, trustedMaterial.RekorLogs())
err = tlog.VerifySET(entry, rekorLogs)
if err != nil {
// skip entries the trust root cannot verify
continue
}
if trustIntegratedTime {
verifiedTimestamps = append(verifiedTimestamps, entry.IntegratedTime())
verifiedTimestamps = append(verifiedTimestamps, Timestamp{Time: entry.IntegratedTime(), URI: tlogVerifier.BaseURL})
}
}
if entity.HasInclusionProof() {
keyID := entry.LogKeyID()
hex64Key := hex.EncodeToString([]byte(keyID))
tlogVerifier, ok := trustedMaterial.RekorLogs()[hex64Key]
if !ok {
// skip entries the trust root cannot verify
continue
}

verifier, err := getVerifier(tlogVerifier.PublicKey, tlogVerifier.SignatureHashFunc)
if err != nil {
return nil, err
Expand All @@ -119,14 +118,6 @@ func VerifyArtifactTransparencyLog(entity SignedEntity, trustedMaterial root.Tru
// DO NOT use timestamp with only an inclusion proof, because it is not signed metadata
}
} else {
keyID := entry.LogKeyID()
hex64Key := hex.EncodeToString([]byte(keyID))
tlogVerifier, ok := trustedMaterial.RekorLogs()[hex64Key]
if !ok {
// skip entries the trust root cannot verify
continue
}

client, err := getRekorClient(tlogVerifier.BaseURL)
if err != nil {
return nil, err
Expand Down Expand Up @@ -160,7 +151,7 @@ func VerifyArtifactTransparencyLog(entity SignedEntity, trustedMaterial root.Tru
}
}
if trustIntegratedTime {
verifiedTimestamps = append(verifiedTimestamps, entry.IntegratedTime())
verifiedTimestamps = append(verifiedTimestamps, Timestamp{Time: entry.IntegratedTime(), URI: tlogVerifier.BaseURL})
}
}
// Ensure entry signature matches signature from bundle
Expand Down
2 changes: 1 addition & 1 deletion pkg/verify/tlog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func TestTlogVerifier(t *testing.T) {
entity, err := virtualSigstore.Attest("foo@example.com", "issuer", statement)
assert.NoError(t, err)

var ts []time.Time
var ts []verify.Timestamp
ts, err = verify.VerifyArtifactTransparencyLog(entity, virtualSigstore, 1, true, false)
assert.NoError(t, err)
// 1 verified timestamp
Expand Down
17 changes: 11 additions & 6 deletions pkg/verify/tsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,14 @@ import (

const maxAllowedTimestamps = 32

type Timestamp struct {
Time time.Time
URI string
}

// VerifyTimestampAuthority verifies that the given entity has been timestamped
// by a trusted timestamp authority and that the timestamp is valid.
func VerifyTimestampAuthority(entity SignedEntity, trustedMaterial root.TrustedMaterial) ([]time.Time, error) { //nolint:revive
func VerifyTimestampAuthority(entity SignedEntity, trustedMaterial root.TrustedMaterial) ([]Timestamp, error) { //nolint:revive
signedTimestamps, err := entity.Timestamps()
if err != nil {
return nil, err
Expand Down Expand Up @@ -62,7 +67,7 @@ func VerifyTimestampAuthority(entity SignedEntity, trustedMaterial root.TrustedM
return nil, err
}

verifiedTimestamps := []time.Time{}
verifiedTimestamps := []Timestamp{}
for _, timestamp := range signedTimestamps {
verifiedSignedTimestamp, err := verifySignedTimestamp(timestamp, signatureBytes, trustedMaterial, verificationContent)

Expand All @@ -82,7 +87,7 @@ func VerifyTimestampAuthority(entity SignedEntity, trustedMaterial root.TrustedM
//
// The threshold parameter is the number of unique timestamps that must be
// verified.
func VerifyTimestampAuthorityWithThreshold(entity SignedEntity, trustedMaterial root.TrustedMaterial, threshold int) ([]time.Time, error) { //nolint:revive
func VerifyTimestampAuthorityWithThreshold(entity SignedEntity, trustedMaterial root.TrustedMaterial, threshold int) ([]Timestamp, error) { //nolint:revive
verifiedTimestamps, err := VerifyTimestampAuthority(entity, trustedMaterial)
if err != nil {
return nil, err
Expand All @@ -93,7 +98,7 @@ func VerifyTimestampAuthorityWithThreshold(entity SignedEntity, trustedMaterial
return verifiedTimestamps, nil
}

func verifySignedTimestamp(signedTimestamp []byte, dsseSignatureBytes []byte, trustedMaterial root.TrustedMaterial, verificationContent VerificationContent) (time.Time, error) {
func verifySignedTimestamp(signedTimestamp []byte, dsseSignatureBytes []byte, trustedMaterial root.TrustedMaterial, verificationContent VerificationContent) (Timestamp, error) {
certAuthorities := trustedMaterial.TimestampingAuthorities()

// Iterate through TSA certificate authorities to find one that verifies
Expand Down Expand Up @@ -124,8 +129,8 @@ func verifySignedTimestamp(signedTimestamp []byte, dsseSignatureBytes []byte, tr
}

// All above verification successful, so return nil
return timestamp.Time, nil
return Timestamp{Time: timestamp.Time, URI: ca.URI}, nil
}

return time.Time{}, errors.New("unable to verify signed timestamps")
return Timestamp{}, errors.New("unable to verify signed timestamps")
}
2 changes: 1 addition & 1 deletion pkg/verify/tsa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func TestTimestampAuthorityVerifierWithoutThreshold(t *testing.T) {
virtualSigstore2, err := ca.NewVirtualSigstore()
assert.NoError(t, err)

var ts []time.Time
var ts []verify.Timestamp

// expect one verified timestamp
ts, err = verify.VerifyTimestampAuthority(entity, virtualSigstore)
Expand Down
Loading