Add authority.WithX509SignerFunc

This change adds a new authority option that allows to pass a callback
that returns the certificate chain and signer used to sign X.509
certificates.

This option will be used by Caddy, they renew the intermediate
certificate weekly and there's no other way to replace it without
re-creating the embedded CA.

Fixes #874
pull/879/head
Mariano Cano 2 years ago
parent 49de04661b
commit 955d4cf80d

@ -163,6 +163,22 @@ func WithX509Signer(crt *x509.Certificate, s crypto.Signer) Option {
} }
} }
// WithX509SignerFunc defines the function used to get the chain of certificates
// and signer used when we sign X.509 certificates.
func WithX509SignerFunc(fn func() ([]*x509.Certificate, crypto.Signer, error)) Option {
return func(a *Authority) error {
srv, err := cas.New(context.Background(), casapi.Options{
Type: casapi.SoftCAS,
CertificateSigner: fn,
})
if err != nil {
return err
}
a.x509CAService = srv
return nil
}
}
// WithSSHUserSigner defines the signer used to sign SSH user certificates. // WithSSHUserSigner defines the signer used to sign SSH user certificates.
func WithSSHUserSigner(s crypto.Signer) Option { func WithSSHUserSigner(s crypto.Signer) Option {
return func(a *Authority) error { return func(a *Authority) error {

@ -31,13 +31,18 @@ type Options struct {
// https://cloud.google.com/docs/authentication. // https://cloud.google.com/docs/authentication.
CredentialsFile string `json:"credentialsFile,omitempty"` CredentialsFile string `json:"credentialsFile,omitempty"`
// Certificate and signer are the issuer certificate, along with any other // CertificateChain and Signer are the issuer certificate, along with any
// bundled certificates to be returned in the chain for consumers, and // other bundled certificates to be returned in the chain for consumers, and
// signer used in SoftCAS. They are configured in ca.json crt and key // signer used in SoftCAS. They are configured in ca.json crt and key
// properties. // properties.
CertificateChain []*x509.Certificate `json:"-"` CertificateChain []*x509.Certificate `json:"-"`
Signer crypto.Signer `json:"-"` Signer crypto.Signer `json:"-"`
// CertificateSigner combines CertificateChain and Signer in a callback that
// returns the chain of certificate and signer used to sign X.509
// certificates in SoftCAS.
CertificateSigner func() ([]*x509.Certificate, crypto.Signer, error) `json:"-"`
// IsCreator is set to true when we're creating a certificate authority. It // IsCreator is set to true when we're creating a certificate authority. It
// is used to skip some validations when initializing a // is used to skip some validations when initializing a
// CertificateAuthority. This option is used on SoftCAS and CloudCAS. // CertificateAuthority. This option is used on SoftCAS and CloudCAS.

@ -24,9 +24,10 @@ var now = time.Now
// SoftCAS implements a Certificate Authority Service using Golang or KMS // SoftCAS implements a Certificate Authority Service using Golang or KMS
// crypto. This is the default CAS used in step-ca. // crypto. This is the default CAS used in step-ca.
type SoftCAS struct { type SoftCAS struct {
CertificateChain []*x509.Certificate CertificateChain []*x509.Certificate
Signer crypto.Signer Signer crypto.Signer
KeyManager kms.KeyManager CertificateSigner func() ([]*x509.Certificate, crypto.Signer, error)
KeyManager kms.KeyManager
} }
// New creates a new CertificateAuthorityService implementation using Golang or KMS // New creates a new CertificateAuthorityService implementation using Golang or KMS
@ -34,16 +35,17 @@ type SoftCAS struct {
func New(ctx context.Context, opts apiv1.Options) (*SoftCAS, error) { func New(ctx context.Context, opts apiv1.Options) (*SoftCAS, error) {
if !opts.IsCreator { if !opts.IsCreator {
switch { switch {
case len(opts.CertificateChain) == 0: case len(opts.CertificateChain) == 0 && opts.CertificateSigner == nil:
return nil, errors.New("softCAS 'CertificateChain' cannot be nil") return nil, errors.New("softCAS 'CertificateChain' cannot be nil")
case opts.Signer == nil: case opts.Signer == nil && opts.CertificateSigner == nil:
return nil, errors.New("softCAS 'signer' cannot be nil") return nil, errors.New("softCAS 'signer' cannot be nil")
} }
} }
return &SoftCAS{ return &SoftCAS{
CertificateChain: opts.CertificateChain, CertificateChain: opts.CertificateChain,
Signer: opts.Signer, Signer: opts.Signer,
KeyManager: opts.KeyManager, CertificateSigner: opts.CertificateSigner,
KeyManager: opts.KeyManager,
}, nil }, nil
} }
@ -57,6 +59,7 @@ func (c *SoftCAS) CreateCertificate(req *apiv1.CreateCertificateRequest) (*apiv1
} }
t := now() t := now()
// Provisioners can also set specific values. // Provisioners can also set specific values.
if req.Template.NotBefore.IsZero() { if req.Template.NotBefore.IsZero() {
req.Template.NotBefore = t.Add(-1 * req.Backdate) req.Template.NotBefore = t.Add(-1 * req.Backdate)
@ -64,16 +67,21 @@ func (c *SoftCAS) CreateCertificate(req *apiv1.CreateCertificateRequest) (*apiv1
if req.Template.NotAfter.IsZero() { if req.Template.NotAfter.IsZero() {
req.Template.NotAfter = t.Add(req.Lifetime) req.Template.NotAfter = t.Add(req.Lifetime)
} }
req.Template.Issuer = c.CertificateChain[0].Subject
cert, err := createCertificate(req.Template, c.CertificateChain[0], req.Template.PublicKey, c.Signer) chain, signer, err := c.getCertSigner()
if err != nil {
return nil, err
}
req.Template.Issuer = chain[0].Subject
cert, err := createCertificate(req.Template, chain[0], req.Template.PublicKey, signer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &apiv1.CreateCertificateResponse{ return &apiv1.CreateCertificateResponse{
Certificate: cert, Certificate: cert,
CertificateChain: c.CertificateChain, CertificateChain: chain,
}, nil }, nil
} }
@ -89,16 +97,21 @@ func (c *SoftCAS) RenewCertificate(req *apiv1.RenewCertificateRequest) (*apiv1.R
t := now() t := now()
req.Template.NotBefore = t.Add(-1 * req.Backdate) req.Template.NotBefore = t.Add(-1 * req.Backdate)
req.Template.NotAfter = t.Add(req.Lifetime) req.Template.NotAfter = t.Add(req.Lifetime)
req.Template.Issuer = c.CertificateChain[0].Subject
cert, err := createCertificate(req.Template, c.CertificateChain[0], req.Template.PublicKey, c.Signer) chain, signer, err := c.getCertSigner()
if err != nil {
return nil, err
}
req.Template.Issuer = chain[0].Subject
cert, err := createCertificate(req.Template, chain[0], req.Template.PublicKey, signer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &apiv1.RenewCertificateResponse{ return &apiv1.RenewCertificateResponse{
Certificate: cert, Certificate: cert,
CertificateChain: c.CertificateChain, CertificateChain: chain,
}, nil }, nil
} }
@ -106,9 +119,13 @@ func (c *SoftCAS) RenewCertificate(req *apiv1.RenewCertificateRequest) (*apiv1.R
// operation is a no-op as the actual revoke will happen when we store the entry // operation is a no-op as the actual revoke will happen when we store the entry
// in the db. // in the db.
func (c *SoftCAS) RevokeCertificate(req *apiv1.RevokeCertificateRequest) (*apiv1.RevokeCertificateResponse, error) { func (c *SoftCAS) RevokeCertificate(req *apiv1.RevokeCertificateRequest) (*apiv1.RevokeCertificateResponse, error) {
chain, _, err := c.getCertSigner()
if err != nil {
return nil, err
}
return &apiv1.RevokeCertificateResponse{ return &apiv1.RevokeCertificateResponse{
Certificate: req.Certificate, Certificate: req.Certificate,
CertificateChain: c.CertificateChain, CertificateChain: chain,
}, nil }, nil
} }
@ -179,7 +196,7 @@ func (c *SoftCAS) CreateCertificateAuthority(req *apiv1.CreateCertificateAuthori
}, nil }, nil
} }
// initializeKeyManager initiazes the default key manager if was not given. // initializeKeyManager initializes the default key manager if was not given.
func (c *SoftCAS) initializeKeyManager() (err error) { func (c *SoftCAS) initializeKeyManager() (err error) {
if c.KeyManager == nil { if c.KeyManager == nil {
c.KeyManager, err = kms.New(context.Background(), kmsapi.Options{ c.KeyManager, err = kms.New(context.Background(), kmsapi.Options{
@ -189,6 +206,15 @@ func (c *SoftCAS) initializeKeyManager() (err error) {
return return
} }
// getCertSigner returns the certificate chain and signer to use.
func (c *SoftCAS) getCertSigner() ([]*x509.Certificate, crypto.Signer, error) {
if c.CertificateSigner != nil {
return c.CertificateSigner()
}
return c.CertificateChain, c.Signer, nil
}
// createKey uses the configured kms to create a key. // createKey uses the configured kms to create a key.
func (c *SoftCAS) createKey(req *kmsapi.CreateKeyRequest) (*kmsapi.CreateKeyResponse, error) { func (c *SoftCAS) createKey(req *kmsapi.CreateKeyRequest) (*kmsapi.CreateKeyResponse, error) {
if err := c.initializeKeyManager(); err != nil { if err := c.initializeKeyManager(); err != nil {

@ -73,6 +73,12 @@ var (
testSignedTemplate = mustSign(testTemplate, testIssuer, testNow, testNow.Add(24*time.Hour)) testSignedTemplate = mustSign(testTemplate, testIssuer, testNow, testNow.Add(24*time.Hour))
testSignedRootTemplate = mustSign(testRootTemplate, testRootTemplate, 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)) testSignedIntermediateTemplate = mustSign(testIntermediateTemplate, testSignedRootTemplate, testNow, testNow.Add(24*time.Hour))
testCertificateSigner = func() ([]*x509.Certificate, crypto.Signer, error) {
return []*x509.Certificate{testIssuer}, testSigner, nil
}
testFailCertificateSigner = func() ([]*x509.Certificate, crypto.Signer, error) {
return nil, nil, errTest
}
) )
type signatureAlgorithmSigner struct { type signatureAlgorithmSigner struct {
@ -186,6 +192,10 @@ func setTeeReader(t *testing.T, w *bytes.Buffer) {
} }
func TestNew(t *testing.T) { func TestNew(t *testing.T) {
assertEqual := func(x, y interface{}) bool {
return reflect.DeepEqual(x, y) || fmt.Sprintf("%#v", x) == fmt.Sprintf("%#v", y)
}
type args struct { type args struct {
ctx context.Context ctx context.Context
opts apiv1.Options opts apiv1.Options
@ -197,6 +207,7 @@ func TestNew(t *testing.T) {
wantErr bool wantErr bool
}{ }{
{"ok", args{context.Background(), apiv1.Options{CertificateChain: []*x509.Certificate{testIssuer}, Signer: testSigner}}, &SoftCAS{CertificateChain: []*x509.Certificate{testIssuer}, Signer: testSigner}, false}, {"ok", args{context.Background(), apiv1.Options{CertificateChain: []*x509.Certificate{testIssuer}, Signer: testSigner}}, &SoftCAS{CertificateChain: []*x509.Certificate{testIssuer}, Signer: testSigner}, false},
{"ok with callback", args{context.Background(), apiv1.Options{CertificateSigner: testCertificateSigner}}, &SoftCAS{CertificateSigner: testCertificateSigner}, false},
{"fail no issuer", args{context.Background(), apiv1.Options{Signer: testSigner}}, nil, true}, {"fail no issuer", args{context.Background(), apiv1.Options{Signer: testSigner}}, nil, true},
{"fail no signer", args{context.Background(), apiv1.Options{CertificateChain: []*x509.Certificate{testIssuer}}}, nil, true}, {"fail no signer", args{context.Background(), apiv1.Options{CertificateChain: []*x509.Certificate{testIssuer}}}, nil, true},
} }
@ -207,7 +218,7 @@ func TestNew(t *testing.T) {
t.Errorf("New() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("New() error = %v, wantErr %v", err, tt.wantErr)
return return
} }
if !reflect.DeepEqual(got, tt.want) { if !assertEqual(got, tt.want) {
t.Errorf("New() = %v, want %v", got, tt.want) t.Errorf("New() = %v, want %v", got, tt.want)
} }
}) })
@ -265,8 +276,9 @@ func TestSoftCAS_CreateCertificate(t *testing.T) {
} }
type fields struct { type fields struct {
Issuer *x509.Certificate Issuer *x509.Certificate
Signer crypto.Signer Signer crypto.Signer
CertificateSigner func() ([]*x509.Certificate, crypto.Signer, error)
} }
type args struct { type args struct {
req *apiv1.CreateCertificateRequest req *apiv1.CreateCertificateRequest
@ -278,43 +290,53 @@ func TestSoftCAS_CreateCertificate(t *testing.T) {
want *apiv1.CreateCertificateResponse want *apiv1.CreateCertificateResponse
wantErr bool wantErr bool
}{ }{
{"ok", fields{testIssuer, testSigner}, args{&apiv1.CreateCertificateRequest{ {"ok", fields{testIssuer, testSigner, nil}, args{&apiv1.CreateCertificateRequest{
Template: testTemplate, Lifetime: 24 * time.Hour, Template: testTemplate, Lifetime: 24 * time.Hour,
}}, &apiv1.CreateCertificateResponse{ }}, &apiv1.CreateCertificateResponse{
Certificate: testSignedTemplate, Certificate: testSignedTemplate,
CertificateChain: []*x509.Certificate{testIssuer}, CertificateChain: []*x509.Certificate{testIssuer},
}, false}, }, false},
{"ok signature algorithm", fields{testIssuer, saSigner}, args{&apiv1.CreateCertificateRequest{ {"ok signature algorithm", fields{testIssuer, saSigner, nil}, args{&apiv1.CreateCertificateRequest{
Template: &saTemplate, Lifetime: 24 * time.Hour, Template: &saTemplate, Lifetime: 24 * time.Hour,
}}, &apiv1.CreateCertificateResponse{ }}, &apiv1.CreateCertificateResponse{
Certificate: testSignedTemplate, Certificate: testSignedTemplate,
CertificateChain: []*x509.Certificate{testIssuer}, CertificateChain: []*x509.Certificate{testIssuer},
}, false}, }, false},
{"ok with notBefore", fields{testIssuer, testSigner}, args{&apiv1.CreateCertificateRequest{ {"ok with notBefore", fields{testIssuer, testSigner, nil}, args{&apiv1.CreateCertificateRequest{
Template: &tmplNotBefore, Lifetime: 24 * time.Hour, Template: &tmplNotBefore, Lifetime: 24 * time.Hour,
}}, &apiv1.CreateCertificateResponse{ }}, &apiv1.CreateCertificateResponse{
Certificate: testSignedTemplate, Certificate: testSignedTemplate,
CertificateChain: []*x509.Certificate{testIssuer}, CertificateChain: []*x509.Certificate{testIssuer},
}, false}, }, false},
{"ok with notBefore+notAfter", fields{testIssuer, testSigner}, args{&apiv1.CreateCertificateRequest{ {"ok with notBefore+notAfter", fields{testIssuer, testSigner, nil}, args{&apiv1.CreateCertificateRequest{
Template: &tmplWithLifetime, Lifetime: 24 * time.Hour, Template: &tmplWithLifetime, Lifetime: 24 * time.Hour,
}}, &apiv1.CreateCertificateResponse{ }}, &apiv1.CreateCertificateResponse{
Certificate: testSignedTemplate, Certificate: testSignedTemplate,
CertificateChain: []*x509.Certificate{testIssuer}, CertificateChain: []*x509.Certificate{testIssuer},
}, false}, }, false},
{"fail template", fields{testIssuer, testSigner}, args{&apiv1.CreateCertificateRequest{Lifetime: 24 * time.Hour}}, nil, true}, {"ok with callback", fields{nil, nil, testCertificateSigner}, args{&apiv1.CreateCertificateRequest{
{"fail lifetime", fields{testIssuer, testSigner}, args{&apiv1.CreateCertificateRequest{Template: testTemplate}}, nil, true}, Template: testTemplate, Lifetime: 24 * time.Hour,
{"fail CreateCertificate", fields{testIssuer, testSigner}, args{&apiv1.CreateCertificateRequest{ }}, &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{
Template: &tmplNoSerial, Template: &tmplNoSerial,
Lifetime: 24 * time.Hour, Lifetime: 24 * time.Hour,
}}, nil, true}, }}, nil, true},
{"fail with callback", fields{nil, nil, testFailCertificateSigner}, args{&apiv1.CreateCertificateRequest{
Template: testTemplate, Lifetime: 24 * time.Hour,
}}, nil, true},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &SoftCAS{ c := &SoftCAS{
CertificateChain: []*x509.Certificate{tt.fields.Issuer}, CertificateChain: []*x509.Certificate{tt.fields.Issuer},
Signer: tt.fields.Signer, Signer: tt.fields.Signer,
CertificateSigner: tt.fields.CertificateSigner,
} }
got, err := c.CreateCertificate(tt.args.req) got, err := c.CreateCertificate(tt.args.req)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
@ -345,8 +367,9 @@ func TestSoftCAS_RenewCertificate(t *testing.T) {
} }
type fields struct { type fields struct {
Issuer *x509.Certificate Issuer *x509.Certificate
Signer crypto.Signer Signer crypto.Signer
CertificateSigner func() ([]*x509.Certificate, crypto.Signer, error)
} }
type args struct { type args struct {
req *apiv1.RenewCertificateRequest req *apiv1.RenewCertificateRequest
@ -358,30 +381,40 @@ func TestSoftCAS_RenewCertificate(t *testing.T) {
want *apiv1.RenewCertificateResponse want *apiv1.RenewCertificateResponse
wantErr bool wantErr bool
}{ }{
{"ok", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{ {"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{
Template: testTemplate, Lifetime: 24 * time.Hour, Template: testTemplate, Lifetime: 24 * time.Hour,
}}, &apiv1.RenewCertificateResponse{ }}, &apiv1.RenewCertificateResponse{
Certificate: testSignedTemplate, Certificate: testSignedTemplate,
CertificateChain: []*x509.Certificate{testIssuer}, CertificateChain: []*x509.Certificate{testIssuer},
}, false}, }, false},
{"ok signature algorithm", fields{testIssuer, saSigner}, args{&apiv1.RenewCertificateRequest{ {"ok with callback", fields{nil, nil, testCertificateSigner}, args{&apiv1.RenewCertificateRequest{
Template: testTemplate, Lifetime: 24 * time.Hour, Template: testTemplate, Lifetime: 24 * time.Hour,
}}, &apiv1.RenewCertificateResponse{ }}, &apiv1.RenewCertificateResponse{
Certificate: testSignedTemplate, Certificate: testSignedTemplate,
CertificateChain: []*x509.Certificate{testIssuer}, CertificateChain: []*x509.Certificate{testIssuer},
}, false}, }, false},
{"fail template", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{Lifetime: 24 * time.Hour}}, nil, true}, {"fail template", fields{testIssuer, testSigner, nil}, args{&apiv1.RenewCertificateRequest{Lifetime: 24 * time.Hour}}, nil, true},
{"fail lifetime", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{Template: testTemplate}}, nil, true}, {"fail lifetime", fields{testIssuer, testSigner, nil}, args{&apiv1.RenewCertificateRequest{Template: testTemplate}}, nil, true},
{"fail CreateCertificate", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{ {"fail CreateCertificate", fields{testIssuer, testSigner, nil}, args{&apiv1.RenewCertificateRequest{
Template: &tmplNoSerial, Template: &tmplNoSerial,
Lifetime: 24 * time.Hour, Lifetime: 24 * time.Hour,
}}, nil, true}, }}, nil, true},
{"fail with callback", fields{nil, nil, testFailCertificateSigner}, args{&apiv1.RenewCertificateRequest{
Template: testTemplate, Lifetime: 24 * time.Hour,
}}, nil, true},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &SoftCAS{ c := &SoftCAS{
CertificateChain: []*x509.Certificate{tt.fields.Issuer}, CertificateChain: []*x509.Certificate{tt.fields.Issuer},
Signer: tt.fields.Signer, Signer: tt.fields.Signer,
CertificateSigner: tt.fields.CertificateSigner,
} }
got, err := c.RenewCertificate(tt.args.req) got, err := c.RenewCertificate(tt.args.req)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
@ -397,8 +430,9 @@ func TestSoftCAS_RenewCertificate(t *testing.T) {
func TestSoftCAS_RevokeCertificate(t *testing.T) { func TestSoftCAS_RevokeCertificate(t *testing.T) {
type fields struct { type fields struct {
Issuer *x509.Certificate Issuer *x509.Certificate
Signer crypto.Signer Signer crypto.Signer
CertificateSigner func() ([]*x509.Certificate, crypto.Signer, error)
} }
type args struct { type args struct {
req *apiv1.RevokeCertificateRequest req *apiv1.RevokeCertificateRequest
@ -410,7 +444,7 @@ func TestSoftCAS_RevokeCertificate(t *testing.T) {
want *apiv1.RevokeCertificateResponse want *apiv1.RevokeCertificateResponse
wantErr bool wantErr bool
}{ }{
{"ok", fields{testIssuer, testSigner}, args{&apiv1.RevokeCertificateRequest{ {"ok", fields{testIssuer, testSigner, nil}, args{&apiv1.RevokeCertificateRequest{
Certificate: &x509.Certificate{Subject: pkix.Name{CommonName: "fake"}}, Certificate: &x509.Certificate{Subject: pkix.Name{CommonName: "fake"}},
Reason: "test reason", Reason: "test reason",
ReasonCode: 1, ReasonCode: 1,
@ -418,23 +452,37 @@ func TestSoftCAS_RevokeCertificate(t *testing.T) {
Certificate: &x509.Certificate{Subject: pkix.Name{CommonName: "fake"}}, Certificate: &x509.Certificate{Subject: pkix.Name{CommonName: "fake"}},
CertificateChain: []*x509.Certificate{testIssuer}, CertificateChain: []*x509.Certificate{testIssuer},
}, false}, }, false},
{"ok no cert", fields{testIssuer, testSigner}, args{&apiv1.RevokeCertificateRequest{ {"ok no cert", fields{testIssuer, testSigner, nil}, args{&apiv1.RevokeCertificateRequest{
Reason: "test reason", Reason: "test reason",
ReasonCode: 1, ReasonCode: 1,
}}, &apiv1.RevokeCertificateResponse{ }}, &apiv1.RevokeCertificateResponse{
Certificate: nil, Certificate: nil,
CertificateChain: []*x509.Certificate{testIssuer}, CertificateChain: []*x509.Certificate{testIssuer},
}, false}, }, false},
{"ok empty", fields{testIssuer, testSigner}, args{&apiv1.RevokeCertificateRequest{}}, &apiv1.RevokeCertificateResponse{ {"ok empty", fields{testIssuer, testSigner, nil}, args{&apiv1.RevokeCertificateRequest{}}, &apiv1.RevokeCertificateResponse{
Certificate: nil, Certificate: nil,
CertificateChain: []*x509.Certificate{testIssuer}, CertificateChain: []*x509.Certificate{testIssuer},
}, false}, }, false},
{"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},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &SoftCAS{ c := &SoftCAS{
CertificateChain: []*x509.Certificate{tt.fields.Issuer}, CertificateChain: []*x509.Certificate{tt.fields.Issuer},
Signer: tt.fields.Signer, Signer: tt.fields.Signer,
CertificateSigner: tt.fields.CertificateSigner,
} }
got, err := c.RevokeCertificate(tt.args.req) got, err := c.RevokeCertificate(tt.args.req)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
@ -609,3 +657,56 @@ func TestSoftCAS_CreateCertificateAuthority(t *testing.T) {
}) })
} }
} }
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
}
})
}
}

Loading…
Cancel
Save