Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add signature algorithm to template during certificate creation #1929

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
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
7 changes: 7 additions & 0 deletions cmd/app/createca.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package app

import (
"crypto"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
Expand All @@ -29,6 +30,7 @@ import (
"time"

"github.com/ThalesIgnite/crypto11"
"github.com/sigstore/fulcio/pkg/ca"
"github.com/sigstore/fulcio/pkg/log"
"github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -126,6 +128,11 @@ func runCreateCACmd(cmd *cobra.Command, args []string) { //nolint: revive
BasicConstraintsValid: true, MaxPathLen: 1,
}

rootCA.SignatureAlgorithm, err = ca.ToSignatureAlgorithm(privKey, crypto.SHA256)
if err != nil {
log.Logger.Fatal(err)
}

caBytes, err := x509.CreateCertificate(rand.Reader, rootCA, rootCA, pubKey, privKey)
if err != nil {
log.Logger.Fatal(err)
Expand Down
16 changes: 16 additions & 0 deletions pkg/ca/baseca/baseca.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ func (bca *BaseCA) CreatePrecertificate(ctx context.Context, principal identity.
Value: asn1.NullBytes,
})

cert.SignatureAlgorithm, err = ca.ToSignatureAlgorithm(privateKey, crypto.SHA256)
if err != nil {
return nil, err
}

finalCertBytes, err := x509.CreateCertificate(rand.Reader, cert, certChain[0], publicKey, privateKey)
if err != nil {
return nil, err
Expand Down Expand Up @@ -115,6 +120,12 @@ func (bca *BaseCA) IssueFinalCertificate(_ context.Context, precert *ca.CodeSign

cert := precert.PreCert
cert.ExtraExtensions = exts

cert.SignatureAlgorithm, err = ca.ToSignatureAlgorithm(precert.PrivateKey, crypto.SHA256)
if err != nil {
return nil, err
}

finalCertBytes, err := x509.CreateCertificate(rand.Reader, cert, precert.CertChain[0], precert.PreCert.PublicKey, precert.PrivateKey)
if err != nil {
return nil, err
Expand All @@ -131,6 +142,11 @@ func (bca *BaseCA) CreateCertificate(ctx context.Context, principal identity.Pri

certChain, privateKey := bca.GetSignerWithChain()

cert.SignatureAlgorithm, err = ca.ToSignatureAlgorithm(privateKey, crypto.SHA256)
if err != nil {
return nil, err
}

finalCertBytes, err := x509.CreateCertificate(rand.Reader, cert, certChain[0], publicKey, privateKey)
if err != nil {
return nil, err
Expand Down
48 changes: 48 additions & 0 deletions pkg/ca/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ package ca
import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
"crypto/x509"
"errors"
"fmt"
"time"

"github.com/sigstore/fulcio/pkg/identity"
Expand Down Expand Up @@ -105,3 +109,47 @@ func VerifyCertChain(certs []*x509.Certificate, signer crypto.Signer) error {

return cryptoutils.ValidatePubKey(signer.Public())
}

// ToSignatureAlgorithm returns the x509.SignatureAlgorithm for the given signer and hash algorithm.
func ToSignatureAlgorithm(signer crypto.Signer, hash crypto.Hash) (x509.SignatureAlgorithm, error) {
if signer == nil {
return x509.UnknownSignatureAlgorithm, errors.New("signer is nil")
}

pub := signer.Public()
switch pub := pub.(type) {
case *rsa.PublicKey:
switch hash {
case crypto.SHA256:
return x509.SHA256WithRSA, nil
case crypto.SHA384:
return x509.SHA384WithRSA, nil
case crypto.SHA512:
return x509.SHA512WithRSA, nil
case crypto.SHA1:
return x509.SHA1WithRSA, nil
case crypto.MD5:
return x509.MD5WithRSA, nil
default:
return x509.UnknownSignatureAlgorithm, fmt.Errorf("unsupported hash algorithm for RSA: %v", hash)
}
case *ecdsa.PublicKey:
switch hash {
case crypto.SHA256:
return x509.ECDSAWithSHA256, nil
case crypto.SHA384:
return x509.ECDSAWithSHA384, nil
case crypto.SHA512:
return x509.ECDSAWithSHA512, nil
case crypto.SHA1:
return x509.ECDSAWithSHA1, nil
default:
return x509.UnknownSignatureAlgorithm, fmt.Errorf("unsupported hash algorithm for ECDSA: %v", hash)
}
case ed25519.PublicKey:
// Ed25519 has a fixed signature so we don't need to check the hash
return x509.PureEd25519, nil
default:
return x509.UnknownSignatureAlgorithm, fmt.Errorf("unsupported public key type: %T", pub)
}
}
143 changes: 143 additions & 0 deletions pkg/ca/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ package ca

import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"strings"
"testing"
Expand Down Expand Up @@ -137,3 +140,143 @@ func TestVerifyCertChain(t *testing.T) {
t.Fatalf("expected error verifying with empty chain: %v", err)
}
}

func TestToSignatureAlgorithm(t *testing.T) {
rsaKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
t.Fatalf("Failed to generate RSA key: %v", err)
}

ecdsaKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatalf("Failed to generate ECDSA key: %v", err)
}

_, ed25519Key, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
t.Fatalf("Failed to generate Ed25519 key: %v", err)
}

tests := []struct {
name string
signer crypto.Signer
hash crypto.Hash
want x509.SignatureAlgorithm
wantErr bool
}{
{
name: "RSA with SHA256",
signer: rsaKey,
hash: crypto.SHA256,
want: x509.SHA256WithRSA,
wantErr: false,
},
{
name: "RSA with SHA384",
signer: rsaKey,
hash: crypto.SHA384,
want: x509.SHA384WithRSA,
wantErr: false,
},
{
name: "RSA with SHA512",
signer: rsaKey,
hash: crypto.SHA512,
want: x509.SHA512WithRSA,
wantErr: false,
},
{
name: "RSA with SHA1",
signer: rsaKey,
hash: crypto.SHA1,
want: x509.SHA1WithRSA,
wantErr: false,
},
{
name: "RSA with MD5",
signer: rsaKey,
hash: crypto.MD5,
want: x509.MD5WithRSA,
wantErr: false,
},
{
name: "RSA with unsupported hash",
signer: rsaKey,
hash: crypto.MD4,
want: x509.UnknownSignatureAlgorithm,
wantErr: true,
},

{
name: "ECDSA with SHA256",
signer: ecdsaKey,
hash: crypto.SHA256,
want: x509.ECDSAWithSHA256,
wantErr: false,
},
{
name: "ECDSA with SHA384",
signer: ecdsaKey,
hash: crypto.SHA384,
want: x509.ECDSAWithSHA384,
wantErr: false,
},
{
name: "ECDSA with SHA512",
signer: ecdsaKey,
hash: crypto.SHA512,
want: x509.ECDSAWithSHA512,
wantErr: false,
},
{
name: "ECDSA with SHA1",
signer: ecdsaKey,
hash: crypto.SHA1,
want: x509.ECDSAWithSHA1,
wantErr: false,
},
{
name: "ECDSA with unsupported hash",
signer: ecdsaKey,
hash: crypto.MD5,
want: x509.UnknownSignatureAlgorithm,
wantErr: true,
},

{
name: "Ed25519 with any hash",
signer: ed25519Key,
hash: crypto.SHA256,
want: x509.PureEd25519,
wantErr: false,
},
{
name: "Ed25519 with different hash",
signer: ed25519Key,
hash: crypto.SHA512,
want: x509.PureEd25519,
wantErr: false,
},

{
name: "nil signer",
signer: nil,
hash: crypto.SHA256,
want: x509.UnknownSignatureAlgorithm,
wantErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ToSignatureAlgorithm(tt.signer, tt.hash)
if (err != nil) != tt.wantErr {
t.Errorf("ToSignatureAlgorithm() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("ToSignatureAlgorithm() = %v, want %v", got, tt.want)
}
})
}
}
6 changes: 6 additions & 0 deletions pkg/ca/ephemeralca/ephemeral.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package ephemeralca

import (
"crypto"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
Expand Down Expand Up @@ -61,6 +62,11 @@ func NewEphemeralCA() (*EphemeralCA, error) {
BasicConstraintsValid: true, MaxPathLen: 1,
}

rootCA.SignatureAlgorithm, err = ca.ToSignatureAlgorithm(signer, crypto.SHA256)
if err != nil {
return nil, err
}

caBytes, err := x509.CreateCertificate(rand.Reader, rootCA, rootCA, signer.Public(), signer)
if err != nil {
return nil, err
Expand Down
16 changes: 16 additions & 0 deletions pkg/certmaker/certmaker.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"strings"
"time"

"github.com/sigstore/fulcio/pkg/ca"
"github.com/sigstore/sigstore/pkg/signature"
"github.com/sigstore/sigstore/pkg/signature/kms"
"go.step.sm/crypto/x509util"
Expand Down Expand Up @@ -188,6 +189,11 @@ func CreateCertificates(sv signature.SignerVerifier, config KMSConfig,
return fmt.Errorf("error parsing root template: %w", err)
}

rootTmpl.SignatureAlgorithm, err = ca.ToSignatureAlgorithm(rootSigner, crypto.SHA256)
if err != nil {
return fmt.Errorf("error determining signature algorithm: %w", err)
}

rootCert, err := x509util.CreateCertificate(rootTmpl, rootTmpl, rootPubKey, rootSigner)
if err != nil {
return fmt.Errorf("error creating root certificate: %w", err)
Expand Down Expand Up @@ -246,6 +252,11 @@ func CreateCertificates(sv signature.SignerVerifier, config KMSConfig,
return fmt.Errorf("error parsing intermediate template: %w", err)
}

intermediateTmpl.SignatureAlgorithm, err = ca.ToSignatureAlgorithm(intermediateSigner, crypto.SHA256)
if err != nil {
return fmt.Errorf("error determining signature algorithm: %w", err)
}

intermediateCert, err := x509util.CreateCertificate(intermediateTmpl, rootCert, intermediatePubKey, rootSigner)
if err != nil {
return fmt.Errorf("error creating intermediate certificate: %w", err)
Expand Down Expand Up @@ -307,6 +318,11 @@ func CreateCertificates(sv signature.SignerVerifier, config KMSConfig,
return fmt.Errorf("error parsing leaf template: %w", err)
}

leafTmpl.SignatureAlgorithm, err = ca.ToSignatureAlgorithm(signingKey, crypto.SHA256)
if err != nil {
return fmt.Errorf("error determining signature algorithm: %w", err)
}

leafCert, err := x509util.CreateCertificate(leafTmpl, signingCert, leafPubKey, signingKey)
if err != nil {
return fmt.Errorf("error creating leaf certificate: %w", err)
Expand Down
Loading