Skip to content

Commit

Permalink
refactor SignerFromKeyOpts
Browse files Browse the repository at this point in the history
Signed-off-by: Jake Sanders <jsand@google.com>
  • Loading branch information
Jake Sanders committed Nov 17, 2021
1 parent 6f0fec1 commit 6680a1d
Showing 1 changed file with 109 additions and 97 deletions.
206 changes: 109 additions & 97 deletions cmd/cosign/cli/sign/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func ShouldUploadToTlog(ref name.Reference, force bool, url string) (bool, error

type Uploader func(*rekGenClient.Rekor, []byte) (*models.LogEntryAnon, error)

func UploadToTlog(ctx context.Context, sv *PKCS11SignerVerifier, rekorURL string, upload Uploader) (*oci.Bundle, error) {
func UploadToTlog(ctx context.Context, sv *SignerVerifier, rekorURL string, upload Uploader) (*oci.Bundle, error) {
var rekorBytes []byte
// Upload the cert or the public key, depending on what we have
if sv.Cert != nil {
Expand Down Expand Up @@ -213,7 +213,7 @@ func SignCmd(ctx context.Context, ko KeyOpts, regOpts options.RegistryOptions, a

func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko KeyOpts,
regOpts options.RegistryOptions, annotations map[string]interface{}, upload bool, force bool,
dd mutate.DupeDetector, sv *PKCS11SignerVerifier, se oci.SignedEntity) error {
dd mutate.DupeDetector, sv *SignerVerifier, se oci.SignedEntity) error {
var err error
// The payload can be passed to skip generation.
if len(payload) == 0 {
Expand Down Expand Up @@ -303,116 +303,114 @@ func getFulcioSigner(ctx context.Context, tok string, ko KeyOpts, fClient *fulcG
return fulcioverifier.NewSigner(ctx, tok, ko.OIDCIssuer, ko.OIDCClientID, fClient)
}

func SignerFromKeyOpts(ctx context.Context, certPath string, ko KeyOpts) (*PKCS11SignerVerifier, error) {
switch {
case ko.Sk:
sk, err := pivkey.GetKeyWithSlot(ko.Slot)
if err != nil {
return nil, err
}
sv, err := sk.SignerVerifier()
func signerFromSecurityKey(certPath, keySlot string) (*SignerVerifier, error) {
sk, err := pivkey.GetKeyWithSlot(keySlot)
if err != nil {
return nil, err
}
sv, err := sk.SignerVerifier()
if err != nil {
return nil, err
}

// Handle the -cert flag.
// With PIV, we assume the certificate is in the same slot on the PIV
// token as the private key. If it's not there, show a warning to the
// user.
certFromPIV, err := sk.Certificate()
var pemBytes []byte
if err != nil {
fmt.Fprintln(os.Stderr, "warning: no x509 certificate retrieved from the PIV token")
} else {
pemBytes, err = cryptoutils.MarshalCertificateToPEM(certFromPIV)
if err != nil {
return nil, err
}
}

return &SignerVerifier{
Cert: pemBytes,
SignerVerifier: sv,
close: sk.Close,
}, nil
}

func signerFromKeyRef(ctx context.Context, certPath, keyRef string, passFunc cosign.PassFunc) (*SignerVerifier, error) {
k, err := sigs.SignerVerifierFromKeyRef(ctx, keyRef, passFunc)
if err != nil {
return nil, errors.Wrap(err, "reading key")
}

// Handle the -cert flag.
// With PIV, we assume the certificate is in the same slot on the PIV
// token as the private key. If it's not there, show a warning to the
// user.
certFromPIV, err := sk.Certificate()
// Handle the -cert flag
// With PKCS11, we assume the certificate is in the same slot on the PKCS11
// token as the private key. If it's not there, show a warning to the
// user.
if pkcs11Key, ok := k.(*pkcs11key.Key); ok {
certFromPKCS11, _ := pkcs11Key.Certificate()
var pemBytes []byte
if err != nil {
fmt.Fprintln(os.Stderr, "warning: no x509 certificate retrieved from the PIV token")
if certFromPKCS11 == nil {
fmt.Fprintln(os.Stderr, "warning: no x509 certificate retrieved from the PKCS11 token")
} else {
pemBytes, err = cryptoutils.MarshalCertificateToPEM(certFromPIV)
pemBytes, err = cryptoutils.MarshalCertificateToPEM(certFromPKCS11)
if err != nil {
return nil, err
}
}

return &PKCS11SignerVerifier{
return &SignerVerifier{
Cert: pemBytes,
SignerVerifier: sv,
close: sk.Close,
}, nil

case ko.KeyRef != "":
k, err := sigs.SignerVerifierFromKeyRef(ctx, ko.KeyRef, ko.PassFunc)
if err != nil {
return nil, errors.Wrap(err, "reading key")
}

// Handle the -cert flag
// With PKCS11, we assume the certificate is in the same slot on the PKCS11
// token as the private key. If it's not there, show a warning to the
// user.
pkcs11Key, ok := k.(*pkcs11key.Key)
if ok {
certFromPKCS11, _ := pkcs11Key.Certificate()
var pemBytes []byte
if certFromPKCS11 == nil {
fmt.Fprintln(os.Stderr, "warning: no x509 certificate retrieved from the PKCS11 token")
} else {
pemBytes, err = cryptoutils.MarshalCertificateToPEM(certFromPKCS11)
if err != nil {
return nil, err
}
}

return &PKCS11SignerVerifier{
Cert: pemBytes,
SignerVerifier: k,
close: pkcs11Key.Close,
}, nil
}
certSigner := &PKCS11SignerVerifier{
SignerVerifier: k,
}
if certPath == "" {
return certSigner, nil
}
close: pkcs11Key.Close,
}, nil
}
certSigner := &SignerVerifier{
SignerVerifier: k,
}
if certPath == "" {
return certSigner, nil
}

certBytes, err := os.ReadFile(certPath)
if err != nil {
return nil, errors.Wrap(err, "read certificate")
}
// Handle PEM.
if bytes.HasPrefix(certBytes, []byte("-----")) {
decoded, _ := pem.Decode(certBytes)
if decoded.Type != "CERTIFICATE" {
return nil, fmt.Errorf("supplied PEM file is not a certificate: %s", certPath)
}
certBytes = decoded.Bytes
}
parsedCert, err := x509.ParseCertificate(certBytes)
if err != nil {
return nil, errors.Wrap(err, "parse x509 certificate")
}
pk, err := k.PublicKey()
if err != nil {
return nil, errors.Wrap(err, "get public key")
certBytes, err := os.ReadFile(certPath)
if err != nil {
return nil, errors.Wrap(err, "read certificate")
}
// Handle PEM.
if bytes.HasPrefix(certBytes, []byte("-----")) {
decoded, _ := pem.Decode(certBytes)
if decoded.Type != "CERTIFICATE" {
return nil, fmt.Errorf("supplied PEM file is not a certificate: %s", certPath)
}
switch kt := parsedCert.PublicKey.(type) {
case *ecdsa.PublicKey:
if !kt.Equal(pk) {
return nil, errors.New("public key in certificate does not match that in the signing key")
}
case *rsa.PublicKey:
if !kt.Equal(pk) {
return nil, errors.New("public key in certificate does not match that in the signing key")
}
default:
return nil, fmt.Errorf("unsupported key type: %T", parsedCert.PublicKey)
certBytes = decoded.Bytes
}
parsedCert, err := x509.ParseCertificate(certBytes)
if err != nil {
return nil, errors.Wrap(err, "parse x509 certificate")
}
pk, err := k.PublicKey()
if err != nil {
return nil, errors.Wrap(err, "get public key")
}
switch kt := parsedCert.PublicKey.(type) {
case *ecdsa.PublicKey:
if !kt.Equal(pk) {
return nil, errors.New("public key in certificate does not match that in the signing key")
}
pemBytes, err := cryptoutils.MarshalCertificateToPEM(parsedCert)
if err != nil {
return nil, errors.Wrap(err, "marshaling certificate to PEM")
case *rsa.PublicKey:
if !kt.Equal(pk) {
return nil, errors.New("public key in certificate does not match that in the signing key")
}
certSigner.Cert = pemBytes
return certSigner, nil
default:
return nil, fmt.Errorf("unsupported key type: %T", parsedCert.PublicKey)
}
// Default Keyless!
fmt.Fprintln(os.Stderr, "Generating ephemeral keys...")
pemBytes, err := cryptoutils.MarshalCertificateToPEM(parsedCert)
if err != nil {
return nil, errors.Wrap(err, "marshaling certificate to PEM")
}
certSigner.Cert = pemBytes
return certSigner, nil
}

func keylessSigner(ctx context.Context, certPath string, ko KeyOpts) (*SignerVerifier, error) {
fulcioServer, err := url.Parse(ko.FulcioURL)
if err != nil {
return nil, errors.Wrap(err, "parsing Fulcio URL")
Expand All @@ -431,21 +429,35 @@ func SignerFromKeyOpts(ctx context.Context, certPath string, ko KeyOpts) (*PKCS1
return nil, errors.Wrap(err, "getting key from Fulcio")
}

return &PKCS11SignerVerifier{
return &SignerVerifier{
Cert: k.Cert,
Chain: k.Chain,
SignerVerifier: k,
}, nil
}

type PKCS11SignerVerifier struct {
func SignerFromKeyOpts(ctx context.Context, certPath string, ko KeyOpts) (*SignerVerifier, error) {
if ko.Sk {
return signerFromSecurityKey(certPath, ko.Slot)
}

if ko.KeyRef != "" {
return signerFromKeyRef(ctx, certPath, ko.KeyRef, ko.PassFunc)
}

// Default Keyless!
fmt.Fprintln(os.Stderr, "Generating ephemeral keys...")
return keylessSigner(ctx, certPath, ko)
}

type SignerVerifier struct {
Cert []byte
Chain []byte
signature.SignerVerifier
close func()
}

func (c *PKCS11SignerVerifier) Close() {
func (c *SignerVerifier) Close() {
if c.close != nil {
c.close()
}
Expand Down

0 comments on commit 6680a1d

Please sign in to comment.