Skip to content

Commit 11163ae

Browse files
Bump sigstore-go, support alternative hash algorithms with keys (#4386)
* Bump sigstore-go, support alternative hash algorithms with keys sigstore-go now handles non-ECDSA-P-256 signatures with Rekor v2. To support verification, we also need a way to provide alternative hash algorithms to the default SHA-256. cosign verify already had a flag for this, so I added the flag to all verify commands. In the future, when we are only processing bundles, we can lookup the default hash algorithm given the key. Signed-off-by: Hayden <[email protected]> * lint fmt Signed-off-by: Hayden <[email protected]> * Drop support for Fulcio with ed25519ph key We've chosen to not support this in sigstore-go, so we'll also remove this from Cosign. This is a niche edge case where a user provides an ed25519 key or algorithm and requests a cert and logs it to Rekor. We'll revisit this if there's demand or when we support the prehash variant in Fulcio. Signed-off-by: Hayden <[email protected]> --------- Signed-off-by: Hayden <[email protected]> Co-authored-by: Hayden <[email protected]>
1 parent 153df46 commit 11163ae

22 files changed

+216
-105
lines changed

cmd/cosign/cli/fulcio/fulcio.go

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,6 @@ type Signer struct {
7272
}
7373

7474
func NewSigner(ctx context.Context, ko options.KeyOpts, signer signature.SignerVerifier) (*Signer, error) {
75-
return NewSignerWithAdapter(ctx, ko, signer, signer)
76-
}
77-
78-
// NewSignerWithAdapter creates a Fulcio Signer with a `fulcioSigner` that is
79-
// used to sign the Proof Of Possession sent to Fulcio. In most cases this will
80-
// be the same as the `signer`, however it is possible to use a different signer.
81-
// For example when ed25519ph is used for signing, the `fulcioSigner` will be
82-
// the equivalent PureED25519 signer, given that Fulcio does not support ed25519ph.
83-
func NewSignerWithAdapter(ctx context.Context, ko options.KeyOpts, signer signature.SignerVerifier, fulcioSigner signature.SignerVerifier) (*Signer, error) {
8475
fClient, err := NewClient(ko.FulcioURL)
8576
if err != nil {
8677
return nil, fmt.Errorf("creating Fulcio client: %w", err)
@@ -96,7 +87,7 @@ func NewSignerWithAdapter(ctx context.Context, ko options.KeyOpts, signer signat
9687
return nil, fmt.Errorf("setting auth flow: %w", err)
9788
}
9889

99-
resp, err := GetCert(ctx, fulcioSigner, idToken, flow, ko.OIDCIssuer, ko.OIDCClientID, ko.OIDCClientSecret, ko.OIDCRedirectURL, fClient)
90+
resp, err := GetCert(ctx, signer, idToken, flow, ko.OIDCIssuer, ko.OIDCClientID, ko.OIDCClientSecret, ko.OIDCRedirectURL, fClient)
10091
if err != nil {
10192
return nil, fmt.Errorf("retrieving cert: %w", err)
10293
}

cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,7 @@ import (
3030
)
3131

3232
func NewSigner(ctx context.Context, ko options.KeyOpts, signer signature.SignerVerifier) (*fulcio.Signer, error) {
33-
return NewSignerWithAdapter(ctx, ko, signer, signer)
34-
}
35-
36-
func NewSignerWithAdapter(ctx context.Context, ko options.KeyOpts, signer signature.SignerVerifier, fulcioSigner signature.SignerVerifier) (*fulcio.Signer, error) {
37-
fs, err := fulcio.NewSignerWithAdapter(ctx, ko, signer, fulcioSigner)
33+
fs, err := fulcio.NewSigner(ctx, ko, signer)
3834
if err != nil {
3935
return nil, err
4036
}

cmd/cosign/cli/options/verify.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ type VerifyAttestationOptions struct {
137137
CertVerify CertVerifyOptions
138138
Registry RegistryOptions
139139
Predicate PredicateRemoteOptions
140+
SignatureDigest SignatureDigestOptions
140141
Policies []string
141142
LocalImage bool
142143
}
@@ -151,6 +152,7 @@ func (o *VerifyAttestationOptions) AddFlags(cmd *cobra.Command) {
151152
o.Registry.AddFlags(cmd)
152153
o.Predicate.AddFlags(cmd)
153154
o.CommonVerifyOptions.AddFlags(cmd)
155+
o.SignatureDigest.AddFlags(cmd)
154156

155157
cmd.Flags().StringVar(&o.Key, "key", "",
156158
"path to the public key file, KMS URI or Kubernetes Secret")
@@ -178,6 +180,7 @@ type VerifyBlobOptions struct {
178180
CertVerify CertVerifyOptions
179181
Rekor RekorOptions
180182
CommonVerifyOptions CommonVerifyOptions
183+
SignatureDigest SignatureDigestOptions
181184

182185
RFC3161TimestampPath string
183186
}
@@ -190,6 +193,7 @@ func (o *VerifyBlobOptions) AddFlags(cmd *cobra.Command) {
190193
o.Rekor.AddFlags(cmd)
191194
o.CertVerify.AddFlags(cmd)
192195
o.CommonVerifyOptions.AddFlags(cmd)
196+
o.SignatureDigest.AddFlags(cmd)
193197

194198
cmd.Flags().StringVar(&o.Key, "key", "",
195199
"path to the public key file, KMS URI or Kubernetes Secret")
@@ -233,6 +237,7 @@ type VerifyBlobAttestationOptions struct {
233237
CertVerify CertVerifyOptions
234238
Rekor RekorOptions
235239
CommonVerifyOptions CommonVerifyOptions
240+
SignatureDigest SignatureDigestOptions
236241

237242
RFC3161TimestampPath string
238243

@@ -249,6 +254,7 @@ func (o *VerifyBlobAttestationOptions) AddFlags(cmd *cobra.Command) {
249254
o.Rekor.AddFlags(cmd)
250255
o.CertVerify.AddFlags(cmd)
251256
o.CommonVerifyOptions.AddFlags(cmd)
257+
o.SignatureDigest.AddFlags(cmd)
252258

253259
cmd.Flags().StringVar(&o.Key, "key", "",
254260
"path to the public key file, KMS URI or Kubernetes Secret")

cmd/cosign/cli/sign/sign.go

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -702,45 +702,22 @@ func signerFromNewKey() (*SignerVerifier, error) {
702702
}, nil
703703
}
704704

705-
// adaptSignerVerifierToFulcio adapts, if necessary, the SignerVerifier to be
706-
// used to interact with Fulcio.
707-
//
708-
// This is needed in particular for ED25519 keys with the pre-hashed version of
709-
// the algorithm, which is not supported by Fulcio. This function creates a
710-
// ED25519 SignerVerifier based on that instead.
711-
func adaptSignerVerifierToFulcio(sv *SignerVerifier) (*SignerVerifier, error) {
712-
if ed25519phSV, ok := sv.SignerVerifier.(*signature.ED25519phSignerVerifier); ok {
713-
signerVerifier, err := ed25519phSV.ToED25519SignerVerifier()
714-
if err != nil {
715-
return nil, err
716-
}
717-
718-
return &SignerVerifier{
719-
SignerVerifier: signerVerifier,
720-
Cert: sv.Cert,
721-
Chain: sv.Chain,
722-
}, nil
723-
}
724-
return sv, nil
725-
}
726-
727705
func KeylessSigner(ctx context.Context, ko options.KeyOpts, sv *SignerVerifier) (*SignerVerifier, error) {
728706
var (
729707
k *fulcio.Signer
730708
err error
731709
)
732710

733-
fulcioSV, err := adaptSignerVerifierToFulcio(sv)
734-
if err != nil {
735-
return nil, fmt.Errorf("adapting signer verifier to Fulcio: %w", err)
711+
if _, ok := sv.SignerVerifier.(*signature.ED25519phSignerVerifier); ok {
712+
return nil, fmt.Errorf("ed25519ph unsupported by Fulcio")
736713
}
737714

738715
if ko.InsecureSkipFulcioVerify {
739-
if k, err = fulcio.NewSignerWithAdapter(ctx, ko, sv, fulcioSV); err != nil {
716+
if k, err = fulcio.NewSigner(ctx, ko, sv); err != nil {
740717
return nil, fmt.Errorf("getting key from Fulcio: %w", err)
741718
}
742719
} else {
743-
if k, err = fulcioverifier.NewSignerWithAdapter(ctx, ko, sv, fulcioSV); err != nil {
720+
if k, err = fulcioverifier.NewSigner(ctx, ko, sv); err != nil {
744721
return nil, fmt.Errorf("getting key from Fulcio: %w", err)
745722
}
746723
}

cmd/cosign/cli/verify.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,11 @@ against the transparency log.`,
218218
o.CommonVerifyOptions.IgnoreTlog = true
219219
}
220220

221+
hashAlgorithm, err := o.SignatureDigest.HashAlgorithm()
222+
if err != nil {
223+
return err
224+
}
225+
221226
v := &verify.VerifyAttestationCommand{
222227
RegistryOptions: o.Registry,
223228
CommonVerifyOptions: o.CommonVerifyOptions,
@@ -247,6 +252,7 @@ against the transparency log.`,
247252
TSACertChainPath: o.CommonVerifyOptions.TSACertChainPath,
248253
IgnoreTlog: o.CommonVerifyOptions.IgnoreTlog,
249254
MaxWorkers: o.CommonVerifyOptions.MaxWorkers,
255+
HashAlgorithm: hashAlgorithm,
250256
UseSignedTimestamps: o.CommonVerifyOptions.UseSignedTimestamps,
251257
}
252258

@@ -330,6 +336,11 @@ The blob may be specified as a path to a file or - for stdin.`,
330336
o.CommonVerifyOptions.IgnoreTlog = true
331337
}
332338

339+
hashAlgorithm, err := o.SignatureDigest.HashAlgorithm()
340+
if err != nil {
341+
return err
342+
}
343+
333344
ko := options.KeyOpts{
334345
KeyRef: o.Key,
335346
Sk: o.SecurityKey.Use,
@@ -359,6 +370,7 @@ The blob may be specified as a path to a file or - for stdin.`,
359370
IgnoreTlog: o.CommonVerifyOptions.IgnoreTlog,
360371
UseSignedTimestamps: o.CommonVerifyOptions.UseSignedTimestamps,
361372
TrustedRootPath: o.CommonVerifyOptions.TrustedRootPath,
373+
HashAlgorithm: hashAlgorithm,
362374
}
363375

364376
ctx, cancel := context.WithTimeout(cmd.Context(), ro.Timeout)
@@ -401,6 +413,11 @@ The blob may be specified as a path to a file.`,
401413
o.CommonVerifyOptions.IgnoreTlog = true
402414
}
403415

416+
hashAlgorithm, err := o.SignatureDigest.HashAlgorithm()
417+
if err != nil {
418+
return err
419+
}
420+
404421
ko := options.KeyOpts{
405422
KeyRef: o.Key,
406423
Sk: o.SecurityKey.Use,
@@ -434,6 +451,7 @@ The blob may be specified as a path to a file.`,
434451
TrustedRootPath: o.CommonVerifyOptions.TrustedRootPath,
435452
Digest: o.Digest,
436453
DigestAlg: o.DigestAlg,
454+
HashAlgorithm: hashAlgorithm,
437455
}
438456
// We only use the blob if we are checking claims.
439457
if o.CheckClaims && len(args) == 0 && (o.Digest == "" || o.DigestAlg == "") {

cmd/cosign/cli/verify/verify_attestation.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package verify
1717

1818
import (
1919
"context"
20+
"crypto"
2021
"errors"
2122
"flag"
2223
"fmt"
@@ -73,6 +74,7 @@ type VerifyAttestationCommand struct {
7374
IgnoreTlog bool
7475
MaxWorkers int
7576
UseSignedTimestamps bool
77+
HashAlgorithm crypto.Hash
7678
}
7779

7880
// Exec runs the verification command
@@ -81,6 +83,11 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e
8183
return flag.ErrHelp
8284
}
8385

86+
// always default to sha256 if the algorithm hasn't been explicitly set
87+
if c.HashAlgorithm == 0 {
88+
c.HashAlgorithm = crypto.SHA256
89+
}
90+
8491
// We can't have both a key and a security key
8592
if options.NOf(c.KeyRef, c.Sk) > 1 {
8693
return &options.KeyParseError{}
@@ -191,7 +198,7 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e
191198
// Keys are optional!
192199
switch {
193200
case keyRef != "":
194-
co.SigVerifier, err = sigs.PublicKeyFromKeyRef(ctx, keyRef)
201+
co.SigVerifier, err = sigs.PublicKeyFromKeyRefWithHashAlgo(ctx, keyRef, c.HashAlgorithm)
195202
if err != nil {
196203
return fmt.Errorf("loading public key: %w", err)
197204
}

cmd/cosign/cli/verify/verify_blob.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,16 @@ type VerifyBlobCmd struct {
7474
Offline bool
7575
UseSignedTimestamps bool
7676
IgnoreTlog bool
77+
HashAlgorithm crypto.Hash
7778
}
7879

7980
// nolint
8081
func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error {
82+
// always default to sha256 if the algorithm hasn't been explicitly set
83+
if c.HashAlgorithm == 0 {
84+
c.HashAlgorithm = crypto.SHA256
85+
}
86+
8187
// Require a certificate/key OR a local bundle file that has the cert.
8288
if options.NOf(c.KeyRef, c.CertRef, c.Sk, c.BundlePath) == 0 {
8389
return fmt.Errorf("provide a key with --key or --sk, a certificate to verify against with --certificate, or a bundle with --bundle")
@@ -116,7 +122,7 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error {
116122
opts := make([]static.Option, 0)
117123
switch {
118124
case c.KeyRef != "":
119-
co.SigVerifier, err = sigs.PublicKeyFromKeyRef(ctx, c.KeyRef)
125+
co.SigVerifier, err = sigs.PublicKeyFromKeyRefWithHashAlgo(ctx, c.KeyRef, c.HashAlgorithm)
120126
if err != nil {
121127
return fmt.Errorf("loading public key: %w", err)
122128
}

cmd/cosign/cli/verify/verify_blob_attestation.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,9 @@ type VerifyBlobAttestationCommand struct {
7979
SignaturePath string // Path to the signature
8080
UseSignedTimestamps bool
8181

82-
Digest string
83-
DigestAlg string
82+
Digest string
83+
DigestAlg string
84+
HashAlgorithm crypto.Hash
8485
}
8586

8687
// Exec runs the verification command
@@ -89,6 +90,11 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st
8990
return fmt.Errorf("please specify path to the DSSE envelope signature via --signature or --bundle")
9091
}
9192

93+
// always default to sha256 if the algorithm hasn't been explicitly set
94+
if c.HashAlgorithm == 0 {
95+
c.HashAlgorithm = crypto.SHA256
96+
}
97+
9298
// Require a certificate/key OR a local bundle file that has the cert.
9399
if options.NOf(c.KeyRef, c.CertRef, c.Sk, c.BundlePath) == 0 {
94100
return fmt.Errorf("provide a key with --key or --sk, a certificate to verify against with --certificate, or a bundle with --bundle")
@@ -126,7 +132,7 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st
126132
opts := make([]static.Option, 0)
127133
switch {
128134
case c.KeyRef != "":
129-
co.SigVerifier, err = sigs.PublicKeyFromKeyRef(ctx, c.KeyRef)
135+
co.SigVerifier, err = sigs.PublicKeyFromKeyRefWithHashAlgo(ctx, c.KeyRef, c.HashAlgorithm)
130136
if err != nil {
131137
return fmt.Errorf("loading public key: %w", err)
132138
}

cmd/cosign/cli/verify/verify_blob_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import (
3737

3838
"github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer"
3939
"github.com/go-openapi/runtime"
40-
"github.com/go-openapi/swag"
40+
"github.com/go-openapi/swag/conv"
4141
"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
4242
"github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/mock"
4343
"github.com/sigstore/cosign/v2/internal/test"
@@ -701,9 +701,9 @@ func makeRekorEntry(t *testing.T, rekorSigner signature.ECDSASignerVerifier,
701701
}
702702
e := models.LogEntryAnon{
703703
Body: base64.StdEncoding.EncodeToString(leaf),
704-
IntegratedTime: swag.Int64(integratedTime.Unix()),
705-
LogIndex: swag.Int64(0),
706-
LogID: swag.String(logID),
704+
IntegratedTime: conv.Pointer(integratedTime.Unix()),
705+
LogIndex: conv.Pointer(int64(0)),
706+
LogID: conv.Pointer(logID),
707707
}
708708
// Marshal payload, sign, and set SET in Bundle
709709
jsonPayload, err := json.Marshal(e)
@@ -723,9 +723,9 @@ func makeRekorEntry(t *testing.T, rekorSigner signature.ECDSASignerVerifier,
723723
e.Verification = &models.LogEntryAnonVerification{
724724
SignedEntryTimestamp: bundleSig,
725725
InclusionProof: &models.InclusionProof{
726-
LogIndex: swag.Int64(0),
727-
TreeSize: swag.Int64(1),
728-
RootHash: swag.String(hex.EncodeToString(uuid)),
726+
LogIndex: conv.Pointer(int64(0)),
727+
TreeSize: conv.Pointer(int64(1)),
728+
RootHash: conv.Pointer(hex.EncodeToString(uuid)),
729729
Hashes: []string{},
730730
},
731731
}

doc/cosign_verify-attestation.md

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)