Skip to content
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
4 changes: 4 additions & 0 deletions cmd/cosign/cli/options/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,8 @@ type KeyOpts struct {
// By default, Ed25519ph is used for ed25519 keys and RSA-PKCS1v15 is used
// for RSA keys.
DefaultLoadOptions *[]signature.LoadOption

// SigningAlgorithm is the AlgorithmDetails string representation used to
// sign/hash the payload.
SigningAlgorithm string
}
12 changes: 12 additions & 0 deletions cmd/cosign/cli/options/signblob.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
package options

import (
"fmt"
"strings"

"github.com/sigstore/cosign/v3/pkg/cosign"
v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
"github.com/sigstore/sigstore/pkg/signature"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -43,6 +49,7 @@ type SignBlobOptions struct {
TSAServerURL string
RFC3161TimestampPath string
IssueCertificate bool
SigningAlgorithm string

UseSigningConfig bool
SigningConfigPath string
Expand Down Expand Up @@ -128,4 +135,9 @@ func (o *SignBlobOptions) AddFlags(cmd *cobra.Command) {

cmd.Flags().BoolVar(&o.IssueCertificate, "issue-certificate", false,
"issue a code signing certificate from Fulcio, even if a key is provided")

keyAlgorithmTypes := cosign.GetSupportedAlgorithms()
keyAlgorithmHelp := fmt.Sprintf("signing algorithm to use for signing/hashing (allowed %s)", strings.Join(keyAlgorithmTypes, ", "))
defaultKeyFlag, _ := signature.FormatSignatureAlgorithmFlag(v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256)
cmd.Flags().StringVar(&o.SigningAlgorithm, "signing-algorithm", defaultKeyFlag, keyAlgorithmHelp)
}
33 changes: 28 additions & 5 deletions cmd/cosign/cli/sign/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package sign
import (
"bytes"
"context"
"crypto"
"crypto/x509"
"encoding/base64"
"encoding/json"
Expand Down Expand Up @@ -58,7 +57,9 @@ import (
"github.com/sigstore/cosign/v3/pkg/oci/walk"
sigs "github.com/sigstore/cosign/v3/pkg/signature"
"github.com/sigstore/cosign/v3/pkg/types"
pb_go_v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
"github.com/sigstore/rekor/pkg/generated/models"

"github.com/sigstore/sigstore-go/pkg/sign"
"github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/sigstore/sigstore/pkg/signature"
Expand Down Expand Up @@ -687,12 +688,34 @@ func signerFromKeyRef(ctx context.Context, certPath, certChainPath, keyRef strin
return certSigner, nil
}

func signerFromNewKey() (*SignerVerifier, error) {
privKey, err := cosign.GeneratePrivateKey()
func ParseSignatureAlgorithmFlag(signingAlgorithm string) (pb_go_v1.PublicKeyDetails, error) {
if signingAlgorithm == "" {
var err error
signingAlgorithm, err = signature.FormatSignatureAlgorithmFlag(pb_go_v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256)
if err != nil {
return pb_go_v1.PublicKeyDetails_PUBLIC_KEY_DETAILS_UNSPECIFIED, fmt.Errorf("formatting signature algorithm: %w", err)
}
}
return signature.ParseSignatureAlgorithmFlag(signingAlgorithm)
}

func signerFromNewKey(signingAlgorithm string, defaultLoadOptions *[]signature.LoadOption) (*SignerVerifier, error) {
keyDetails, err := ParseSignatureAlgorithmFlag(signingAlgorithm)
if err != nil {
return nil, fmt.Errorf("parsing signature algorithm: %w", err)
}
algo, err := signature.GetAlgorithmDetails(keyDetails)
if err != nil {
return nil, fmt.Errorf("getting algorithm details: %w", err)
}

privKey, err := cosign.GeneratePrivateKeyWithAlgorithm(&algo)
if err != nil {
return nil, fmt.Errorf("generating cert: %w", err)
}
sv, err := signature.LoadECDSASignerVerifier(privKey, crypto.SHA256)

defaultLoadOptions = cosign.GetDefaultLoadOptions(defaultLoadOptions)
sv, err := signature.LoadSignerVerifierFromAlgorithmDetails(privKey, algo, *defaultLoadOptions...)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -741,7 +764,7 @@ func SignerFromKeyOpts(ctx context.Context, certPath string, certChainPath strin
default:
genKey = true
ui.Infof(ctx, "Generating ephemeral keys...")
sv, err = signerFromNewKey()
sv, err = signerFromNewKey(ko.SigningAlgorithm, ko.DefaultLoadOptions)
}
if err != nil {
return nil, false, err
Expand Down
33 changes: 23 additions & 10 deletions cmd/cosign/cli/sign/sign_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string
}
defer sv.Close()

hashFunction, err := getHashFunction(sv, ko.DefaultLoadOptions)
hashFunction, err := getHashFunction(sv, ko)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -369,18 +369,31 @@ func extractCertificate(ctx context.Context, sv *SignerVerifier) ([]byte, error)
return nil, nil
}

func getHashFunction(sv *SignerVerifier, defaultLoadOptions *[]signature.LoadOption) (crypto.Hash, error) {
pubKey, err := sv.PublicKey()
if err != nil {
return crypto.Hash(0), fmt.Errorf("error getting public key: %w", err)
}
func getHashFunction(sv *SignerVerifier, ko options.KeyOpts) (crypto.Hash, error) {
if ko.Sk || ko.KeyRef != "" {
pubKey, err := sv.PublicKey()
if err != nil {
return crypto.Hash(0), fmt.Errorf("error getting public key: %w", err)
}

defaultLoadOptions := cosign.GetDefaultLoadOptions(ko.DefaultLoadOptions)

defaultLoadOptions = cosign.GetDefaultLoadOptions(defaultLoadOptions)
// TODO: Ideally the SignerVerifier should have a method to get the hash function
algo, err := signature.GetDefaultAlgorithmDetails(pubKey, *defaultLoadOptions...)
if err != nil {
return crypto.Hash(0), fmt.Errorf("error getting default algorithm details: %w", err)
}
return algo.GetHashType(), nil
}

// TODO: Ideally the SignerVerifier should have a method to get the hash function
algo, err := signature.GetDefaultAlgorithmDetails(pubKey, *defaultLoadOptions...)
// New key was generated, using the signing algorithm specified by the user
keyDetails, err := ParseSignatureAlgorithmFlag(ko.SigningAlgorithm)
if err != nil {
return crypto.Hash(0), fmt.Errorf("parsing signature algorithm: %w", err)
}
algo, err := signature.GetAlgorithmDetails(keyDetails)
if err != nil {
return crypto.Hash(0), fmt.Errorf("error getting default algorithm details: %w", err)
return crypto.Hash(0), fmt.Errorf("getting algorithm details: %w", err)
}
return algo.GetHashType(), nil
}
Expand Down
17 changes: 17 additions & 0 deletions cmd/cosign/cli/signblob.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"context"
"fmt"
"os"
"strings"

"github.com/sigstore/cosign/v3/cmd/cosign/cli/generate"
"github.com/sigstore/cosign/v3/cmd/cosign/cli/options"
Expand Down Expand Up @@ -66,6 +67,21 @@ func SignBlob() *cobra.Command {
if options.NOf(o.Key, o.SecurityKey.Use) > 1 {
return &options.KeyParseError{}
}

// Check if the algorithm is in the list of supported algorithms
supportedAlgorithms := cosign.GetSupportedAlgorithms()
isValid := false
for _, algo := range supportedAlgorithms {
if algo == o.SigningAlgorithm {
isValid = true
break
}
}
if !isValid {
return fmt.Errorf("invalid signing algorithm: %s. Supported algorithms are: %s",
o.SigningAlgorithm, strings.Join(supportedAlgorithms, ", "))
}

return nil
},
RunE: func(_ *cobra.Command, args []string) error {
Expand Down Expand Up @@ -99,6 +115,7 @@ func SignBlob() *cobra.Command {
TSAServerURL: o.TSAServerURL,
RFC3161TimestampPath: o.RFC3161TimestampPath,
IssueCertificateForExistingKey: o.IssueCertificate,
SigningAlgorithm: o.SigningAlgorithm,
}
// If a signing config is used, then service URLs cannot be specified
if (o.UseSigningConfig || o.SigningConfigPath != "") &&
Expand Down
1 change: 1 addition & 0 deletions doc/cosign_sign-blob.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions pkg/cosign/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"fmt"
"os"
"path/filepath"
"sort"

"github.com/secure-systems-lab/go-securesystemslib/encrypted"
"github.com/sigstore/cosign/v3/pkg/oci/static"
Expand All @@ -50,6 +51,17 @@ const (
RFC3161TimestampKey = static.RFC3161TimestampAnnotationKey
)

var SupportedKeyDetails = []v1.PublicKeyDetails{
v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256,
v1.PublicKeyDetails_PKIX_ECDSA_P384_SHA_384,
v1.PublicKeyDetails_PKIX_ECDSA_P521_SHA_512,
v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_2048_SHA256,
v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_3072_SHA256,
v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_4096_SHA256,
// Ed25519ph is not supported by Fulcio, so we don't support it here for now.
// v1.PublicKeyDetails_PKIX_ED25519_PH,
}

// PassFunc is the function to be called to retrieve the signer password. If
// nil, then it assumes that no password is provided.
type PassFunc func(bool) ([]byte, error)
Expand Down Expand Up @@ -297,3 +309,17 @@ func GetDefaultLoadOptions(defaultLoadOptions *[]signature.LoadOption) *[]signat
}
return defaultLoadOptions
}

// GetSupportedAlgorithms returns a list of supported algorithms sorted alphabetically.
func GetSupportedAlgorithms() []string {
algorithms := make([]string, 0, len(SupportedKeyDetails))
for _, algorithm := range SupportedKeyDetails {
signatureFlag, err := signature.FormatSignatureAlgorithmFlag(algorithm)
if err != nil {
continue
}
algorithms = append(algorithms, signatureFlag)
}
sort.Strings(algorithms)
return algorithms
}
Loading