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

Use default Verifier for the public key contained in a certificate (closes #74) #424

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion examples/oci-image-verification/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ replace github.com/sigstore/sigstore-go => ../../
require (
github.com/google/go-containerregistry v0.20.3
github.com/sigstore/protobuf-specs v0.4.1
github.com/sigstore/sigstore v1.9.1
github.com/sigstore/sigstore v1.9.2-0.20250408060058-404e5b5549bc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

github.com/sigstore/sigstore-go v0.6.2
)

Expand Down
4 changes: 2 additions & 2 deletions examples/oci-image-verification/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ github.com/sigstore/protobuf-specs v0.4.1 h1:5SsMqZbdkcO/DNHudaxuCUEjj6x29tS2Xby
github.com/sigstore/protobuf-specs v0.4.1/go.mod h1:+gXR+38nIa2oEupqDdzg4qSBT0Os+sP7oYv6alWewWc=
github.com/sigstore/rekor v1.3.9 h1:sUjRpKVh/hhgqGMs0t+TubgYsksArZ6poLEC3MsGAzU=
github.com/sigstore/rekor v1.3.9/go.mod h1:xThNUhm6eNEmkJ/SiU/FVU7pLY2f380fSDZFsdDWlcM=
github.com/sigstore/sigstore v1.9.1 h1:bNMsfFATsMPaagcf+uppLk4C9rQZ2dh5ysmCxQBYWaw=
github.com/sigstore/sigstore v1.9.1/go.mod h1:zUoATYzR1J3rLNp3jmp4fzIJtWdhC3ZM6MnpcBtnsE4=
github.com/sigstore/sigstore v1.9.2-0.20250408060058-404e5b5549bc h1:b2wvxtPzan3vHxn7WvODQsPO9+EbTKQx7Kexmxm8XoI=
github.com/sigstore/sigstore v1.9.2-0.20250408060058-404e5b5549bc/go.mod h1:VwYkiw0G0dRtwL25KSs04hCyVFF6CYMd/qvNeYrl7EQ=
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.9.1 h1:/YcNq687WnXpIRXl04nLfJX741G4iW+w+7Nem2Zy0f4=
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.9.1/go.mod h1:ApL9RpKsi7gkSYN0bMNdm/3jZ9EefxMmfYHfUmq2ZYM=
github.com/sigstore/sigstore/pkg/signature/kms/azure v1.9.1 h1:FnusXyTIInnwfIOzzl5PFilRm1I97dxMSOcCkZBu9Kc=
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ require (
github.com/secure-systems-lab/go-securesystemslib v0.9.0
github.com/sigstore/protobuf-specs v0.4.1
github.com/sigstore/rekor v1.3.9
github.com/sigstore/sigstore v1.9.1
github.com/sigstore/sigstore v1.9.2-0.20250408060058-404e5b5549bc
github.com/sigstore/timestamp-authority v1.2.5
github.com/stretchr/testify v1.10.0
github.com/theupdateframework/go-tuf/v2 v2.0.2
Expand All @@ -29,7 +29,7 @@ require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/coreos/go-oidc/v3 v3.12.0 // indirect
github.com/coreos/go-oidc/v3 v3.13.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
github.com/coreos/go-oidc/v3 v3.12.0 h1:sJk+8G2qq94rDI6ehZ71Bol3oUHy63qNYmkiSjrc/Jo=
github.com/coreos/go-oidc/v3 v3.12.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
github.com/coreos/go-oidc/v3 v3.13.0 h1:M66zd0pcc5VxvBNM4pB331Wrsanby+QomQYjN8HamW8=
github.com/coreos/go-oidc/v3 v3.13.0/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 h1:vU+EP9ZuFUCYE0NYLwTSob+3LNEJATzNfP/DC7SWGWI=
github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
Expand Down Expand Up @@ -280,8 +280,8 @@ github.com/sigstore/protobuf-specs v0.4.1 h1:5SsMqZbdkcO/DNHudaxuCUEjj6x29tS2Xby
github.com/sigstore/protobuf-specs v0.4.1/go.mod h1:+gXR+38nIa2oEupqDdzg4qSBT0Os+sP7oYv6alWewWc=
github.com/sigstore/rekor v1.3.9 h1:sUjRpKVh/hhgqGMs0t+TubgYsksArZ6poLEC3MsGAzU=
github.com/sigstore/rekor v1.3.9/go.mod h1:xThNUhm6eNEmkJ/SiU/FVU7pLY2f380fSDZFsdDWlcM=
github.com/sigstore/sigstore v1.9.1 h1:bNMsfFATsMPaagcf+uppLk4C9rQZ2dh5ysmCxQBYWaw=
github.com/sigstore/sigstore v1.9.1/go.mod h1:zUoATYzR1J3rLNp3jmp4fzIJtWdhC3ZM6MnpcBtnsE4=
github.com/sigstore/sigstore v1.9.2-0.20250408060058-404e5b5549bc h1:b2wvxtPzan3vHxn7WvODQsPO9+EbTKQx7Kexmxm8XoI=
github.com/sigstore/sigstore v1.9.2-0.20250408060058-404e5b5549bc/go.mod h1:VwYkiw0G0dRtwL25KSs04hCyVFF6CYMd/qvNeYrl7EQ=
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.9.1 h1:/YcNq687WnXpIRXl04nLfJX741G4iW+w+7Nem2Zy0f4=
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.9.1/go.mod h1:ApL9RpKsi7gkSYN0bMNdm/3jZ9EefxMmfYHfUmq2ZYM=
github.com/sigstore/sigstore/pkg/signature/kms/azure v1.9.1 h1:FnusXyTIInnwfIOzzl5PFilRm1I97dxMSOcCkZBu9Kc=
Expand Down
8 changes: 6 additions & 2 deletions pkg/bundle/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func NewProtobufBundle(b *protobundle.Bundle) (*ProtobufBundle, error) {
}

func (b *Bundle) validate() error {
bundleVersion, err := getBundleVersion(b.MediaType)
bundleVersion, err := b.Version()
if err != nil {
return fmt.Errorf("error getting bundle version: %w", err)
}
Expand Down Expand Up @@ -152,6 +152,10 @@ func MediaTypeString(version string) (string, error) {
return mtString, nil
}

func (b *Bundle) Version() (string, error) {
return getBundleVersion(b.MediaType)
}

func getBundleVersion(mediaType string) (string, error) {
switch mediaType {
case mediaTypeBase + "+json;version=0.1":
Expand Down Expand Up @@ -369,7 +373,7 @@ func (b *Bundle) Timestamps() ([][]byte, error) {

// MinVersion returns true if the bundle version is greater than or equal to the expected version.
func (b *Bundle) MinVersion(expectVersion string) bool {
version, err := getBundleVersion(b.MediaType)
version, err := b.Version()
if err != nil {
return false
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/sign/transparency_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (m *mockRekor) CreateLogEntry(_ *entries.CreateLogEntryParams, _ ...entries
return nil, err
}

signer, err := signature.LoadECDSASignerVerifier(leafPrivKey, crypto.SHA256)
signer, err := signature.LoadSignerVerifier(leafPrivKey, crypto.SHA256)
if err != nil {
return nil, err
}
Expand Down
112 changes: 88 additions & 24 deletions pkg/testing/ca/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"crypto/x509/pkix"
Expand All @@ -38,6 +39,7 @@ import (
"github.com/go-openapi/runtime"
"github.com/go-openapi/swag"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
"github.com/sigstore/rekor/pkg/generated/models"
"github.com/sigstore/rekor/pkg/pki"
"github.com/sigstore/rekor/pkg/types"
Expand All @@ -56,16 +58,17 @@ import (
)

type VirtualSigstore struct {
fulcioCA *root.FulcioCertificateAuthority
fulcioIntermediateKey *ecdsa.PrivateKey
tsaCA *root.SigstoreTimestampingAuthority
tsaLeafKey *ecdsa.PrivateKey
rekorKey *ecdsa.PrivateKey
ctlogKey *ecdsa.PrivateKey
publicKeyVerifier map[string]root.TimeConstrainedVerifier
fulcioCA *root.FulcioCertificateAuthority
fulcioIntermediateKey *ecdsa.PrivateKey
tsaCA *root.SigstoreTimestampingAuthority
tsaLeafKey *ecdsa.PrivateKey
rekorKey *ecdsa.PrivateKey
ctlogKey *ecdsa.PrivateKey
publicKeyVerifier map[string]root.TimeConstrainedVerifier
signingAlgorithmDetails signature.AlgorithmDetails
}

func NewVirtualSigstore() (*VirtualSigstore, error) {
func NewVirtualSigstoreWithSigningAlg(signingKeyDetails v1.PublicKeyDetails) (*VirtualSigstore, error) {
ss := &VirtualSigstore{fulcioCA: &root.FulcioCertificateAuthority{}, tsaCA: &root.SigstoreTimestampingAuthority{}}

rootCert, rootKey, err := GenerateRootCa()
Expand Down Expand Up @@ -109,10 +112,18 @@ func NewVirtualSigstore() (*VirtualSigstore, error) {
if err != nil {
return nil, err
}
ss.signingAlgorithmDetails, err = signature.GetAlgorithmDetails(signingKeyDetails)
if err != nil {
return nil, err
}

return ss, nil
}

func NewVirtualSigstore() (*VirtualSigstore, error) {
return NewVirtualSigstoreWithSigningAlg(v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256)
}

// getLogID calculates the digest of a PKIX-encoded public key
func getLogID(pub crypto.PublicKey) (string, error) {
pubBytes, err := x509.MarshalPKIXPublicKey(pub)
Expand Down Expand Up @@ -147,8 +158,25 @@ func (ca *VirtualSigstore) RekorSignPayload(payload tlog.RekorPayload) ([]byte,
return bundleSig, nil
}

func (ca *VirtualSigstore) GenerateLeafCert(identity, issuer string) (*x509.Certificate, *ecdsa.PrivateKey, error) {
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
func (ca *VirtualSigstore) GenerateLeafCert(identity, issuer string) (*x509.Certificate, crypto.PrivateKey, error) {
var privKey crypto.PrivateKey
var err error
switch ca.signingAlgorithmDetails.GetKeyType() {
case signature.ECDSA:
var curve *elliptic.Curve
curve, err = ca.signingAlgorithmDetails.GetECDSACurve()
if err != nil {
return nil, nil, err
}
privKey, err = ecdsa.GenerateKey(*curve, rand.Reader)
case signature.RSA:
var keySize signature.RSAKeySize
keySize, err = ca.signingAlgorithmDetails.GetRSAKeySize()
if err != nil {
return nil, nil, err
}
privKey, err = rsa.GenerateKey(rand.Reader, int(keySize))
}
if err != nil {
return nil, nil, err
}
Expand All @@ -171,7 +199,7 @@ func (ca *VirtualSigstore) AttestAtTime(identity, issuer string, envelopeBody []
return nil, err
}

signer, err := signature.LoadECDSASignerVerifier(leafPrivKey, crypto.SHA256)
signer, err := signature.LoadSignerFromAlgorithmDetails(leafPrivKey, ca.signingAlgorithmDetails)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -213,21 +241,42 @@ func (ca *VirtualSigstore) AttestAtTime(identity, issuer string, envelopeBody []
}

func (ca *VirtualSigstore) Sign(identity, issuer string, artifact []byte) (*TestEntity, error) {
return ca.SignAtTime(identity, issuer, artifact, time.Now().Add(5*time.Minute))
return ca.SignAtTimeWithVersion(identity, issuer, artifact, time.Now().Add(5*time.Minute), "v0.3")
}

func (ca *VirtualSigstore) SignWithVersion(identity, issuer string, artifact []byte, version string) (*TestEntity, error) {
return ca.SignAtTimeWithVersion(identity, issuer, artifact, time.Now().Add(5*time.Minute), version)
}

func (ca *VirtualSigstore) SignAtTime(identity, issuer string, artifact []byte, integratedTime time.Time) (*TestEntity, error) {
return ca.SignAtTimeWithVersion(identity, issuer, artifact, integratedTime, "v0.3")
}

func (ca *VirtualSigstore) SignAtTimeWithVersion(identity, issuer string, artifact []byte, integratedTime time.Time, version string) (*TestEntity, error) {
leafCert, leafPrivKey, err := ca.GenerateLeafCert(identity, issuer)
if err != nil {
return nil, err
}

signer, err := signature.LoadECDSASignerVerifier(leafPrivKey, crypto.SHA256)
signer, err := signature.LoadSignerFromAlgorithmDetails(leafPrivKey, ca.signingAlgorithmDetails)
if err != nil {
return nil, err
}

digest := sha256.Sum256(artifact)
hashType := ca.signingAlgorithmDetails.GetHashType()
hasher := hashType.New()
hasher.Write(artifact)
digest := hasher.Sum(nil)

var digestString string
switch hashType {
case crypto.SHA256:
digestString = "SHA2_256"
case crypto.SHA384:
digestString = "SHA2_384"
case crypto.SHA512:
digestString = "SHA2_512"
}
sig, err := signer.SignMessage(bytes.NewReader(artifact))
if err != nil {
return nil, err
Expand All @@ -246,8 +295,9 @@ func (ca *VirtualSigstore) SignAtTime(identity, issuer string, artifact []byte,
return &TestEntity{
certChain: []*x509.Certificate{leafCert, ca.fulcioCA.Intermediates[0], ca.fulcioCA.Root},
timestamps: [][]byte{tsr},
messageSignature: bundle.NewMessageSignature(digest[:], "SHA2_256", sig),
messageSignature: bundle.NewMessageSignature(digest, digestString, sig),
tlogEntries: []*tlog.Entry{entry},
version: version,
}, nil
}

Expand All @@ -262,7 +312,7 @@ func (ca *VirtualSigstore) GenerateTlogEntry(leafCert *x509.Certificate, envelop
return nil, err
}

rekorBody, err := generateRekorEntry(intoto.KIND, intoto.New().DefaultVersion(), envelopeBytes, leafCertPem, sig)
rekorBody, err := generateRekorEntry(intoto.KIND, intoto.New().DefaultVersion(), envelopeBytes, leafCertPem, sig, ca.signingAlgorithmDetails)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -327,7 +377,7 @@ func (ca *VirtualSigstore) generateTlogEntryHashedRekord(leafCert *x509.Certific
return nil, err
}

rekorBody, err := generateRekorEntry(hashedrekord.KIND, hashedrekord.New().DefaultVersion(), artifact, leafCertPem, sig)
rekorBody, err := generateRekorEntry(hashedrekord.KIND, hashedrekord.New().DefaultVersion(), artifact, leafCertPem, sig, ca.signingAlgorithmDetails)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -366,9 +416,9 @@ func (ca *VirtualSigstore) PublicKeyVerifier(keyID string) (root.TimeConstrained
return v, nil
}

func generateRekorEntry(kind, version string, artifact []byte, cert []byte, sig []byte) (string, error) {
func generateRekorEntry(kind, version string, artifact []byte, cert []byte, sig []byte, algorithmDetails signature.AlgorithmDetails) (string, error) {
// Generate the Rekor Entry
entryImpl, err := createEntry(context.Background(), kind, version, artifact, cert, sig)
entryImpl, err := createEntry(context.Background(), kind, version, artifact, cert, sig, algorithmDetails)
if err != nil {
return "", err
}
Expand All @@ -379,7 +429,7 @@ func generateRekorEntry(kind, version string, artifact []byte, cert []byte, sig
return base64.StdEncoding.EncodeToString(entryBytes), nil
}

func createEntry(ctx context.Context, kind, apiVersion string, blobBytes, certBytes, sigBytes []byte) (types.EntryImpl, error) {
func createEntry(ctx context.Context, kind, apiVersion string, blobBytes, certBytes, sigBytes []byte, algorithmDetails signature.AlgorithmDetails) (types.EntryImpl, error) {
props := types.ArtifactProperties{
PublicKeyBytes: [][]byte{certBytes},
PKIFormat: string(pki.X509),
Expand All @@ -389,8 +439,12 @@ func createEntry(ctx context.Context, kind, apiVersion string, blobBytes, certBy
props.ArtifactBytes = blobBytes
props.SignatureBytes = sigBytes
case hashedrekord.KIND:
blobHash := sha256.Sum256(blobBytes)
props.ArtifactHash = strings.ToLower(hex.EncodeToString(blobHash[:]))
hashType := algorithmDetails.GetHashType()
hasher := hashType.New()
hasher.Write(blobBytes)
blobHash := hasher.Sum(nil)

props.ArtifactHash = strings.ToLower(hex.EncodeToString(blobHash))
props.SignatureBytes = sigBytes
default:
return nil, fmt.Errorf("unexpected entry kind: %s", kind)
Expand Down Expand Up @@ -513,6 +567,7 @@ type TestEntity struct {
messageSignature *bundle.MessageSignature
timestamps [][]byte
tlogEntries []*tlog.Entry
version string
}

func (e *TestEntity) VerificationContent() (verify.VerificationContent, error) {
Expand All @@ -523,6 +578,10 @@ func (e *TestEntity) HasInclusionPromise() bool {
return true
}

func (e *TestEntity) Version() (string, error) {
return e.version, nil
}

func (e *TestEntity) HasInclusionProof() bool {
for _, tlog := range e.tlogEntries {
if tlog.HasInclusionProof() {
Expand Down Expand Up @@ -645,7 +704,7 @@ func GenerateTSAIntermediate(rootTemplate *x509.Certificate, rootPriv crypto.Sig
return cert, priv, nil
}

func GenerateLeafCert(subject string, oidcIssuer string, expiration time.Time, priv *ecdsa.PrivateKey,
func GenerateLeafCert(subject string, oidcIssuer string, expiration time.Time, priv crypto.PrivateKey,
parentTemplate *x509.Certificate, parentPriv crypto.Signer) (*x509.Certificate, error) {
certTemplate := &x509.Certificate{
SerialNumber: big.NewInt(1),
Expand All @@ -664,7 +723,12 @@ func GenerateLeafCert(subject string, oidcIssuer string, expiration time.Time, p
},
}

cert, err := createCertificate(certTemplate, parentTemplate, &priv.PublicKey, parentPriv)
signer, ok := priv.(crypto.Signer)
if !ok {
return nil, fmt.Errorf("private key does not implement crypto.Signer")
}

cert, err := createCertificate(certTemplate, parentTemplate, signer.Public(), parentPriv)
if err != nil {
return nil, err
}
Expand Down
9 changes: 9 additions & 0 deletions pkg/verify/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,18 @@ type VerificationProvider interface {
VerificationContent() (VerificationContent, error)
}

type VersionProvider interface {
Version() (string, error)
}

type SignedEntity interface {
HasInclusionPromise
HasInclusionProof
SignatureProvider
SignedTimestampProvider
TlogEntryProvider
VerificationProvider
VersionProvider
}

type VerificationContent interface {
Expand Down Expand Up @@ -119,3 +124,7 @@ func (b *BaseSignedEntity) Timestamps() ([][]byte, error) {
func (b *BaseSignedEntity) TlogEntries() ([]*tlog.Entry, error) {
return nil, errNotImplemented
}

func (b *BaseSignedEntity) Version() (string, error) {
return "", errNotImplemented
}
Loading
Loading