diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fb517a1..e3f9223e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ 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 be signed using the same algorithm as the issuer certificate was signed with. The signature will no longer default to PKCS #1. For example, if the issuer certificate was signed using RSA-PSS with SHA-256, a new certificate will also be signed using RSA-PSS with SHA-256. + ## [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)