forked from TrueCloudLab/certificates
Merge pull request #879 from smallstep/feat/WithX509SignerFunc
Add authority.WithX509SignerFunc
This commit is contained in:
commit
b42c1dfe64
4 changed files with 200 additions and 49 deletions
|
@ -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,12 +31,20 @@ 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 contains the issuer certificate, along with any other
|
||||||
// bundled certificates to be returned in the chain for consumers, and
|
// bundled certificates to be returned in the chain for consumers. It is
|
||||||
// signer used in SoftCAS. They are configured in ca.json crt and key
|
// used used in SoftCAS, and is configured in the crt property of the
|
||||||
// properties.
|
// ca.json.
|
||||||
CertificateChain []*x509.Certificate `json:"-"`
|
CertificateChain []*x509.Certificate `json:"-"`
|
||||||
Signer crypto.Signer `json:"-"`
|
|
||||||
|
// Signer is the private key or a KMS signer for the issuer certificate. It is used in
|
||||||
|
// SoftCAS and it is configured in the key property of the ca.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
|
||||||
|
|
|
@ -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,
|
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 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},
|
||||||
{"fail template", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{Lifetime: 24 * time.Hour}}, nil, true},
|
{"ok with callback", fields{nil, nil, testCertificateSigner}, args{&apiv1.RenewCertificateRequest{
|
||||||
{"fail lifetime", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{Template: testTemplate}}, nil, true},
|
Template: testTemplate, Lifetime: 24 * time.Hour,
|
||||||
{"fail CreateCertificate", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{
|
}}, &apiv1.RenewCertificateResponse{
|
||||||
|
Certificate: testSignedTemplate,
|
||||||
|
CertificateChain: []*x509.Certificate{testIssuer},
|
||||||
|
}, false},
|
||||||
|
{"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{
|
||||||
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…
Reference in a new issue