2020-09-16 02:37:02 +00:00
package softcas
import (
"bytes"
"context"
"crypto"
2022-08-30 23:49:56 +00:00
"crypto/ecdsa"
"crypto/elliptic"
2020-09-16 02:37:02 +00:00
"crypto/rand"
2022-06-16 02:10:58 +00:00
"crypto/rsa"
2020-09-16 02:37:02 +00:00
"crypto/x509"
"crypto/x509/pkix"
2020-10-28 01:45:49 +00:00
"fmt"
2020-09-16 02:37:02 +00:00
"io"
"math/big"
"reflect"
"testing"
"time"
2020-10-28 01:45:49 +00:00
"github.com/pkg/errors"
"github.com/smallstep/certificates/cas/apiv1"
2022-08-09 00:58:18 +00:00
"go.step.sm/crypto/kms"
kmsapi "go.step.sm/crypto/kms/apiv1"
2020-09-16 02:37:02 +00:00
"go.step.sm/crypto/pemutil"
"go.step.sm/crypto/x509util"
)
var (
testIntermediatePem = ` -- -- - BEGIN CERTIFICATE -- -- -
MIIBPjCB8aADAgECAhAk4aPIlsVvQg3gveApc3mIMAUGAytlcDAeMRwwGgYDVQQD
ExNTbWFsbHN0ZXAgVW5pdCBUZXN0MB4XDTIwMDkxNjAyMDgwMloXDTMwMDkxNDAy
MDgwMlowHjEcMBoGA1UEAxMTU21hbGxzdGVwIFVuaXQgVGVzdDAqMAUGAytlcAMh
ANLs3JCzECR29biut0NDsaLnh0BGij5eJx6VkdJPfS / ko0UwQzAOBgNVHQ8BAf8E
BAMCAQYwEgYDVR0TAQH / BAgwBgEB / wIBATAdBgNVHQ4EFgQUup5qpZFMAFdgK7RB
xNzmUaQM8YwwBQYDK2VwA0EAAwcW25E / 6 bchyKwp3RRK1GXiPMDCc + hsTJxuOLWy
YM7ga829dU8X4pRcEEAcBndqCED / 502 excjEK7U9vCkFCg ==
-- -- - END CERTIFICATE -- -- - `
testIntermediateKeyPem = ` -- -- - BEGIN PRIVATE KEY -- -- -
MC4CAQAwBQYDK2VwBCIEII9ZckcrDKlbhZKR0jp820Uz6mOMLFsq2JhI + Tl7WJwH
-- -- - END PRIVATE KEY -- -- - `
)
var (
2020-10-28 01:45:49 +00:00
errTest = errors . New ( "test error" )
2020-09-16 02:37:02 +00:00
testIssuer = mustIssuer ( )
testSigner = mustSigner ( )
testTemplate = & x509 . Certificate {
Subject : pkix . Name { CommonName : "test.smallstep.com" } ,
DNSNames : [ ] string { "test.smallstep.com" } ,
KeyUsage : x509 . KeyUsageDigitalSignature ,
ExtKeyUsage : [ ] x509 . ExtKeyUsage { x509 . ExtKeyUsageServerAuth , x509 . ExtKeyUsageClientAuth } ,
2020-10-28 01:45:49 +00:00
PublicKey : testSigner . Public ( ) ,
2020-09-16 02:37:02 +00:00
SerialNumber : big . NewInt ( 1234 ) ,
}
2020-10-28 01:45:49 +00:00
testRootTemplate = & x509 . Certificate {
Subject : pkix . Name { CommonName : "Test Root CA" } ,
KeyUsage : x509 . KeyUsageCRLSign | x509 . KeyUsageCertSign ,
PublicKey : testSigner . Public ( ) ,
BasicConstraintsValid : true ,
IsCA : true ,
MaxPathLen : 1 ,
SerialNumber : big . NewInt ( 1234 ) ,
}
testIntermediateTemplate = & x509 . Certificate {
Subject : pkix . Name { CommonName : "Test Intermediate CA" } ,
KeyUsage : x509 . KeyUsageCRLSign | x509 . KeyUsageCertSign ,
PublicKey : testSigner . Public ( ) ,
BasicConstraintsValid : true ,
IsCA : true ,
MaxPathLen : 0 ,
MaxPathLenZero : true ,
SerialNumber : big . NewInt ( 1234 ) ,
}
testNow = time . Now ( )
testSignedTemplate = mustSign ( testTemplate , testIssuer , testNow , testNow . Add ( 24 * time . Hour ) )
testSignedRootTemplate = mustSign ( testRootTemplate , testRootTemplate , testNow , testNow . Add ( 24 * time . Hour ) )
testSignedIntermediateTemplate = mustSign ( testIntermediateTemplate , testSignedRootTemplate , testNow , testNow . Add ( 24 * time . Hour ) )
2022-03-29 00:54:35 +00:00
testCertificateSigner = func ( ) ( [ ] * x509 . Certificate , crypto . Signer , error ) {
return [ ] * x509 . Certificate { testIssuer } , testSigner , nil
}
testFailCertificateSigner = func ( ) ( [ ] * x509 . Certificate , crypto . Signer , error ) {
return nil , nil , errTest
}
2020-09-16 02:37:02 +00:00
)
2021-09-08 22:33:34 +00:00
type signatureAlgorithmSigner struct {
crypto . Signer
algorithm x509 . SignatureAlgorithm
}
func ( s * signatureAlgorithmSigner ) SignatureAlgorithm ( ) x509 . SignatureAlgorithm {
return s . algorithm
}
2020-10-28 01:45:49 +00:00
type mockKeyManager struct {
signer crypto . Signer
errGetPublicKey error
errCreateKey error
errCreatesigner error
errClose error
}
2023-05-10 06:47:28 +00:00
func ( m * mockKeyManager ) GetPublicKey ( * kmsapi . GetPublicKeyRequest ) ( crypto . PublicKey , error ) {
2020-10-28 01:45:49 +00:00
signer := testSigner
if m . signer != nil {
signer = m . signer
}
return signer . Public ( ) , m . errGetPublicKey
}
func ( m * mockKeyManager ) CreateKey ( req * kmsapi . CreateKeyRequest ) ( * kmsapi . CreateKeyResponse , error ) {
signer := testSigner
if m . signer != nil {
signer = m . signer
}
return & kmsapi . CreateKeyResponse {
2021-10-07 21:19:39 +00:00
Name : req . Name ,
2020-10-28 01:45:49 +00:00
PrivateKey : signer ,
PublicKey : signer . Public ( ) ,
} , m . errCreateKey
}
2023-05-10 06:47:28 +00:00
func ( m * mockKeyManager ) CreateSigner ( * kmsapi . CreateSignerRequest ) ( crypto . Signer , error ) {
2020-10-28 01:45:49 +00:00
signer := testSigner
if m . signer != nil {
signer = m . signer
}
return signer , m . errCreatesigner
}
2023-05-10 06:47:28 +00:00
func ( m * mockKeyManager ) CreateDecrypter ( * kmsapi . CreateDecrypterRequest ) ( crypto . Decrypter , error ) {
2021-02-25 23:32:21 +00:00
return nil , nil
}
2020-10-28 01:45:49 +00:00
func ( m * mockKeyManager ) Close ( ) error {
return m . errClose
}
type badSigner struct { }
func ( b * badSigner ) Public ( ) crypto . PublicKey {
return testSigner . Public ( )
}
2021-10-08 18:59:57 +00:00
func ( b * badSigner ) Sign ( _ io . Reader , _ [ ] byte , _ crypto . SignerOpts ) ( [ ] byte , error ) {
2020-10-28 01:45:49 +00:00
return nil , fmt . Errorf ( "💥" )
}
2023-05-10 06:47:28 +00:00
//nolint:gocritic // ignore sloppy test func name
2020-09-16 02:37:02 +00:00
func mockNow ( t * testing . T ) {
tmp := now
now = func ( ) time . Time {
return testNow
}
t . Cleanup ( func ( ) {
now = tmp
} )
}
func mustIssuer ( ) * x509 . Certificate {
v , err := pemutil . Parse ( [ ] byte ( testIntermediatePem ) )
if err != nil {
panic ( err )
}
return v . ( * x509 . Certificate )
}
func mustSigner ( ) crypto . Signer {
v , err := pemutil . Parse ( [ ] byte ( testIntermediateKeyPem ) )
if err != nil {
panic ( err )
}
return v . ( crypto . Signer )
}
2020-10-28 01:45:49 +00:00
func mustSign ( template , parent * x509 . Certificate , notBefore , notAfter time . Time ) * x509 . Certificate {
2020-09-16 02:37:02 +00:00
tmpl := * template
tmpl . NotBefore = notBefore
tmpl . NotAfter = notAfter
2020-10-28 01:45:49 +00:00
tmpl . Issuer = parent . Subject
cert , err := x509util . CreateCertificate ( & tmpl , parent , tmpl . PublicKey , testSigner )
2020-09-16 02:37:02 +00:00
if err != nil {
panic ( err )
}
return cert
}
func setTeeReader ( t * testing . T , w * bytes . Buffer ) {
t . Helper ( )
reader := rand . Reader
t . Cleanup ( func ( ) {
rand . Reader = reader
} )
rand . Reader = io . TeeReader ( reader , w )
}
func TestNew ( t * testing . T ) {
2022-03-29 00:54:35 +00:00
assertEqual := func ( x , y interface { } ) bool {
return reflect . DeepEqual ( x , y ) || fmt . Sprintf ( "%#v" , x ) == fmt . Sprintf ( "%#v" , y )
}
2020-09-16 02:37:02 +00:00
type args struct {
ctx context . Context
opts apiv1 . Options
}
tests := [ ] struct {
name string
args args
want * SoftCAS
wantErr bool
} {
2020-12-24 04:41:10 +00:00
{ "ok" , args { context . Background ( ) , apiv1 . Options { CertificateChain : [ ] * x509 . Certificate { testIssuer } , Signer : testSigner } } , & SoftCAS { CertificateChain : [ ] * x509 . Certificate { testIssuer } , Signer : testSigner } , false } ,
2022-03-29 00:54:35 +00:00
{ "ok with callback" , args { context . Background ( ) , apiv1 . Options { CertificateSigner : testCertificateSigner } } , & SoftCAS { CertificateSigner : testCertificateSigner } , false } ,
2020-09-16 02:37:02 +00:00
{ "fail no issuer" , args { context . Background ( ) , apiv1 . Options { Signer : testSigner } } , nil , true } ,
2020-12-24 04:41:10 +00:00
{ "fail no signer" , args { context . Background ( ) , apiv1 . Options { CertificateChain : [ ] * x509 . Certificate { testIssuer } } } , nil , true } ,
2020-09-16 02:37:02 +00:00
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
got , err := New ( tt . args . ctx , tt . args . opts )
if ( err != nil ) != tt . wantErr {
t . Errorf ( "New() error = %v, wantErr %v" , err , tt . wantErr )
return
}
2022-03-29 00:54:35 +00:00
if ! assertEqual ( got , tt . want ) {
2020-09-16 02:37:02 +00:00
t . Errorf ( "New() = %v, want %v" , got , tt . want )
}
} )
}
}
func TestNew_register ( t * testing . T ) {
newFn , ok := apiv1 . LoadCertificateAuthorityServiceNewFunc ( apiv1 . SoftCAS )
if ! ok {
t . Error ( "apiv1.LoadCertificateAuthorityServiceNewFunc(apiv1.SoftCAS) was not found" )
return
}
want := & SoftCAS {
2020-12-24 04:41:10 +00:00
CertificateChain : [ ] * x509 . Certificate { testIssuer } ,
Signer : testSigner ,
2020-09-16 02:37:02 +00:00
}
2020-12-24 04:41:10 +00:00
got , err := newFn ( context . Background ( ) , apiv1 . Options { CertificateChain : [ ] * x509 . Certificate { testIssuer } , Signer : testSigner } )
2020-09-16 02:37:02 +00:00
if err != nil {
t . Errorf ( "New() error = %v" , err )
return
}
if ! reflect . DeepEqual ( got , want ) {
t . Errorf ( "New() = %v, want %v" , got , want )
}
}
func TestSoftCAS_CreateCertificate ( t * testing . T ) {
mockNow ( t )
// Set rand.Reader to EOF
buf := new ( bytes . Buffer )
setTeeReader ( t , buf )
rand . Reader = buf
tmplNotBefore := * testTemplate
tmplNotBefore . NotBefore = testNow
tmplWithLifetime := * testTemplate
tmplWithLifetime . NotBefore = testNow
tmplWithLifetime . NotAfter = testNow . Add ( 24 * time . Hour )
tmplNoSerial := * testTemplate
tmplNoSerial . SerialNumber = nil
2021-09-08 22:33:34 +00:00
saTemplate := * testSignedTemplate
saTemplate . SignatureAlgorithm = 0
saSigner := & signatureAlgorithmSigner {
Signer : testSigner ,
algorithm : x509 . PureEd25519 ,
}
2020-09-16 02:37:02 +00:00
type fields struct {
2022-03-29 00:54:35 +00:00
Issuer * x509 . Certificate
Signer crypto . Signer
CertificateSigner func ( ) ( [ ] * x509 . Certificate , crypto . Signer , error )
2020-09-16 02:37:02 +00:00
}
type args struct {
req * apiv1 . CreateCertificateRequest
}
tests := [ ] struct {
name string
fields fields
args args
want * apiv1 . CreateCertificateResponse
wantErr bool
} {
2022-03-29 00:54:35 +00:00
{ "ok" , fields { testIssuer , testSigner , nil } , args { & apiv1 . CreateCertificateRequest {
2020-09-16 02:37:02 +00:00
Template : testTemplate , Lifetime : 24 * time . Hour ,
} } , & apiv1 . CreateCertificateResponse {
Certificate : testSignedTemplate ,
CertificateChain : [ ] * x509 . Certificate { testIssuer } ,
} , false } ,
2022-03-29 00:54:35 +00:00
{ "ok signature algorithm" , fields { testIssuer , saSigner , nil } , args { & apiv1 . CreateCertificateRequest {
2021-09-08 22:33:34 +00:00
Template : & saTemplate , Lifetime : 24 * time . Hour ,
} } , & apiv1 . CreateCertificateResponse {
Certificate : testSignedTemplate ,
CertificateChain : [ ] * x509 . Certificate { testIssuer } ,
} , false } ,
2022-03-29 00:54:35 +00:00
{ "ok with notBefore" , fields { testIssuer , testSigner , nil } , args { & apiv1 . CreateCertificateRequest {
2020-09-16 02:37:02 +00:00
Template : & tmplNotBefore , Lifetime : 24 * time . Hour ,
} } , & apiv1 . CreateCertificateResponse {
Certificate : testSignedTemplate ,
CertificateChain : [ ] * x509 . Certificate { testIssuer } ,
} , false } ,
2022-03-29 00:54:35 +00:00
{ "ok with notBefore+notAfter" , fields { testIssuer , testSigner , nil } , args { & apiv1 . CreateCertificateRequest {
2020-09-16 02:37:02 +00:00
Template : & tmplWithLifetime , Lifetime : 24 * time . Hour ,
} } , & apiv1 . CreateCertificateResponse {
Certificate : testSignedTemplate ,
CertificateChain : [ ] * x509 . Certificate { testIssuer } ,
} , false } ,
2022-03-29 00:54:35 +00:00
{ "ok with callback" , fields { nil , nil , testCertificateSigner } , args { & apiv1 . CreateCertificateRequest {
Template : testTemplate , Lifetime : 24 * time . Hour ,
} } , & apiv1 . CreateCertificateResponse {
Certificate : testSignedTemplate ,
CertificateChain : [ ] * x509 . Certificate { testIssuer } ,
} , false } ,
{ "fail template" , fields { testIssuer , testSigner , nil } , args { & apiv1 . CreateCertificateRequest { Lifetime : 24 * time . Hour } } , nil , true } ,
{ "fail lifetime" , fields { testIssuer , testSigner , nil } , args { & apiv1 . CreateCertificateRequest { Template : testTemplate } } , nil , true } ,
{ "fail CreateCertificate" , fields { testIssuer , testSigner , nil } , args { & apiv1 . CreateCertificateRequest {
2020-09-16 02:37:02 +00:00
Template : & tmplNoSerial ,
Lifetime : 24 * time . Hour ,
} } , nil , true } ,
2022-03-29 00:54:35 +00:00
{ "fail with callback" , fields { nil , nil , testFailCertificateSigner } , args { & apiv1 . CreateCertificateRequest {
Template : testTemplate , Lifetime : 24 * time . Hour ,
} } , nil , true } ,
2020-09-16 02:37:02 +00:00
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
c := & SoftCAS {
2022-03-29 00:54:35 +00:00
CertificateChain : [ ] * x509 . Certificate { tt . fields . Issuer } ,
Signer : tt . fields . Signer ,
CertificateSigner : tt . fields . CertificateSigner ,
2020-09-16 02:37:02 +00:00
}
got , err := c . CreateCertificate ( tt . args . req )
if ( err != nil ) != tt . wantErr {
t . Errorf ( "SoftCAS.CreateCertificate() error = %v, wantErr %v" , err , tt . wantErr )
return
}
if ! reflect . DeepEqual ( got , tt . want ) {
t . Errorf ( "SoftCAS.CreateCertificate() = %v, want %v" , got , tt . want )
}
} )
}
}
2022-06-16 02:10:58 +00:00
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 )
}
}
2022-08-30 23:49:56 +00:00
func TestSoftCAS_CreateCertificate_ec_rsa ( t * testing . T ) {
rootSigner , err := ecdsa . GenerateKey ( elliptic . P256 ( ) , rand . Reader )
if err != nil {
t . Fatal ( err )
}
intSigner , err := rsa . GenerateKey ( rand . Reader , 2048 )
if err != nil {
t . Fatal ( err )
}
now := time . Now ( )
// Root template
template := & x509 . Certificate {
Subject : pkix . Name { CommonName : "Test Root CA" } ,
KeyUsage : x509 . KeyUsageCRLSign | x509 . KeyUsageCertSign ,
PublicKey : rootSigner . Public ( ) ,
BasicConstraintsValid : true ,
IsCA : true ,
MaxPathLen : 0 ,
SerialNumber : big . NewInt ( 1234 ) ,
NotBefore : now ,
NotAfter : now . Add ( 24 * time . Hour ) ,
}
root , err := x509util . CreateCertificate ( template , template , rootSigner . Public ( ) , rootSigner )
if err != nil {
t . Fatal ( err )
}
// Intermediate template
template = & x509 . Certificate {
Subject : pkix . Name { CommonName : "Test Intermediate CA" } ,
KeyUsage : x509 . KeyUsageCRLSign | x509 . KeyUsageCertSign ,
PublicKey : intSigner . Public ( ) ,
BasicConstraintsValid : true ,
IsCA : true ,
MaxPathLen : 0 ,
SerialNumber : big . NewInt ( 1234 ) ,
NotBefore : now ,
NotAfter : now . Add ( 24 * time . Hour ) ,
}
iss , err := x509util . CreateCertificate ( template , root , intSigner . Public ( ) , rootSigner )
if err != nil {
t . Fatal ( err )
}
if iss . SignatureAlgorithm != x509 . ECDSAWithSHA256 {
t . Errorf ( "Certificate.SignatureAlgorithm = %v, want %v" , iss . SignatureAlgorithm , x509 . ECDSAWithSHA256 )
}
c := & SoftCAS {
CertificateChain : [ ] * x509 . Certificate { iss } ,
Signer : intSigner ,
}
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 . SHA256WithRSA {
t . Errorf ( "Certificate.SignatureAlgorithm = %v, want %v" , iss . SignatureAlgorithm , x509 . SHA256WithRSAPSS )
}
2022-08-31 00:11:44 +00:00
roots := x509 . NewCertPool ( )
roots . AddCert ( root )
intermediates := x509 . NewCertPool ( )
intermediates . AddCert ( iss )
2022-08-30 23:49:56 +00:00
if _ , err = cert . Certificate . Verify ( x509 . VerifyOptions {
2022-08-31 00:11:44 +00:00
CurrentTime : time . Now ( ) ,
Roots : roots ,
Intermediates : intermediates ,
KeyUsages : [ ] x509 . ExtKeyUsage { x509 . ExtKeyUsageClientAuth , x509 . ExtKeyUsageServerAuth } ,
2022-08-30 23:49:56 +00:00
} ) ; err != nil {
t . Errorf ( "Certificate.Verify() error = %v" , err )
}
}
2020-09-16 02:37:02 +00:00
func TestSoftCAS_RenewCertificate ( t * testing . T ) {
mockNow ( t )
// Set rand.Reader to EOF
buf := new ( bytes . Buffer )
setTeeReader ( t , buf )
rand . Reader = buf
tmplNoSerial := * testTemplate
tmplNoSerial . SerialNumber = nil
2021-09-08 22:33:34 +00:00
saSigner := & signatureAlgorithmSigner {
Signer : testSigner ,
algorithm : x509 . PureEd25519 ,
}
2020-09-16 02:37:02 +00:00
type fields struct {
2022-03-29 00:54:35 +00:00
Issuer * x509 . Certificate
Signer crypto . Signer
CertificateSigner func ( ) ( [ ] * x509 . Certificate , crypto . Signer , error )
2020-09-16 02:37:02 +00:00
}
type args struct {
req * apiv1 . RenewCertificateRequest
}
tests := [ ] struct {
name string
fields fields
args args
want * apiv1 . RenewCertificateResponse
wantErr bool
} {
2022-03-29 00:54:35 +00:00
{ "ok" , fields { testIssuer , testSigner , nil } , args { & apiv1 . RenewCertificateRequest {
Template : testTemplate , Lifetime : 24 * time . Hour ,
} } , & apiv1 . RenewCertificateResponse {
Certificate : testSignedTemplate ,
CertificateChain : [ ] * x509 . Certificate { testIssuer } ,
} , false } ,
{ "ok signature algorithm" , fields { testIssuer , saSigner , nil } , args { & apiv1 . RenewCertificateRequest {
2020-09-16 02:37:02 +00:00
Template : testTemplate , Lifetime : 24 * time . Hour ,
} } , & apiv1 . RenewCertificateResponse {
Certificate : testSignedTemplate ,
CertificateChain : [ ] * x509 . Certificate { testIssuer } ,
} , false } ,
2022-03-29 00:54:35 +00:00
{ "ok with callback" , fields { nil , nil , testCertificateSigner } , args { & apiv1 . RenewCertificateRequest {
2021-09-08 22:33:34 +00:00
Template : testTemplate , Lifetime : 24 * time . Hour ,
} } , & apiv1 . RenewCertificateResponse {
Certificate : testSignedTemplate ,
CertificateChain : [ ] * x509 . Certificate { testIssuer } ,
} , false } ,
2022-03-29 00:54:35 +00:00
{ "fail template" , fields { testIssuer , testSigner , nil } , args { & apiv1 . RenewCertificateRequest { Lifetime : 24 * time . Hour } } , nil , true } ,
{ "fail lifetime" , fields { testIssuer , testSigner , nil } , args { & apiv1 . RenewCertificateRequest { Template : testTemplate } } , nil , true } ,
{ "fail CreateCertificate" , fields { testIssuer , testSigner , nil } , args { & apiv1 . RenewCertificateRequest {
2020-09-16 02:37:02 +00:00
Template : & tmplNoSerial ,
Lifetime : 24 * time . Hour ,
} } , nil , true } ,
2022-03-29 00:54:35 +00:00
{ "fail with callback" , fields { nil , nil , testFailCertificateSigner } , args { & apiv1 . RenewCertificateRequest {
Template : testTemplate , Lifetime : 24 * time . Hour ,
} } , nil , true } ,
2020-09-16 02:37:02 +00:00
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
c := & SoftCAS {
2022-03-29 00:54:35 +00:00
CertificateChain : [ ] * x509 . Certificate { tt . fields . Issuer } ,
Signer : tt . fields . Signer ,
CertificateSigner : tt . fields . CertificateSigner ,
2020-09-16 02:37:02 +00:00
}
got , err := c . RenewCertificate ( tt . args . req )
if ( err != nil ) != tt . wantErr {
t . Errorf ( "SoftCAS.RenewCertificate() error = %v, wantErr %v" , err , tt . wantErr )
return
}
if ! reflect . DeepEqual ( got , tt . want ) {
t . Errorf ( "SoftCAS.RenewCertificate() = %v, want %v" , got , tt . want )
}
} )
}
}
func TestSoftCAS_RevokeCertificate ( t * testing . T ) {
type fields struct {
2022-03-29 00:54:35 +00:00
Issuer * x509 . Certificate
Signer crypto . Signer
CertificateSigner func ( ) ( [ ] * x509 . Certificate , crypto . Signer , error )
2020-09-16 02:37:02 +00:00
}
type args struct {
req * apiv1 . RevokeCertificateRequest
}
tests := [ ] struct {
name string
fields fields
args args
want * apiv1 . RevokeCertificateResponse
wantErr bool
} {
2022-03-29 00:54:35 +00:00
{ "ok" , fields { testIssuer , testSigner , nil } , args { & apiv1 . RevokeCertificateRequest {
2020-09-16 02:37:02 +00:00
Certificate : & x509 . Certificate { Subject : pkix . Name { CommonName : "fake" } } ,
Reason : "test reason" ,
ReasonCode : 1 ,
} } , & apiv1 . RevokeCertificateResponse {
Certificate : & x509 . Certificate { Subject : pkix . Name { CommonName : "fake" } } ,
CertificateChain : [ ] * x509 . Certificate { testIssuer } ,
} , false } ,
2022-03-29 00:54:35 +00:00
{ "ok no cert" , fields { testIssuer , testSigner , nil } , args { & apiv1 . RevokeCertificateRequest {
2020-09-16 02:37:02 +00:00
Reason : "test reason" ,
ReasonCode : 1 ,
} } , & apiv1 . RevokeCertificateResponse {
Certificate : nil ,
CertificateChain : [ ] * x509 . Certificate { testIssuer } ,
} , false } ,
2022-03-29 00:54:35 +00:00
{ "ok empty" , fields { testIssuer , testSigner , nil } , args { & apiv1 . RevokeCertificateRequest { } } , & apiv1 . RevokeCertificateResponse {
2020-09-16 02:37:02 +00:00
Certificate : nil ,
CertificateChain : [ ] * x509 . Certificate { testIssuer } ,
} , false } ,
2022-03-29 00:54:35 +00:00
{ "ok with callback" , fields { nil , nil , testCertificateSigner } , args { & apiv1 . RevokeCertificateRequest {
Certificate : & x509 . Certificate { Subject : pkix . Name { CommonName : "fake" } } ,
Reason : "test reason" ,
ReasonCode : 1 ,
} } , & apiv1 . RevokeCertificateResponse {
Certificate : & x509 . Certificate { Subject : pkix . Name { CommonName : "fake" } } ,
CertificateChain : [ ] * x509 . Certificate { testIssuer } ,
} , false } ,
{ "fail with callback" , fields { nil , nil , testFailCertificateSigner } , args { & apiv1 . RevokeCertificateRequest {
Certificate : & x509 . Certificate { Subject : pkix . Name { CommonName : "fake" } } ,
Reason : "test reason" ,
ReasonCode : 1 ,
} } , nil , true } ,
2020-09-16 02:37:02 +00:00
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
c := & SoftCAS {
2022-03-29 00:54:35 +00:00
CertificateChain : [ ] * x509 . Certificate { tt . fields . Issuer } ,
Signer : tt . fields . Signer ,
CertificateSigner : tt . fields . CertificateSigner ,
2020-09-16 02:37:02 +00:00
}
got , err := c . RevokeCertificate ( tt . args . req )
if ( err != nil ) != tt . wantErr {
t . Errorf ( "SoftCAS.RevokeCertificate() error = %v, wantErr %v" , err , tt . wantErr )
return
}
if ! reflect . DeepEqual ( got , tt . want ) {
t . Errorf ( "SoftCAS.RevokeCertificate() = %v, want %v" , got , tt . want )
}
} )
}
}
func Test_now ( t * testing . T ) {
t0 := time . Now ( )
t1 := now ( )
if t1 . Sub ( t0 ) > time . Second {
t . Errorf ( "now() = %s, want ~%s" , t1 , t0 )
}
}
2020-10-28 01:45:49 +00:00
func TestSoftCAS_CreateCertificateAuthority ( t * testing . T ) {
mockNow ( t )
2021-09-08 22:33:34 +00:00
saSigner := & signatureAlgorithmSigner {
Signer : testSigner ,
algorithm : x509 . PureEd25519 ,
}
2020-10-28 01:45:49 +00:00
type fields struct {
Issuer * x509 . Certificate
Signer crypto . Signer
KeyManager kms . KeyManager
}
type args struct {
req * apiv1 . CreateCertificateAuthorityRequest
}
tests := [ ] struct {
name string
fields fields
args args
want * apiv1 . CreateCertificateAuthorityResponse
wantErr bool
} {
{ "ok root" , fields { nil , nil , & mockKeyManager { } } , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . RootCA ,
Template : testRootTemplate ,
Lifetime : 24 * time . Hour ,
} } , & apiv1 . CreateCertificateAuthorityResponse {
Name : "Test Root CA" ,
Certificate : testSignedRootTemplate ,
PublicKey : testSignedRootTemplate . PublicKey ,
PrivateKey : testSigner ,
Signer : testSigner ,
} , false } ,
{ "ok intermediate" , fields { nil , nil , & mockKeyManager { } } , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . IntermediateCA ,
Template : testIntermediateTemplate ,
Lifetime : 24 * time . Hour ,
Parent : & apiv1 . CreateCertificateAuthorityResponse {
Certificate : testSignedRootTemplate ,
Signer : testSigner ,
} ,
} } , & apiv1 . CreateCertificateAuthorityResponse {
Name : "Test Intermediate CA" ,
Certificate : testSignedIntermediateTemplate ,
CertificateChain : [ ] * x509 . Certificate { testSignedRootTemplate } ,
PublicKey : testSignedIntermediateTemplate . PublicKey ,
PrivateKey : testSigner ,
Signer : testSigner ,
} , false } ,
2021-09-08 22:33:34 +00:00
{ "ok signature algorithm" , fields { nil , nil , & mockKeyManager { signer : saSigner } } , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . RootCA ,
Template : testRootTemplate ,
Lifetime : 24 * time . Hour ,
} } , & apiv1 . CreateCertificateAuthorityResponse {
Name : "Test Root CA" ,
Certificate : testSignedRootTemplate ,
PublicKey : testSignedRootTemplate . PublicKey ,
PrivateKey : saSigner ,
Signer : saSigner ,
} , false } ,
2021-10-07 21:19:39 +00:00
{ "ok createKey" , fields { nil , nil , & mockKeyManager { } } , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . RootCA ,
Template : testRootTemplate ,
Lifetime : 24 * time . Hour ,
CreateKey : & kmsapi . CreateKeyRequest {
Name : "root_ca.crt" ,
SignatureAlgorithm : kmsapi . ECDSAWithSHA256 ,
} ,
} } , & apiv1 . CreateCertificateAuthorityResponse {
Name : "Test Root CA" ,
Certificate : testSignedRootTemplate ,
PublicKey : testSignedRootTemplate . PublicKey ,
KeyName : "root_ca.crt" ,
PrivateKey : testSigner ,
Signer : testSigner ,
} , false } ,
2020-10-28 01:45:49 +00:00
{ "fail template" , fields { nil , nil , & mockKeyManager { } } , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . RootCA ,
Lifetime : 24 * time . Hour ,
} } , nil , true } ,
{ "fail lifetime" , fields { nil , nil , & mockKeyManager { } } , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . RootCA ,
Template : testIntermediateTemplate ,
} } , nil , true } ,
{ "fail type" , fields { nil , nil , & mockKeyManager { } } , args { & apiv1 . CreateCertificateAuthorityRequest {
Template : testIntermediateTemplate ,
Lifetime : 24 * time . Hour ,
} } , nil , true } ,
{ "fail parent" , fields { nil , nil , & mockKeyManager { } } , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . IntermediateCA ,
Template : testIntermediateTemplate ,
Lifetime : 24 * time . Hour ,
} } , nil , true } ,
{ "fail parent.certificate" , fields { nil , nil , & mockKeyManager { } } , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . IntermediateCA ,
Template : testIntermediateTemplate ,
Lifetime : 24 * time . Hour ,
Parent : & apiv1 . CreateCertificateAuthorityResponse {
Signer : testSigner ,
} ,
} } , nil , true } ,
{ "fail parent.signer" , fields { nil , nil , & mockKeyManager { } } , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . IntermediateCA ,
Template : testIntermediateTemplate ,
Lifetime : 24 * time . Hour ,
Parent : & apiv1 . CreateCertificateAuthorityResponse {
Certificate : testSignedRootTemplate ,
} ,
} } , nil , true } ,
{ "fail createKey" , fields { nil , nil , & mockKeyManager { errCreateKey : errTest } } , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . RootCA ,
Template : testIntermediateTemplate ,
Lifetime : 24 * time . Hour ,
} } , nil , true } ,
{ "fail createSigner" , fields { nil , nil , & mockKeyManager { errCreatesigner : errTest } } , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . RootCA ,
Template : testIntermediateTemplate ,
Lifetime : 24 * time . Hour ,
} } , nil , true } ,
{ "fail sign root" , fields { nil , nil , & mockKeyManager { signer : & badSigner { } } } , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . RootCA ,
Template : testIntermediateTemplate ,
Lifetime : 24 * time . Hour ,
} } , nil , true } ,
{ "fail sign intermediate" , fields { nil , nil , & mockKeyManager { } } , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . IntermediateCA ,
Template : testIntermediateTemplate ,
Lifetime : 24 * time . Hour ,
Parent : & apiv1 . CreateCertificateAuthorityResponse {
Certificate : testSignedRootTemplate ,
Signer : & badSigner { } ,
} ,
} } , nil , true } ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
c := & SoftCAS {
2020-12-24 04:41:10 +00:00
CertificateChain : [ ] * x509 . Certificate { tt . fields . Issuer } ,
Signer : tt . fields . Signer ,
KeyManager : tt . fields . KeyManager ,
2020-10-28 01:45:49 +00:00
}
got , err := c . CreateCertificateAuthority ( tt . args . req )
if ( err != nil ) != tt . wantErr {
t . Errorf ( "SoftCAS.CreateCertificateAuthority() error = %v, wantErr %v" , err , tt . wantErr )
return
}
if ! reflect . DeepEqual ( got , tt . want ) {
t . Errorf ( "SoftCAS.CreateCertificateAuthority() = \n%#v, want \n%#v" , got , tt . want )
}
} )
}
}
2022-03-29 00:54:35 +00:00
func TestSoftCAS_defaultKeyManager ( t * testing . T ) {
mockNow ( t )
type args struct {
req * apiv1 . CreateCertificateAuthorityRequest
}
tests := [ ] struct {
name string
args args
wantErr bool
} {
{ "ok root" , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . RootCA ,
Template : & x509 . Certificate {
Subject : pkix . Name { CommonName : "Test Root CA" } ,
KeyUsage : x509 . KeyUsageCRLSign | x509 . KeyUsageCertSign ,
BasicConstraintsValid : true ,
IsCA : true ,
MaxPathLen : 1 ,
SerialNumber : big . NewInt ( 1234 ) ,
} ,
Lifetime : 24 * time . Hour ,
} } , false } ,
{ "ok intermediate" , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . IntermediateCA ,
Template : testIntermediateTemplate ,
Lifetime : 24 * time . Hour ,
Parent : & apiv1 . CreateCertificateAuthorityResponse {
Certificate : testSignedRootTemplate ,
Signer : testSigner ,
} ,
} } , false } ,
{ "fail with default key manager" , args { & apiv1 . CreateCertificateAuthorityRequest {
Type : apiv1 . IntermediateCA ,
Template : testIntermediateTemplate ,
Lifetime : 24 * time . Hour ,
Parent : & apiv1 . CreateCertificateAuthorityResponse {
Certificate : testSignedRootTemplate ,
Signer : & badSigner { } ,
} ,
} } , true } ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
c := & SoftCAS { }
_ , err := c . CreateCertificateAuthority ( tt . args . req )
if ( err != nil ) != tt . wantErr {
t . Errorf ( "SoftCAS.CreateCertificateAuthority() error = %v, wantErr %v" , err , tt . wantErr )
return
}
} )
}
}
2022-08-30 23:49:56 +00:00
func Test_isRSA ( t * testing . T ) {
type args struct {
sa x509 . SignatureAlgorithm
}
tests := [ ] struct {
name string
args args
want bool
} {
{ "SHA256WithRSA" , args { x509 . SHA256WithRSA } , true } ,
{ "SHA384WithRSA" , args { x509 . SHA384WithRSA } , true } ,
{ "SHA512WithRSA" , args { x509 . SHA512WithRSA } , true } ,
{ "SHA256WithRSAPSS" , args { x509 . SHA256WithRSAPSS } , true } ,
{ "SHA384WithRSAPSS" , args { x509 . SHA384WithRSAPSS } , true } ,
{ "SHA512WithRSAPSS" , args { x509 . SHA512WithRSAPSS } , true } ,
{ "ECDSAWithSHA256" , args { x509 . ECDSAWithSHA256 } , false } ,
{ "ECDSAWithSHA384" , args { x509 . ECDSAWithSHA384 } , false } ,
{ "ECDSAWithSHA512" , args { x509 . ECDSAWithSHA512 } , false } ,
{ "PureEd25519" , args { x509 . PureEd25519 } , false } ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
if got := isRSA ( tt . args . sa ) ; got != tt . want {
t . Errorf ( "isRSA() = %v, want %v" , got , tt . want )
}
} )
}
}