Sign certificates with the issuer signature algorithm

An RSA key can sign another certificates using the RSA PKCS#1
and the RSA-PSS scheme, this change will keep the signature
algorithm used in the issuer in the signed certificates instead
of using PKCS#1 by default.
This commit is contained in:
Mariano Cano 2022-06-15 19:10:58 -07:00
parent 34d141e4d5
commit 31af1efa48
3 changed files with 72 additions and 0 deletions

View file

@ -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/) 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). 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 ## [0.20.0] - 2022-05-26
### Added ### Added
- Added Kubernetes auth method for Vault RAs. - Added Kubernetes auth method for Vault RAs.

View file

@ -3,6 +3,7 @@ package softcas
import ( import (
"context" "context"
"crypto" "crypto"
"crypto/rsa"
"crypto/x509" "crypto/x509"
"time" "time"
@ -244,6 +245,8 @@ func createCertificate(template, parent *x509.Certificate, pub crypto.PublicKey,
if template.SignatureAlgorithm == 0 { if template.SignatureAlgorithm == 0 {
if sa, ok := signer.(apiv1.SignatureAlgorithmGetter); ok { if sa, ok := signer.(apiv1.SignatureAlgorithmGetter); ok {
template.SignatureAlgorithm = sa.SignatureAlgorithm() template.SignatureAlgorithm = sa.SignatureAlgorithm()
} else if _, ok := parent.PublicKey.(*rsa.PublicKey); ok {
template.SignatureAlgorithm = parent.SignatureAlgorithm
} }
} }
return x509util.CreateCertificate(template, parent, pub, signer) return x509util.CreateCertificate(template, parent, pub, signer)

View file

@ -5,6 +5,7 @@ import (
"context" "context"
"crypto" "crypto"
"crypto/rand" "crypto/rand"
"crypto/rsa"
"crypto/x509" "crypto/x509"
"crypto/x509/pkix" "crypto/x509/pkix"
"fmt" "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) { func TestSoftCAS_RenewCertificate(t *testing.T) {
mockNow(t) mockNow(t)