diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fb517a1..78d666ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [Unreleased] +### Changed +- Certificates signed by an issuer using an RSA key will use the same algorithm + and not default to PKCS #1. For example, if the issuer certificate uses + x509.SHA256WithRSAPSS, the signed certificate will also be signed using + x509.SHA256WithRSAPSS. + ## [0.20.0] - 2022-05-26 ### Added - Added Kubernetes auth method for Vault RAs. diff --git a/cas/softcas/softcas.go b/cas/softcas/softcas.go index 2a97145b..2c61fbae 100644 --- a/cas/softcas/softcas.go +++ b/cas/softcas/softcas.go @@ -3,6 +3,7 @@ package softcas import ( "context" "crypto" + "crypto/rsa" "crypto/x509" "time" @@ -244,6 +245,8 @@ func createCertificate(template, parent *x509.Certificate, pub crypto.PublicKey, if template.SignatureAlgorithm == 0 { if sa, ok := signer.(apiv1.SignatureAlgorithmGetter); ok { template.SignatureAlgorithm = sa.SignatureAlgorithm() + } else if _, ok := parent.PublicKey.(*rsa.PublicKey); ok { + template.SignatureAlgorithm = parent.SignatureAlgorithm } } return x509util.CreateCertificate(template, parent, pub, signer) diff --git a/cas/softcas/softcas_test.go b/cas/softcas/softcas_test.go index b4f5b440..0651ab4d 100644 --- a/cas/softcas/softcas_test.go +++ b/cas/softcas/softcas_test.go @@ -5,6 +5,7 @@ import ( "context" "crypto" "crypto/rand" + "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "fmt" @@ -350,6 +351,67 @@ func TestSoftCAS_CreateCertificate(t *testing.T) { } } +func TestSoftCAS_CreateCertificate_pss(t *testing.T) { + signer, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatal(err) + } + + now := time.Now() + template := &x509.Certificate{ + Subject: pkix.Name{CommonName: "Test Root CA"}, + KeyUsage: x509.KeyUsageCRLSign | x509.KeyUsageCertSign, + PublicKey: signer.Public(), + BasicConstraintsValid: true, + IsCA: true, + MaxPathLen: 0, + SerialNumber: big.NewInt(1234), + SignatureAlgorithm: x509.SHA256WithRSAPSS, + NotBefore: now, + NotAfter: now.Add(24 * time.Hour), + } + + iss, err := x509util.CreateCertificate(template, template, signer.Public(), signer) + if err != nil { + t.Fatal(err) + } + if iss.SignatureAlgorithm != x509.SHA256WithRSAPSS { + t.Errorf("Certificate.SignatureAlgorithm = %v, want %v", iss.SignatureAlgorithm, x509.SHA256WithRSAPSS) + } + + c := &SoftCAS{ + CertificateChain: []*x509.Certificate{iss}, + Signer: signer, + } + cert, err := c.CreateCertificate(&apiv1.CreateCertificateRequest{ + Template: &x509.Certificate{ + Subject: pkix.Name{CommonName: "test.smallstep.com"}, + DNSNames: []string{"test.smallstep.com"}, + KeyUsage: x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, + PublicKey: testSigner.Public(), + SerialNumber: big.NewInt(1234), + }, + Lifetime: time.Hour, Backdate: time.Minute, + }) + if err != nil { + t.Fatalf("SoftCAS.CreateCertificate() error = %v", err) + } + if cert.Certificate.SignatureAlgorithm != x509.SHA256WithRSAPSS { + t.Errorf("Certificate.SignatureAlgorithm = %v, want %v", iss.SignatureAlgorithm, x509.SHA256WithRSAPSS) + } + + pool := x509.NewCertPool() + pool.AddCert(iss) + if _, err = cert.Certificate.Verify(x509.VerifyOptions{ + CurrentTime: time.Now(), + Roots: pool, + KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + }); err != nil { + t.Errorf("Certificate.Verify() error = %v", err) + } +} + func TestSoftCAS_RenewCertificate(t *testing.T) { mockNow(t)