Skip to content
Draft
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
6 changes: 5 additions & 1 deletion cmd/cosign/cli/attest/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import (
"github.com/sigstore/rekor/pkg/generated/client"
"github.com/sigstore/rekor/pkg/generated/models"
"github.com/sigstore/sigstore-go/pkg/sign"
"github.com/sigstore/sigstore/pkg/signature"
"github.com/sigstore/sigstore/pkg/signature/dsse"
signatureoptions "github.com/sigstore/sigstore/pkg/signature/options"
)
Expand Down Expand Up @@ -164,11 +165,14 @@ func (c *AttestCommand) Exec(ctx context.Context, imageRef string) error {
var err error

if c.Sk || c.Slot != "" || c.KeyRef != "" || c.CertPath != "" {
// Set no load options so that Ed25519 is preferred over Ed25519ph, required for signing DSSEs
var signOpts []signature.LoadOption
c.KeyOpts.DefaultLoadOptions = &signOpts
sv, _, err = cosign_sign.SignerFromKeyOpts(ctx, c.CertPath, c.CertChainPath, c.KeyOpts)
if err != nil {
return fmt.Errorf("getting signer: %w", err)
}
keypair, err = key.NewSignerVerifierKeypair(sv, c.DefaultLoadOptions)
keypair, err = key.NewSignerVerifierKeypair(sv, &signOpts)
if err != nil {
return fmt.Errorf("creating signerverifier keypair: %w", err)
}
Expand Down
5 changes: 4 additions & 1 deletion cmd/cosign/cli/attest/attest_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,14 @@ func (c *AttestBlobCommand) Exec(ctx context.Context, artifactPath string) error
var err error

if c.Sk || c.Slot != "" || c.KeyRef != "" || c.CertPath != "" {
// Set no load options so that Ed25519 is preferred over Ed25519ph, required for signing DSSEs
var signOpts []signature.LoadOption
c.KeyOpts.DefaultLoadOptions = &signOpts
sv, _, err = cosign_sign.SignerFromKeyOpts(ctx, c.CertPath, c.CertChainPath, c.KeyOpts)
if err != nil {
return fmt.Errorf("getting signer: %w", err)
}
keypair, err = key.NewSignerVerifierKeypair(sv, c.DefaultLoadOptions)
keypair, err = key.NewSignerVerifierKeypair(sv, &signOpts)
if err != nil {
return fmt.Errorf("creating signerverifier keypair: %w", err)
}
Expand Down
5 changes: 4 additions & 1 deletion cmd/cosign/cli/sign/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,14 @@ func signDigestBundle(ctx context.Context, digest name.Digest, ko options.KeyOpt
var err error

if ko.Sk || ko.Slot != "" || ko.KeyRef != "" || signOpts.Cert != "" {
// Set no load options so that Ed25519 is preferred over Ed25519ph, required for signing DSSEs
var signLoadOpts []signature.LoadOption
ko.DefaultLoadOptions = &signLoadOpts
sv, _, err = SignerFromKeyOpts(ctx, signOpts.Cert, signOpts.CertChain, ko)
if err != nil {
return fmt.Errorf("getting signer: %w", err)
}
keypair, err = key.NewSignerVerifierKeypair(sv, ko.DefaultLoadOptions)
keypair, err = key.NewSignerVerifierKeypair(sv, &signLoadOpts)
if err != nil {
return fmt.Errorf("creating signerverifier keypair: %w", err)
}
Expand Down
1 change: 1 addition & 0 deletions cmd/cosign/cli/sign/sign_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string
var err error

if ko.Sk || ko.Slot != "" || ko.KeyRef != "" {
// Default load options prefer Ed25519ph over Ed25519, required for blobs with hashedrekord
sv, _, err = SignerFromKeyOpts(ctx, "", "", ko)
if err != nil {
return nil, fmt.Errorf("getting signer: %w", err)
Expand Down
4 changes: 3 additions & 1 deletion cmd/cosign/cli/verify/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,9 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
var pubKey signature.Verifier
switch {
case keyRef != "":
pubKey, err = sigs.PublicKeyFromKeyRefWithHashAlgo(ctx, keyRef, c.HashAlgorithm)
// Set no load options so that Ed25519 is preferred over Ed25519ph, required for verifying DSSEs
var signOpts []signature.LoadOption
pubKey, err = sigs.PublicKeyFromKeyRefWithHashAlgo(ctx, keyRef, c.HashAlgorithm, &signOpts)
if err != nil {
return fmt.Errorf("loading public key: %w", err)
}
Expand Down
5 changes: 4 additions & 1 deletion cmd/cosign/cli/verify/verify_attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (
"github.com/sigstore/cosign/v2/pkg/policy"
sigs "github.com/sigstore/cosign/v2/pkg/signature"
"github.com/sigstore/sigstore-go/pkg/root"
"github.com/sigstore/sigstore/pkg/signature"
)

// VerifyAttestationCommand verifies a signature on a supplied container image
Expand Down Expand Up @@ -210,7 +211,9 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e
// Keys are optional!
switch {
case keyRef != "":
co.SigVerifier, err = sigs.PublicKeyFromKeyRefWithHashAlgo(ctx, keyRef, c.HashAlgorithm)
// Set no load options so that Ed25519 is preferred over Ed25519ph, required for verifying DSSEs
var signOpts []signature.LoadOption
co.SigVerifier, err = sigs.PublicKeyFromKeyRefWithHashAlgo(ctx, keyRef, c.HashAlgorithm, &signOpts)
if err != nil {
return fmt.Errorf("loading public key: %w", err)
}
Expand Down
12 changes: 10 additions & 2 deletions cmd/cosign/cli/verify/verify_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
sgverify "github.com/sigstore/sigstore-go/pkg/verify"

"github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/sigstore/sigstore/pkg/signature"
)

func isb64(data []byte) bool {
Expand Down Expand Up @@ -117,12 +118,19 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error {
NewBundleFormat: c.KeyOpts.NewBundleFormat && checkNewBundle(c.BundlePath),
}

if !c.IgnoreTlog {
// To maintain backwards compatibility with older cosign versions,
// we do not use ed25519ph for ed25519 keys when the signatures are not
// uploaded to the Tlog.
c.DefaultLoadOptions = &[]signature.LoadOption{}
}

// Keys are optional!
var cert *x509.Certificate
opts := make([]static.Option, 0)
switch {
case c.KeyRef != "":
co.SigVerifier, err = sigs.PublicKeyFromKeyRefWithHashAlgo(ctx, c.KeyRef, c.HashAlgorithm)
co.SigVerifier, err = sigs.PublicKeyFromKeyRefWithHashAlgo(ctx, c.KeyRef, c.HashAlgorithm, c.DefaultLoadOptions)
if err != nil {
return fmt.Errorf("loading public key: %w", err)
}
Expand Down Expand Up @@ -265,7 +273,7 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error {
bundleCert, err := loadCertFromPEM(certBytes)
if err != nil {
// check if cert is actually a public key
co.SigVerifier, err = sigs.LoadPublicKeyRaw(certBytes, crypto.SHA256)
co.SigVerifier, err = sigs.LoadPublicKeyRaw(certBytes, crypto.SHA256, c.DefaultLoadOptions)
if err != nil {
return fmt.Errorf("loading verifier from bundle: %w", err)
}
Expand Down
9 changes: 7 additions & 2 deletions cmd/cosign/cli/verify/verify_blob_attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
"github.com/sigstore/sigstore-go/pkg/root"
sgverify "github.com/sigstore/sigstore-go/pkg/verify"
"github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/sigstore/sigstore/pkg/signature"
)

// VerifyBlobAttestationCommand verifies an attestation on a supplied blob
Expand Down Expand Up @@ -127,12 +128,16 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st
NewBundleFormat: c.NewBundleFormat && checkNewBundle(c.BundlePath),
}

// Set no load options so that Ed25519 is preferred over Ed25519ph, required for verifying DSSEs
var signOpts []signature.LoadOption
c.DefaultLoadOptions = &signOpts

// Keys are optional!
var cert *x509.Certificate
opts := make([]static.Option, 0)
switch {
case c.KeyRef != "":
co.SigVerifier, err = sigs.PublicKeyFromKeyRefWithHashAlgo(ctx, c.KeyRef, c.HashAlgorithm)
co.SigVerifier, err = sigs.PublicKeyFromKeyRefWithHashAlgo(ctx, c.KeyRef, c.HashAlgorithm, c.DefaultLoadOptions)
if err != nil {
return fmt.Errorf("loading public key: %w", err)
}
Expand Down Expand Up @@ -329,7 +334,7 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st
bundleCert, err := loadCertFromPEM(certBytes)
if err != nil {
// check if cert is actually a public key
co.SigVerifier, err = sigs.LoadPublicKeyRaw(certBytes, crypto.SHA256)
co.SigVerifier, err = sigs.LoadPublicKeyRaw(certBytes, crypto.SHA256, c.DefaultLoadOptions)
if err != nil {
return fmt.Errorf("loading verifier from bundle: %w", err)
}
Expand Down
17 changes: 12 additions & 5 deletions internal/key/svkeypair.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,20 @@ func (k *SignerVerifierKeypair) GetPublicKeyPem() (string, error) {

// SignData signs the given data with the SignerVerifier.
func (k *SignerVerifierKeypair) SignData(ctx context.Context, data []byte) ([]byte, []byte, error) {
h := k.sigAlg.GetHashType().New()
h.Write(data)
digest := h.Sum(nil)
sOpts := []signature.SignOption{signatureoptions.WithContext(ctx), signatureoptions.WithDigest(digest)}
sOpts := []signature.SignOption{signatureoptions.WithContext(ctx)}

hf := k.sigAlg.GetHashType()
dataToSign := data
// RSA, ECDSA, and Ed25519ph sign a digest, while pure Ed25519's interface takes data and hashes during signing
if hf != crypto.Hash(0) {
hasher := hf.New()
hasher.Write(data)
dataToSign = hasher.Sum(nil)
sOpts = append(sOpts, signatureoptions.WithDigest(dataToSign))
}
sig, err := k.sv.SignMessage(bytes.NewReader(data), sOpts...)
if err != nil {
return nil, nil, err
}
return sig, digest, nil
return sig, dataToSign, nil
}
23 changes: 21 additions & 2 deletions internal/key/svkeypair_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
protocommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
"github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/sigstore/sigstore/pkg/signature"
"github.com/sigstore/sigstore/pkg/signature/options"
)

// mockSignerVerifier is a mock implementation of signature.SignerVerifier for testing.
Expand Down Expand Up @@ -61,7 +62,7 @@ func (m *mockSignerVerifier) VerifySignature(_, _ io.Reader, _ ...signature.Veri
return errors.New("not implemented")
}

func TestNewKMSKeypair(t *testing.T) {
func TestNewSignerVerifierKeypair(t *testing.T) {
ecdsaPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatalf("failed to generate ecdsa key: %v", err)
Expand All @@ -78,6 +79,7 @@ func TestNewKMSKeypair(t *testing.T) {
testCases := []struct {
name string
sv signature.SignerVerifier
prehash bool
expectErr bool
errMsg string
}{
Expand All @@ -102,6 +104,14 @@ func TestNewKMSKeypair(t *testing.T) {
},
expectErr: false,
},
{
name: "ED25519ph key",
sv: &mockSignerVerifier{
pubKey: ed25519Priv.Public(),
},
prehash: true,
expectErr: false,
},
{
name: "Unsupported key type",
sv: &mockSignerVerifier{
Expand All @@ -122,7 +132,11 @@ func TestNewKMSKeypair(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
kp, err := NewSignerVerifierKeypair(tc.sv, nil)
var loadOpts []signature.LoadOption
if tc.prehash {
loadOpts = []signature.LoadOption{options.WithED25519ph()}
}
kp, err := NewSignerVerifierKeypair(tc.sv, &loadOpts)
if tc.expectErr {
if err == nil {
t.Errorf("expected an error, but got none")
Expand All @@ -137,6 +151,11 @@ func TestNewKMSKeypair(t *testing.T) {
t.Error("expected a keypair, but got nil")
}
}
if !tc.expectErr {
if _, _, err := kp.SignData(context.Background(), []byte("data")); err != nil {
t.Errorf("unexpected error: %v", err)
}
}
})
}
}
Expand Down
7 changes: 6 additions & 1 deletion pkg/cosign/bundle/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/sigstore/sigstore-go/pkg/root"
"github.com/sigstore/sigstore-go/pkg/sign"
"github.com/sigstore/sigstore/pkg/signature"
"github.com/sigstore/sigstore/pkg/signature/options"
"google.golang.org/protobuf/encoding/protojson"
)

Expand Down Expand Up @@ -63,7 +64,11 @@ func SignData(ctx context.Context, content sign.Content, keypair sign.Keypair, i
if err != nil {
log.Fatal(err)
}
verifier, err := signature.LoadDefaultVerifier(pubKey)
var verifierOpts []signature.LoadOption
if _, ok := content.(*sign.PlainData); ok {
verifierOpts = append(verifierOpts, options.WithED25519ph())
}
verifier, err := signature.LoadDefaultVerifier(pubKey, verifierOpts...)
if err != nil {
log.Fatal(err)
}
Expand Down
25 changes: 15 additions & 10 deletions pkg/signature/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,17 @@ import (
"github.com/sigstore/sigstore/pkg/signature"

"github.com/sigstore/sigstore/pkg/signature/kms"
"github.com/sigstore/sigstore/pkg/signature/options"
)

// LoadPublicKey is a wrapper for VerifierForKeyRef, hardcoding SHA256 as the hash algorithm
func LoadPublicKey(ctx context.Context, keyRef string) (verifier signature.Verifier, err error) {
return VerifierForKeyRef(ctx, keyRef, crypto.SHA256)
return VerifierForKeyRef(ctx, keyRef, crypto.SHA256, nil)
}

// VerifierForKeyRef parses the given keyRef, loads the key and returns an appropriate
// verifier using the provided hash algorithm
func VerifierForKeyRef(ctx context.Context, keyRef string, hashAlgorithm crypto.Hash) (verifier signature.Verifier, err error) {
func VerifierForKeyRef(ctx context.Context, keyRef string, hashAlgorithm crypto.Hash, defaultLoadOptions *[]signature.LoadOption) (verifier signature.Verifier, err error) {
// The key could be plaintext, in a file, at a URL, or in KMS.
var perr *kms.ProviderNotFoundError
kmsKey, err := kms.Get(ctx, keyRef, hashAlgorithm)
Expand Down Expand Up @@ -69,7 +70,9 @@ func VerifierForKeyRef(ctx context.Context, keyRef string, hashAlgorithm crypto.
return nil, fmt.Errorf("pem to public key: %w", err)
}

return signature.LoadVerifier(pubKey, hashAlgorithm)
opts := *cosign.GetDefaultLoadOptions(defaultLoadOptions)
opts = append(opts, options.WithHash(hashAlgorithm))
return signature.LoadVerifierWithOpts(pubKey, opts...)
}

func loadKey(keyPath string, pf cosign.PassFunc, defaultLoadOptions *[]signature.LoadOption) (signature.SignerVerifier, error) {
Expand All @@ -88,12 +91,14 @@ func loadKey(keyPath string, pf cosign.PassFunc, defaultLoadOptions *[]signature
}

// LoadPublicKeyRaw loads a verifier from a PEM-encoded public key
func LoadPublicKeyRaw(raw []byte, hashAlgorithm crypto.Hash) (signature.Verifier, error) {
func LoadPublicKeyRaw(raw []byte, hashAlgorithm crypto.Hash, defaultLoadOptions *[]signature.LoadOption) (signature.Verifier, error) {
pub, err := cryptoutils.UnmarshalPEMToPublicKey(raw)
if err != nil {
return nil, err
}
return signature.LoadVerifier(pub, hashAlgorithm)
opts := *cosign.GetDefaultLoadOptions(defaultLoadOptions)
opts = append(opts, options.WithHash(hashAlgorithm))
return signature.LoadVerifierWithOpts(pub, opts...)
}

func SignerFromKeyRef(ctx context.Context, keyRef string, pf cosign.PassFunc) (signature.Signer, error) {
Expand Down Expand Up @@ -169,18 +174,18 @@ func SignerVerifierFromKeyRef(ctx context.Context, keyRef string, pf cosign.Pass
}

func PublicKeyFromKeyRef(ctx context.Context, keyRef string) (signature.Verifier, error) {
return PublicKeyFromKeyRefWithHashAlgo(ctx, keyRef, crypto.SHA256)
return PublicKeyFromKeyRefWithHashAlgo(ctx, keyRef, crypto.SHA256, nil)
}

func PublicKeyFromKeyRefWithHashAlgo(ctx context.Context, keyRef string, hashAlgorithm crypto.Hash) (signature.Verifier, error) {
func PublicKeyFromKeyRefWithHashAlgo(ctx context.Context, keyRef string, hashAlgorithm crypto.Hash, defaultLoadOptions *[]signature.LoadOption) (signature.Verifier, error) {
if strings.HasPrefix(keyRef, kubernetes.KeyReference) {
s, err := kubernetes.GetKeyPairSecret(ctx, keyRef)
if err != nil {
return nil, err
}

if len(s.Data) > 0 {
return LoadPublicKeyRaw(s.Data["cosign.pub"], hashAlgorithm)
return LoadPublicKeyRaw(s.Data["cosign.pub"], hashAlgorithm, defaultLoadOptions)
}
}

Expand Down Expand Up @@ -219,11 +224,11 @@ func PublicKeyFromKeyRefWithHashAlgo(ctx context.Context, keyRef string, hashAlg
}

if len(pubKey) > 0 {
return LoadPublicKeyRaw([]byte(pubKey), hashAlgorithm)
return LoadPublicKeyRaw([]byte(pubKey), hashAlgorithm, defaultLoadOptions)
}
}

return VerifierForKeyRef(ctx, keyRef, hashAlgorithm)
return VerifierForKeyRef(ctx, keyRef, hashAlgorithm, defaultLoadOptions)
}

func PublicKeyPem(key signature.PublicKeyProvider, pkOpts ...signature.PublicKeyOption) ([]byte, error) {
Expand Down
Loading
Loading