Skip to content

Commit

Permalink
Remove online Rekor lookups for verification (#344)
Browse files Browse the repository at this point in the history
For #80

Eventually we're going to remove the lookup ability from Rekor,
and there's no security difference between online and offline.

Signed-off-by: Zach Steindler <[email protected]>
  • Loading branch information
steiza authored Dec 9, 2024
1 parent 8c69fe2 commit f4f0b6e
Show file tree
Hide file tree
Showing 7 changed files with 30 additions and 271 deletions.
3 changes: 0 additions & 3 deletions cmd/conformance/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,9 +300,6 @@ func main() {

verifierConfig := []verify.VerifierOption{}
verifierConfig = append(verifierConfig, verify.WithoutAnyObserverTimestampsUnsafe(), verify.WithSignedCertificateTimestamps(1))
if len(tr.RekorLogs()) > 0 {
verifierConfig = append(verifierConfig, verify.WithOnlineVerification())
}

// Verify bundle
sev, err := verify.NewSignedEntityVerifier(tr, verifierConfig...)
Expand Down
6 changes: 0 additions & 6 deletions cmd/sigstore-go/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ var requireTimestamp *bool
var requireCTlog *bool
var requireTlog *bool
var minBundleVersion *string
var onlineTlog *bool
var trustedPublicKey *string
var trustedrootJSONpath *string
var tufRootURL *string
Expand All @@ -66,7 +65,6 @@ func init() {
requireCTlog = flag.Bool("requireCTlog", true, "Require Certificate Transparency log entry")
requireTlog = flag.Bool("requireTlog", true, "Require Artifact Transparency log entry (Rekor)")
minBundleVersion = flag.String("minBundleVersion", "", "Minimum acceptable bundle version (e.g. '0.1')")
onlineTlog = flag.Bool("onlineTlog", false, "Verify Artifact Transparency log entry online (Rekor)")
trustedPublicKey = flag.String("publicKey", "", "Path to trusted public key")
trustedrootJSONpath = flag.String("trustedrootJSONpath", "examples/trusted-root-public-good.json", "Path to trustedroot JSON file")
tufRootURL = flag.String("tufRootURL", "", "URL of TUF root containing trusted root JSON file")
Expand Down Expand Up @@ -118,10 +116,6 @@ func run() error {
verifierConfig = append(verifierConfig, verify.WithTransparencyLog(1))
}

if *onlineTlog {
verifierConfig = append(verifierConfig, verify.WithOnlineVerification())
}

certID, err := verify.NewShortCertificateIdentity(*expectedOIDIssuer, *expectedOIDIssuerRegex, *expectedSAN, *expectedSANRegex)
if err != nil {
return err
Expand Down
6 changes: 0 additions & 6 deletions examples/oci-image-verification/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ var ignoreSCT *bool
var requireTimestamp *bool
var requireTlog *bool
var minBundleVersion *string
var onlineTlog *bool
var trustedPublicKey *string
var trustedrootJSONpath *string
var tufRootURL *string
Expand All @@ -74,7 +73,6 @@ func init() {
requireTimestamp = flag.Bool("requireTimestamp", true, "Require either an RFC3161 signed timestamp or log entry integrated timestamp")
requireTlog = flag.Bool("requireTlog", true, "Require Artifact Transparency log entry (Rekor)")
minBundleVersion = flag.String("minBundleVersion", "", "Minimum acceptable bundle version (e.g. '0.1')")
onlineTlog = flag.Bool("onlineTlog", false, "Verify Artifact Transparency log entry online (Rekor)")
trustedPublicKey = flag.String("publicKey", "", "Path to trusted public key")
trustedrootJSONpath = flag.String("trustedrootJSONpath", "examples/trusted-root-public-good.json", "Path to trustedroot JSON file")
tufRootURL = flag.String("tufRootURL", "", "URL of TUF root containing trusted root JSON file")
Expand Down Expand Up @@ -135,10 +133,6 @@ func run() error {
verifierConfig = append(verifierConfig, verify.WithTransparencyLog(1))
}

if *onlineTlog {
verifierConfig = append(verifierConfig, verify.WithOnlineVerification())
}

if *expectedOIDIssuer != "" || *expectedOIDIssuerRegex != "" || *expectedSAN != "" || *expectedSANRegex != "" {
certID, err := verify.NewShortCertificateIdentity(*expectedOIDIssuer, *expectedOIDIssuerRegex, *expectedSAN, *expectedSANRegex)
if err != nil {
Expand Down
3 changes: 1 addition & 2 deletions pkg/verify/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@ func FuzzVerifyArtifactTransparencyLog(f *testing.F) {
verify.VerifyArtifactTransparencyLog(entity,
virtualSigstore,
logThreshold,
trustIntegratedTime,
false)
trustIntegratedTime)
})
}

Expand Down
15 changes: 1 addition & 14 deletions pkg/verify/signed_entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ type SignedEntityVerifier struct {
}

type VerifierConfig struct { // nolint: revive
// performOnlineVerification queries logs during verification.
// Default is offline
performOnlineVerification bool
// weExpectSignedTimestamps requires RFC3161 timestamps to verify
// short-lived certificates
weExpectSignedTimestamps bool
Expand Down Expand Up @@ -109,16 +106,6 @@ func NewSignedEntityVerifier(trustedMaterial root.TrustedMaterial, options ...Ve
return v, nil
}

// WithOnlineVerification configures the SignedEntityVerifier to perform
// online verification when verifying Transparency Log entries and
// Signed Certificate Timestamps.
func WithOnlineVerification() VerifierOption {
return func(c *VerifierConfig) error {
c.performOnlineVerification = true
return nil
}
}

// WithSignedTimestamps configures the SignedEntityVerifier to expect RFC 3161
// timestamps from a Timestamp Authority, verify them using the TrustedMaterial's
// TimestampingAuthorities(), and, if it exists, use the resulting timestamp(s)
Expand Down Expand Up @@ -663,7 +650,7 @@ func (v *SignedEntityVerifier) VerifyTransparencyLogInclusion(entity SignedEntit
if v.config.weExpectTlogEntries {
// log timestamps should be verified if with WithIntegratedTimestamps or WithObserverTimestamps is used
verifiedTlogTimestamps, err := VerifyArtifactTransparencyLog(entity, v.trustedMaterial, v.config.tlogEntriesThreshold,
v.config.requireIntegratedTimestamps || v.config.requireObserverTimestamps, v.config.performOnlineVerification)
v.config.requireIntegratedTimestamps || v.config.requireObserverTimestamps)
if err != nil {
return nil, err
}
Expand Down
88 changes: 17 additions & 71 deletions pkg/verify/tlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,25 @@ package verify

import (
"bytes"
"context"
"crypto"
"encoding/hex"
"errors"
"fmt"

rekorClient "github.com/sigstore/rekor/pkg/client"
rekorGeneratedClient "github.com/sigstore/rekor/pkg/generated/client"
rekorEntries "github.com/sigstore/rekor/pkg/generated/client/entries"
rekorVerify "github.com/sigstore/rekor/pkg/verify"
"github.com/sigstore/sigstore/pkg/signature"

"github.com/sigstore/sigstore-go/pkg/root"
"github.com/sigstore/sigstore-go/pkg/tlog"
"github.com/sigstore/sigstore-go/pkg/util"
)

const maxAllowedTlogEntries = 32

var RekorClientGetter = getRekorClient

// VerifyArtifactTransparencyLog verifies that the given entity has been logged
// in the transparency log and that the log entry is valid.
//
// The threshold parameter is the number of unique transparency log entries
// 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) ([]root.Timestamp, error) { //nolint:revive
func VerifyArtifactTransparencyLog(entity SignedEntity, trustedMaterial root.TrustedMaterial, logThreshold int, trustIntegratedTime bool) ([]root.Timestamp, error) { //nolint:revive
entries, err := entity.TlogEntries()
if err != nil {
return nil, err
Expand Down Expand Up @@ -93,68 +83,33 @@ func VerifyArtifactTransparencyLog(entity SignedEntity, trustedMaterial root.Tru
// 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, rekorLogs)
if err != nil {
// skip entries the trust root cannot verify
continue
}
if trustIntegratedTime {
verifiedTimestamps = append(verifiedTimestamps, root.Timestamp{Time: entry.IntegratedTime(), URI: tlogVerifier.BaseURL})
}
}
if entry.HasInclusionProof() {
verifier, err := getVerifier(tlogVerifier.PublicKey, tlogVerifier.SignatureHashFunc)
if err != nil {
return nil, err
}

err = tlog.VerifyInclusion(entry, *verifier)
if err != nil {
return nil, err
}
// DO NOT use timestamp with only an inclusion proof, because it is not signed metadata
}
} else {
client, err := RekorClientGetter(tlogVerifier.BaseURL)

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, rekorLogs)
if err != nil {
return nil, err
// skip entries the trust root cannot verify
continue
}

if trustIntegratedTime {
verifiedTimestamps = append(verifiedTimestamps, root.Timestamp{Time: entry.IntegratedTime(), URI: tlogVerifier.BaseURL})
}
}
if entry.HasInclusionProof() {
verifier, err := getVerifier(tlogVerifier.PublicKey, tlogVerifier.SignatureHashFunc)
if err != nil {
return nil, err
}

logIndex := entry.LogIndex()

searchParams := rekorEntries.NewGetLogEntryByIndexParams()
searchParams.LogIndex = logIndex

resp, err := client.Entries.GetLogEntryByIndex(searchParams)
err = tlog.VerifyInclusion(entry, *verifier)
if err != nil {
return nil, err
}

if len(resp.Payload) == 0 {
return nil, fmt.Errorf("unable to locate log entry %d", logIndex)
}

for _, v := range resp.Payload {
v := v
err = rekorVerify.VerifyLogEntry(context.TODO(), &v, *verifier)
if err != nil {
return nil, err
}
}
if trustIntegratedTime {
verifiedTimestamps = append(verifiedTimestamps, root.Timestamp{Time: entry.IntegratedTime(), URI: tlogVerifier.BaseURL})
}
// DO NOT use timestamp with only an inclusion proof, because it is not signed metadata
}

// Ensure entry signature matches signature from bundle
if !bytes.Equal(entry.Signature(), entitySignature) {
return nil, errors.New("transparency log signature does not match")
Expand Down Expand Up @@ -191,12 +146,3 @@ func getVerifier(publicKey crypto.PublicKey, hashFunc crypto.Hash) (*signature.V

return &verifier, nil
}

func getRekorClient(baseURL string) (*rekorGeneratedClient.Rekor, error) {
client, err := rekorClient.GetRekorClient(baseURL, rekorClient.WithUserAgent(util.ConstructUserAgent()))
if err != nil {
return nil, err
}

return client, nil
}
Loading

0 comments on commit f4f0b6e

Please sign in to comment.