@@ -43,8 +43,14 @@ import (
43
43
"github.com/sigstore/cosign/v2/internal/pkg/cosign"
44
44
"github.com/sigstore/cosign/v2/pkg/blob"
45
45
cbundle "github.com/sigstore/cosign/v2/pkg/cosign/bundle"
46
+
47
+ ocibundle "github.com/sigstore/cosign/v2/pkg/oci/bundle"
46
48
"github.com/sigstore/cosign/v2/pkg/oci/static"
47
49
"github.com/sigstore/cosign/v2/pkg/types"
50
+ protobundle "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1"
51
+ sgbundle "github.com/sigstore/sigstore-go/pkg/bundle"
52
+ "github.com/sigstore/sigstore-go/pkg/root"
53
+ sgverify "github.com/sigstore/sigstore-go/pkg/verify"
48
54
49
55
"github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer"
50
56
"github.com/google/go-containerregistry/pkg/name"
@@ -83,6 +89,14 @@ type Identity struct {
83
89
SubjectRegExp string
84
90
}
85
91
92
+ // type CertPool struct {
93
+ // certs []*x509.Certificate
94
+ // }
95
+
96
+ // func (c *CertPool) AddCert(cert *x509.Certificate) {
97
+ // c.certs = append(c.certs, cert)
98
+ // }
99
+
86
100
// CheckOpts are the options for checking signatures.
87
101
type CheckOpts struct {
88
102
// RegistryClientOpts are the options for interacting with the container registry.
@@ -163,6 +177,16 @@ type CheckOpts struct {
163
177
// Should the experimental OCI 1.1 behaviour be enabled or not.
164
178
// Defaults to false.
165
179
ExperimentalOCI11 bool
180
+
181
+ ExpectSigstoreBundle bool
182
+
183
+ // TrustedMaterial is the trusted material to use for verification.
184
+ // Currently, this is only applicable when ExpectSigstoreBundle is true.
185
+ TrustedMaterial root.TrustedMaterial
186
+
187
+ // TODO: Add the following, deprecate overlapping fields
188
+ //CertificateIdentities verify.CertificateIdentities
189
+ //VerifierOptions []verify.VerifierOption
166
190
}
167
191
168
192
// This is a substitutable signature verification function that can be used for verifying
@@ -495,6 +519,10 @@ func VerifyImageSignatures(ctx context.Context, signedImgRef name.Reference, co
495
519
}
496
520
}
497
521
522
+ if co .ExpectSigstoreBundle {
523
+ return nil , false , errors .New ("bundle support for image signatures is not yet implemented" )
524
+ }
525
+
498
526
// Enforce this up front.
499
527
if co .RootCerts == nil && co .SigVerifier == nil {
500
528
return nil , false , errors .New ("one of verifier or root certs is required" )
@@ -842,6 +870,24 @@ func loadSignatureFromFile(ctx context.Context, sigRef string, signedImgRef name
842
870
targetSig = []byte (sigRef )
843
871
}
844
872
873
+ if co .ExpectSigstoreBundle {
874
+ var bundle * sgbundle.Bundle
875
+ bundle .Bundle = new (protobundle.Bundle )
876
+
877
+ err = bundle .UnmarshalJSON (targetSig )
878
+ if err != nil {
879
+ return nil , err
880
+ }
881
+ signature , err := ocibundle .NewSignature (bundle , & ocibundle.Options {})
882
+ if err != nil {
883
+ return nil , err
884
+ }
885
+
886
+ return & fakeOCISignatures {
887
+ signatures : []oci.Signature {signature },
888
+ }, nil
889
+ }
890
+
845
891
_ , err = base64 .StdEncoding .DecodeString (string (targetSig ))
846
892
847
893
if err == nil {
@@ -880,8 +926,11 @@ func loadSignatureFromFile(ctx context.Context, sigRef string, signedImgRef name
880
926
// If there were no valid attestations, we return an error.
881
927
func VerifyImageAttestations (ctx context.Context , signedImgRef name.Reference , co * CheckOpts ) (checkedAttestations []oci.Signature , bundleVerified bool , err error ) {
882
928
// Enforce this up front.
883
- if co .RootCerts == nil && co .SigVerifier == nil {
884
- return nil , false , errors .New ("one of verifier or root certs is required" )
929
+ if co .RootCerts == nil && co .SigVerifier == nil && co .TrustedMaterial == nil {
930
+ return nil , false , errors .New ("one of verifier, root certs, or TrustedMaterial is required" )
931
+ }
932
+ if co .ExpectSigstoreBundle {
933
+ return verifyImageAttestationsSigstoreBundle (ctx , signedImgRef , co )
885
934
}
886
935
887
936
// This is a carefully optimized sequence for fetching the attestations of
@@ -1413,3 +1462,104 @@ func verifyImageSignaturesExperimentalOCI(ctx context.Context, signedImgRef name
1413
1462
1414
1463
return verifySignatures (ctx , sigs , h , co )
1415
1464
}
1465
+
1466
+ func getBundles (ctx context.Context , signedImgRef name.Reference , co * CheckOpts ) ([]* sgbundle.Bundle , * v1.Hash , error ) {
1467
+ // Enforce this up front.
1468
+ if co .TrustedMaterial == nil {
1469
+ return nil , nil , errors .New ("Sigstore bundle verification requires TrustedMaterial" )
1470
+ }
1471
+
1472
+ // This is a carefully optimized sequence for fetching the signatures of the
1473
+ // entity that minimizes registry requests when supplied with a digest input
1474
+ digest , err := ociremote .ResolveDigest (signedImgRef , co .RegistryClientOpts ... )
1475
+ if err != nil {
1476
+ if terr := (& transport.Error {}); errors .As (err , & terr ) && terr .StatusCode == http .StatusNotFound {
1477
+ return nil , nil , & ErrImageTagNotFound {
1478
+ fmt .Errorf ("image tag not found: %w" , err ),
1479
+ }
1480
+ }
1481
+ return nil , nil , err
1482
+ }
1483
+ h , err := v1 .NewHash (digest .Identifier ())
1484
+ if err != nil {
1485
+ return nil , nil , err
1486
+ }
1487
+
1488
+ index , err := ociremote .Referrers (digest , "" , co .RegistryClientOpts ... )
1489
+ if err != nil {
1490
+ return nil , nil , err
1491
+ }
1492
+ var bundles = make ([]* sgbundle.Bundle , 0 , len (index .Manifests ))
1493
+ for _ , result := range index .Manifests {
1494
+ st , err := name .ParseReference (fmt .Sprintf ("%s@%s" , digest .Repository , result .Digest .String ()))
1495
+ if err != nil {
1496
+ return nil , nil , err
1497
+ }
1498
+ bundle , err := ociremote .Bundle (st , co .RegistryClientOpts ... )
1499
+ if err != nil {
1500
+ return nil , nil , err
1501
+ }
1502
+ bundles = append (bundles , bundle )
1503
+ }
1504
+
1505
+ return bundles , & h , nil
1506
+ }
1507
+
1508
+ // verifyImageAttestationsSigstoreBundle verifies attestations from attached sigstore bundles
1509
+ func verifyImageAttestationsSigstoreBundle (ctx context.Context , signedImgRef name.Reference , co * CheckOpts ) (checkedSignatures []oci.Signature , bundleVerified bool , err error ) {
1510
+ bundles , hash , err := getBundles (ctx , signedImgRef , co )
1511
+ if err != nil {
1512
+ return nil , false , err
1513
+ }
1514
+
1515
+ digestBytes , err := hex .DecodeString (hash .Hex )
1516
+ if err != nil {
1517
+ return nil , false , err
1518
+ }
1519
+
1520
+ // TODO: build verifierConfig from CheckOpts
1521
+ verifierConfig := []sgverify.VerifierOption {
1522
+ sgverify .WithSignedCertificateTimestamps (1 ),
1523
+ sgverify .WithTransparencyLog (1 ),
1524
+ sgverify .WithIntegratedTimestamps (1 ),
1525
+ }
1526
+
1527
+ sev , err := sgverify .NewSignedEntityVerifier (co .TrustedMaterial , verifierConfig ... )
1528
+ if err != nil {
1529
+ return nil , false , err
1530
+ }
1531
+
1532
+ policyOptions := make ([]sgverify.PolicyOption , 0 , len (co .Identities ))
1533
+ for _ , i := range co .Identities {
1534
+ id , err := sgverify .NewShortCertificateIdentity (i .Issuer , i .IssuerRegExp , i .Subject , i .SubjectRegExp )
1535
+ if err != nil {
1536
+ return nil , false , err
1537
+ }
1538
+ policyOptions = append (policyOptions , sgverify .WithCertificateIdentity (id ))
1539
+ }
1540
+ policy := sgverify .NewPolicy (sgverify .WithArtifactDigest (hash .Algorithm , digestBytes ), policyOptions ... )
1541
+
1542
+ checkedSignatures = make ([]oci.Signature , 0 , len (bundles ))
1543
+ for _ , bundle := range bundles {
1544
+ _ , err := sev .Verify (bundle , policy )
1545
+ if err != nil {
1546
+ continue
1547
+ }
1548
+ dsse , ok := bundle .Content .(* protobundle.Bundle_DsseEnvelope )
1549
+ if ! ok {
1550
+ continue
1551
+ }
1552
+ payload , err := json .Marshal (dsse .DsseEnvelope )
1553
+ if err != nil {
1554
+ continue
1555
+ }
1556
+ // TODO: Add additional data to oci.Signature (Cert, Rekor Bundle, Timestamp, etc)
1557
+ sig , err := static .NewAttestation (payload )
1558
+ if err != nil {
1559
+ continue
1560
+ }
1561
+ checkedSignatures = append (checkedSignatures , sig )
1562
+ bundleVerified = true
1563
+ }
1564
+ return checkedSignatures , bundleVerified , nil
1565
+ }
0 commit comments