2020-09-16 02:37:02 +00:00
|
|
|
package softcas
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"crypto"
|
|
|
|
"crypto/rand"
|
|
|
|
"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"
|
|
|
|
"github.com/smallstep/certificates/kms"
|
|
|
|
kmsapi "github.com/smallstep/certificates/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/6bchyKwp3RRK1GXiPMDCc+hsTJxuOLWy
|
|
|
|
YM7ga829dU8X4pRcEEAcBndqCED/502excjEK7U9vCkFCg==
|
|
|
|
-----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))
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *mockKeyManager) GetPublicKey(req *kmsapi.GetPublicKeyRequest) (crypto.PublicKey, error) {
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *mockKeyManager) CreateSigner(req *kmsapi.CreateSignerRequest) (crypto.Signer, error) {
|
|
|
|
signer := testSigner
|
|
|
|
if m.signer != nil {
|
|
|
|
signer = m.signer
|
|
|
|
}
|
|
|
|
return signer, m.errCreatesigner
|
|
|
|
}
|
|
|
|
|
2021-02-25 23:32:21 +00:00
|
|
|
func (m *mockKeyManager) CreateDecrypter(req *kmsapi.CreateDecrypterRequest) (crypto.Decrypter, error) {
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *badSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
|
|
|
|
return nil, fmt.Errorf("💥")
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
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},
|
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
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
|
|
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
|
|
|
|
|
|
|
|
tmplNotAfter := *testTemplate
|
|
|
|
tmplNotAfter.NotAfter = testNow.Add(24 * time.Hour)
|
|
|
|
|
|
|
|
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 {
|
|
|
|
Issuer *x509.Certificate
|
|
|
|
Signer crypto.Signer
|
|
|
|
}
|
|
|
|
type args struct {
|
|
|
|
req *apiv1.CreateCertificateRequest
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
fields fields
|
|
|
|
args args
|
|
|
|
want *apiv1.CreateCertificateResponse
|
|
|
|
wantErr bool
|
|
|
|
}{
|
|
|
|
{"ok", fields{testIssuer, testSigner}, args{&apiv1.CreateCertificateRequest{
|
|
|
|
Template: testTemplate, Lifetime: 24 * time.Hour,
|
|
|
|
}}, &apiv1.CreateCertificateResponse{
|
|
|
|
Certificate: testSignedTemplate,
|
|
|
|
CertificateChain: []*x509.Certificate{testIssuer},
|
|
|
|
}, false},
|
2021-09-08 22:33:34 +00:00
|
|
|
{"ok signature algorithm", fields{testIssuer, saSigner}, args{&apiv1.CreateCertificateRequest{
|
|
|
|
Template: &saTemplate, Lifetime: 24 * time.Hour,
|
|
|
|
}}, &apiv1.CreateCertificateResponse{
|
|
|
|
Certificate: testSignedTemplate,
|
|
|
|
CertificateChain: []*x509.Certificate{testIssuer},
|
|
|
|
}, false},
|
2020-09-16 02:37:02 +00:00
|
|
|
{"ok with notBefore", fields{testIssuer, testSigner}, args{&apiv1.CreateCertificateRequest{
|
|
|
|
Template: &tmplNotBefore, Lifetime: 24 * time.Hour,
|
|
|
|
}}, &apiv1.CreateCertificateResponse{
|
|
|
|
Certificate: testSignedTemplate,
|
|
|
|
CertificateChain: []*x509.Certificate{testIssuer},
|
|
|
|
}, false},
|
|
|
|
{"ok with notBefore+notAfter", fields{testIssuer, testSigner}, args{&apiv1.CreateCertificateRequest{
|
|
|
|
Template: &tmplWithLifetime, Lifetime: 24 * time.Hour,
|
|
|
|
}}, &apiv1.CreateCertificateResponse{
|
|
|
|
Certificate: testSignedTemplate,
|
|
|
|
CertificateChain: []*x509.Certificate{testIssuer},
|
|
|
|
}, false},
|
|
|
|
{"fail template", fields{testIssuer, testSigner}, args{&apiv1.CreateCertificateRequest{Lifetime: 24 * time.Hour}}, nil, true},
|
|
|
|
{"fail lifetime", fields{testIssuer, testSigner}, args{&apiv1.CreateCertificateRequest{Template: testTemplate}}, nil, true},
|
|
|
|
{"fail CreateCertificate", fields{testIssuer, testSigner}, args{&apiv1.CreateCertificateRequest{
|
|
|
|
Template: &tmplNoSerial,
|
|
|
|
Lifetime: 24 * time.Hour,
|
|
|
|
}}, 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,
|
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)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
|
|
|
Issuer *x509.Certificate
|
|
|
|
Signer crypto.Signer
|
|
|
|
}
|
|
|
|
type args struct {
|
|
|
|
req *apiv1.RenewCertificateRequest
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
fields fields
|
|
|
|
args args
|
|
|
|
want *apiv1.RenewCertificateResponse
|
|
|
|
wantErr bool
|
|
|
|
}{
|
|
|
|
{"ok", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{
|
|
|
|
Template: testTemplate, Lifetime: 24 * time.Hour,
|
|
|
|
}}, &apiv1.RenewCertificateResponse{
|
|
|
|
Certificate: testSignedTemplate,
|
|
|
|
CertificateChain: []*x509.Certificate{testIssuer},
|
|
|
|
}, false},
|
2021-09-08 22:33:34 +00:00
|
|
|
{"ok signature algorithm", fields{testIssuer, saSigner}, args{&apiv1.RenewCertificateRequest{
|
|
|
|
Template: testTemplate, Lifetime: 24 * time.Hour,
|
|
|
|
}}, &apiv1.RenewCertificateResponse{
|
|
|
|
Certificate: testSignedTemplate,
|
|
|
|
CertificateChain: []*x509.Certificate{testIssuer},
|
|
|
|
}, false},
|
2020-09-16 02:37:02 +00:00
|
|
|
{"fail template", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{Lifetime: 24 * time.Hour}}, nil, true},
|
|
|
|
{"fail lifetime", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{Template: testTemplate}}, nil, true},
|
|
|
|
{"fail CreateCertificate", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{
|
|
|
|
Template: &tmplNoSerial,
|
|
|
|
Lifetime: 24 * time.Hour,
|
|
|
|
}}, 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,
|
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 {
|
|
|
|
Issuer *x509.Certificate
|
|
|
|
Signer crypto.Signer
|
|
|
|
}
|
|
|
|
type args struct {
|
|
|
|
req *apiv1.RevokeCertificateRequest
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
fields fields
|
|
|
|
args args
|
|
|
|
want *apiv1.RevokeCertificateResponse
|
|
|
|
wantErr bool
|
|
|
|
}{
|
|
|
|
{"ok", fields{testIssuer, testSigner}, 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},
|
|
|
|
{"ok no cert", fields{testIssuer, testSigner}, args{&apiv1.RevokeCertificateRequest{
|
|
|
|
Reason: "test reason",
|
|
|
|
ReasonCode: 1,
|
|
|
|
}}, &apiv1.RevokeCertificateResponse{
|
|
|
|
Certificate: nil,
|
|
|
|
CertificateChain: []*x509.Certificate{testIssuer},
|
|
|
|
}, false},
|
|
|
|
{"ok empty", fields{testIssuer, testSigner}, args{&apiv1.RevokeCertificateRequest{}}, &apiv1.RevokeCertificateResponse{
|
|
|
|
Certificate: nil,
|
|
|
|
CertificateChain: []*x509.Certificate{testIssuer},
|
|
|
|
}, false},
|
|
|
|
}
|
|
|
|
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,
|
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)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|