38fa780775
This change makes easier the configuration of cloudCAS as it does not require to configure the root or intermediate certificate in the ca.json. CloudCAS will get the root certificate using the configured certificateAuthority.
675 lines
23 KiB
Go
675 lines
23 KiB
Go
package cloudcas
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"crypto/rand"
|
|
"crypto/x509"
|
|
"encoding/asn1"
|
|
"io"
|
|
"os"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
gax "github.com/googleapis/gax-go/v2"
|
|
"github.com/pkg/errors"
|
|
"github.com/smallstep/certificates/cas/apiv1"
|
|
pb "google.golang.org/genproto/googleapis/cloud/security/privateca/v1beta1"
|
|
)
|
|
|
|
var (
|
|
errTest = errors.New("test error")
|
|
testAuthorityName = "projects/test-project/locations/us-west1/certificateAuthorities/test-ca"
|
|
testCertificateName = "projects/test-project/locations/us-west1/certificateAuthorities/test-ca/certificates/test-certificate"
|
|
testRootCertificate = `-----BEGIN CERTIFICATE-----
|
|
MIIBhjCCAS2gAwIBAgIQLbKTuXau4+t3KFbGpJJAADAKBggqhkjOPQQDAjAiMSAw
|
|
HgYDVQQDExdHb29nbGUgQ0FTIFRlc3QgUm9vdCBDQTAeFw0yMDA5MTQyMjQ4NDla
|
|
Fw0zMDA5MTIyMjQ4NDlaMCIxIDAeBgNVBAMTF0dvb2dsZSBDQVMgVGVzdCBSb290
|
|
IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYKGgQ3/0D7+oBTc0CXoYfSC6
|
|
M8hOqLsmzBapPZSYpfwjgEsjdNU84jdrYmW1zF1+p+MrL4c7qJv9NLo/picCuqNF
|
|
MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE
|
|
FFVn9V7Qymd7cUJh9KAhnUDAQL5YMAoGCCqGSM49BAMCA0cAMEQCIA4LzttYoT3u
|
|
8TYgSrvFT+Z+cklfi4UrPBU6aSbcUaW2AiAPfaqbyccQT3CxMVyHg+xZZjAirZp8
|
|
lAeA/T4FxAonHA==
|
|
-----END CERTIFICATE-----`
|
|
testIntermediateCertificate = `-----BEGIN CERTIFICATE-----
|
|
MIIBsDCCAVagAwIBAgIQOb91kHxWKVzSJ9ESW1ViVzAKBggqhkjOPQQDAjAiMSAw
|
|
HgYDVQQDExdHb29nbGUgQ0FTIFRlc3QgUm9vdCBDQTAeFw0yMDA5MTQyMjQ4NDla
|
|
Fw0zMDA5MTIyMjQ4NDlaMCoxKDAmBgNVBAMTH0dvb2dsZSBDQVMgVGVzdCBJbnRl
|
|
cm1lZGlhdGUgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASUHN1cNyId4Ei/
|
|
4MxD5VrZFc51P50caMUdDZVrPveidChBYCU/9IM6vnRlZHx2HLjQ0qAvqHwY3rT0
|
|
xc7n+PfCo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAd
|
|
BgNVHQ4EFgQUSDlasiw0pRKyS7llhL0ZuVFNa9UwHwYDVR0jBBgwFoAUVWf1XtDK
|
|
Z3txQmH0oCGdQMBAvlgwCgYIKoZIzj0EAwIDSAAwRQIgMmsLcoC4KriXw+s+cZx2
|
|
bJMf6Mx/WESj31buJJhpzY0CIQCBUa/JtvS3nyce/4DF5tK2v49/NWHREgqAaZ57
|
|
DcYyHQ==
|
|
-----END CERTIFICATE-----`
|
|
testLeafCertificate = `-----BEGIN CERTIFICATE-----
|
|
MIIB1jCCAX2gAwIBAgIQQfOn+COMeuD8VYF1TiDkEzAKBggqhkjOPQQDAjAqMSgw
|
|
JgYDVQQDEx9Hb29nbGUgQ0FTIFRlc3QgSW50ZXJtZWRpYXRlIENBMB4XDTIwMDkx
|
|
NDIyNTE1NVoXDTMwMDkxMjIyNTE1MlowHTEbMBkGA1UEAxMSdGVzdC5zbWFsbHN0
|
|
ZXAuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAdUSRBrpgHFilN4eaGlN
|
|
nX2+xfjXa1Iwk2/+AensjFTXJi1UAIB0e+4pqi7Sen5E2QVBhntEHCrA3xOf7czg
|
|
P6OBkTCBjjAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG
|
|
AQUFBwMCMB0GA1UdDgQWBBSYPbu4Tmm7Zze/hCePeZH1Avoj+jAfBgNVHSMEGDAW
|
|
gBRIOVqyLDSlErJLuWWEvRm5UU1r1TAdBgNVHREEFjAUghJ0ZXN0LnNtYWxsc3Rl
|
|
cC5jb20wCgYIKoZIzj0EAwIDRwAwRAIgY+nTc+RHn31/BOhht4JpxCmJPHxqFT3S
|
|
ojnictBudV0CIB87ipY5HV3c8FLVEzTA0wFwdDZvQraQYsthwbg2kQFb
|
|
-----END CERTIFICATE-----`
|
|
testSignedCertificate = `-----BEGIN CERTIFICATE-----
|
|
MIIB/DCCAaKgAwIBAgIQHHFuGMz0cClfde5kqP5prTAKBggqhkjOPQQDAjAqMSgw
|
|
JgYDVQQDEx9Hb29nbGUgQ0FTIFRlc3QgSW50ZXJtZWRpYXRlIENBMB4XDTIwMDkx
|
|
NTAwMDQ0M1oXDTMwMDkxMzAwMDQ0MFowHTEbMBkGA1UEAxMSdGVzdC5zbWFsbHN0
|
|
ZXAuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMqNCiXMvbn74LsHzRv+8
|
|
17m9vEzH6RHrg3m82e0uEc36+fZWV/zJ9SKuONmnl5VP79LsjL5SVH0RDj73U2XO
|
|
DKOBtjCBszAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG
|
|
AQUFBwMCMB0GA1UdDgQWBBRTA2cTs7PCNjnps/+T0dS8diqv0DAfBgNVHSMEGDAW
|
|
gBRIOVqyLDSlErJLuWWEvRm5UU1r1TBCBgwrBgEEAYKkZMYoQAIEMjAwEwhjbG91
|
|
ZGNhcxMkZDhkMThhNjgtNTI5Ni00YWYzLWFlNGItMmY4NzdkYTNmYmQ5MAoGCCqG
|
|
SM49BAMCA0gAMEUCIGxl+pqJ50WYWUqK2l4V1FHoXSi0Nht5kwTxFxnWZu1xAiEA
|
|
zemu3bhWLFaGg3s8i+HTEhw4RqkHP74vF7AVYp88bAw=
|
|
-----END CERTIFICATE-----`
|
|
)
|
|
|
|
type testClient struct {
|
|
credentialsFile string
|
|
certificate *pb.Certificate
|
|
certificateAuthority *pb.CertificateAuthority
|
|
err error
|
|
}
|
|
|
|
func newTestClient(credentialsFile string) (CertificateAuthorityClient, error) {
|
|
if credentialsFile == "testdata/error.json" {
|
|
return nil, errTest
|
|
}
|
|
return &testClient{
|
|
credentialsFile: credentialsFile,
|
|
}, nil
|
|
}
|
|
|
|
func okTestClient() *testClient {
|
|
return &testClient{
|
|
credentialsFile: "testdata/credentials.json",
|
|
certificate: &pb.Certificate{
|
|
Name: testCertificateName,
|
|
PemCertificate: testSignedCertificate,
|
|
PemCertificateChain: []string{testIntermediateCertificate, testRootCertificate},
|
|
},
|
|
certificateAuthority: &pb.CertificateAuthority{
|
|
PemCaCertificates: []string{testIntermediateCertificate, testRootCertificate},
|
|
},
|
|
}
|
|
}
|
|
|
|
func failTestClient() *testClient {
|
|
return &testClient{
|
|
credentialsFile: "testdata/credentials.json",
|
|
err: errTest,
|
|
}
|
|
}
|
|
|
|
func badTestClient() *testClient {
|
|
return &testClient{
|
|
credentialsFile: "testdata/credentials.json",
|
|
certificate: &pb.Certificate{
|
|
Name: testCertificateName,
|
|
PemCertificate: "not a pem cert",
|
|
PemCertificateChain: []string{testIntermediateCertificate, testRootCertificate},
|
|
},
|
|
certificateAuthority: &pb.CertificateAuthority{
|
|
PemCaCertificates: []string{testIntermediateCertificate, "not a pem 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 (c *testClient) CreateCertificate(ctx context.Context, req *pb.CreateCertificateRequest, opts ...gax.CallOption) (*pb.Certificate, error) {
|
|
return c.certificate, c.err
|
|
}
|
|
|
|
func (c *testClient) RevokeCertificate(ctx context.Context, req *pb.RevokeCertificateRequest, opts ...gax.CallOption) (*pb.Certificate, error) {
|
|
return c.certificate, c.err
|
|
}
|
|
|
|
func (c *testClient) GetCertificateAuthority(ctx context.Context, req *pb.GetCertificateAuthorityRequest, opts ...gax.CallOption) (*pb.CertificateAuthority, error) {
|
|
return c.certificateAuthority, c.err
|
|
}
|
|
|
|
func mustParseCertificate(t *testing.T, pemCert string) *x509.Certificate {
|
|
t.Helper()
|
|
crt, err := parseCertificate(pemCert)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return crt
|
|
}
|
|
|
|
func TestNew(t *testing.T) {
|
|
tmp := newCertificateAuthorityClient
|
|
newCertificateAuthorityClient = func(ctx context.Context, credentialsFile string) (CertificateAuthorityClient, error) {
|
|
return newTestClient(credentialsFile)
|
|
}
|
|
t.Cleanup(func() {
|
|
newCertificateAuthorityClient = tmp
|
|
})
|
|
|
|
type args struct {
|
|
ctx context.Context
|
|
opts apiv1.Options
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *CloudCAS
|
|
wantErr bool
|
|
}{
|
|
{"ok", args{context.Background(), apiv1.Options{
|
|
Certificateauthority: testAuthorityName,
|
|
}}, &CloudCAS{
|
|
client: &testClient{},
|
|
certificateAuthority: testAuthorityName,
|
|
}, false},
|
|
{"ok with credentials", args{context.Background(), apiv1.Options{
|
|
Certificateauthority: testAuthorityName, CredentialsFile: "testdata/credentials.json",
|
|
}}, &CloudCAS{
|
|
client: &testClient{credentialsFile: "testdata/credentials.json"},
|
|
certificateAuthority: testAuthorityName,
|
|
}, false},
|
|
{"fail certificate authority", args{context.Background(), apiv1.Options{}}, nil, true},
|
|
{"fail with credentials", args{context.Background(), apiv1.Options{
|
|
Certificateauthority: testAuthorityName, CredentialsFile: "testdata/error.json",
|
|
}}, nil, true},
|
|
}
|
|
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) {
|
|
tmp := newCertificateAuthorityClient
|
|
newCertificateAuthorityClient = func(ctx context.Context, credentialsFile string) (CertificateAuthorityClient, error) {
|
|
return newTestClient(credentialsFile)
|
|
}
|
|
t.Cleanup(func() {
|
|
newCertificateAuthorityClient = tmp
|
|
})
|
|
|
|
want := &CloudCAS{
|
|
client: &testClient{credentialsFile: "testdata/credentials.json"},
|
|
certificateAuthority: testAuthorityName,
|
|
}
|
|
|
|
newFn, ok := apiv1.LoadCertificateAuthorityServiceNewFunc(apiv1.CloudCAS)
|
|
if !ok {
|
|
t.Error("apiv1.LoadCertificateAuthorityServiceNewFunc(apiv1.CloudCAS) was not found")
|
|
return
|
|
}
|
|
|
|
got, err := newFn(context.Background(), apiv1.Options{
|
|
Certificateauthority: testAuthorityName, CredentialsFile: "testdata/credentials.json",
|
|
})
|
|
if err != nil {
|
|
t.Errorf("New() error = %v", err)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Errorf("New() = %v, want %v", got, want)
|
|
}
|
|
|
|
}
|
|
|
|
func TestNew_real(t *testing.T) {
|
|
if v, ok := os.LookupEnv("GOOGLE_APPLICATION_CREDENTIALS"); ok {
|
|
os.Unsetenv("GOOGLE_APPLICATION_CREDENTIALS")
|
|
t.Cleanup(func() {
|
|
os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", v)
|
|
})
|
|
}
|
|
|
|
type args struct {
|
|
ctx context.Context
|
|
opts apiv1.Options
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
skipOnCI bool
|
|
args args
|
|
wantErr bool
|
|
}{
|
|
{"fail default credentials", true, args{context.Background(), apiv1.Options{Certificateauthority: testAuthorityName}}, true},
|
|
{"fail certificate authority", false, args{context.Background(), apiv1.Options{}}, true},
|
|
{"fail with credentials", false, args{context.Background(), apiv1.Options{
|
|
Certificateauthority: testAuthorityName, CredentialsFile: "testdata/missing.json",
|
|
}}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.skipOnCI && os.Getenv("CI") == "true" {
|
|
t.SkipNow()
|
|
}
|
|
_, err := New(tt.args.ctx, tt.args.opts)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("New() error = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCloudCAS_GetCertificateAuthority(t *testing.T) {
|
|
root := mustParseCertificate(t, testRootCertificate)
|
|
type fields struct {
|
|
client CertificateAuthorityClient
|
|
certificateAuthority string
|
|
}
|
|
type args struct {
|
|
req *apiv1.GetCertificateAuthorityRequest
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want *apiv1.GetCertificateAuthorityResponse
|
|
wantErr bool
|
|
}{
|
|
{"ok", fields{okTestClient(), testCertificateName}, args{&apiv1.GetCertificateAuthorityRequest{}}, &apiv1.GetCertificateAuthorityResponse{
|
|
RootCertificate: root,
|
|
}, false},
|
|
{"ok with name", fields{okTestClient(), testCertificateName}, args{&apiv1.GetCertificateAuthorityRequest{
|
|
Name: testCertificateName,
|
|
}}, &apiv1.GetCertificateAuthorityResponse{
|
|
RootCertificate: root,
|
|
}, false},
|
|
{"fail GetCertificateAuthority", fields{failTestClient(), testCertificateName}, args{&apiv1.GetCertificateAuthorityRequest{}}, nil, true},
|
|
{"fail bad root", fields{badTestClient(), testCertificateName}, args{&apiv1.GetCertificateAuthorityRequest{}}, nil, true},
|
|
{"fail no pems", fields{&testClient{certificateAuthority: &pb.CertificateAuthority{}}, testCertificateName}, args{&apiv1.GetCertificateAuthorityRequest{}}, nil, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
c := &CloudCAS{
|
|
client: tt.fields.client,
|
|
certificateAuthority: tt.fields.certificateAuthority,
|
|
}
|
|
got, err := c.GetCertificateAuthority(tt.args.req)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("CloudCAS.GetCertificateAuthority() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("CloudCAS.GetCertificateAuthority() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCloudCAS_CreateCertificate(t *testing.T) {
|
|
type fields struct {
|
|
client CertificateAuthorityClient
|
|
certificateAuthority string
|
|
}
|
|
type args struct {
|
|
req *apiv1.CreateCertificateRequest
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want *apiv1.CreateCertificateResponse
|
|
wantErr bool
|
|
}{
|
|
{"ok", fields{okTestClient(), testCertificateName}, args{&apiv1.CreateCertificateRequest{
|
|
Template: mustParseCertificate(t, testLeafCertificate),
|
|
Lifetime: 24 * time.Hour,
|
|
}}, &apiv1.CreateCertificateResponse{
|
|
Certificate: mustParseCertificate(t, testSignedCertificate),
|
|
CertificateChain: []*x509.Certificate{mustParseCertificate(t, testIntermediateCertificate)},
|
|
}, false},
|
|
{"fail Template", fields{okTestClient(), testCertificateName}, args{&apiv1.CreateCertificateRequest{
|
|
Lifetime: 24 * time.Hour,
|
|
}}, nil, true},
|
|
{"fail Lifetime", fields{okTestClient(), testCertificateName}, args{&apiv1.CreateCertificateRequest{
|
|
Template: mustParseCertificate(t, testLeafCertificate),
|
|
}}, nil, true},
|
|
{"fail CreateCertificate", fields{failTestClient(), testCertificateName}, args{&apiv1.CreateCertificateRequest{
|
|
Template: mustParseCertificate(t, testLeafCertificate),
|
|
Lifetime: 24 * time.Hour,
|
|
}}, nil, true},
|
|
{"fail Certificate", fields{badTestClient(), testCertificateName}, args{&apiv1.CreateCertificateRequest{
|
|
Template: mustParseCertificate(t, testLeafCertificate),
|
|
Lifetime: 24 * time.Hour,
|
|
}}, nil, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
c := &CloudCAS{
|
|
client: tt.fields.client,
|
|
certificateAuthority: tt.fields.certificateAuthority,
|
|
}
|
|
got, err := c.CreateCertificate(tt.args.req)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("CloudCAS.CreateCertificate() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("CloudCAS.CreateCertificate() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCloudCAS_createCertificate(t *testing.T) {
|
|
leaf := mustParseCertificate(t, testLeafCertificate)
|
|
signed := mustParseCertificate(t, testSignedCertificate)
|
|
chain := []*x509.Certificate{mustParseCertificate(t, testIntermediateCertificate)}
|
|
|
|
type fields struct {
|
|
client CertificateAuthorityClient
|
|
certificateAuthority string
|
|
}
|
|
type args struct {
|
|
tpl *x509.Certificate
|
|
lifetime time.Duration
|
|
requestID string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want *x509.Certificate
|
|
want1 []*x509.Certificate
|
|
wantErr bool
|
|
}{
|
|
{"ok", fields{okTestClient(), testAuthorityName}, args{leaf, 24 * time.Hour, "request-id"}, signed, chain, false},
|
|
{"fail CertificateConfig", fields{okTestClient(), testAuthorityName}, args{&x509.Certificate{}, 24 * time.Hour, "request-id"}, nil, nil, true},
|
|
{"fail CreateCertificate", fields{failTestClient(), testAuthorityName}, args{leaf, 24 * time.Hour, "request-id"}, nil, nil, true},
|
|
{"fail ParseCertificates", fields{badTestClient(), testAuthorityName}, args{leaf, 24 * time.Hour, "request-id"}, nil, nil, true},
|
|
{"fail create id", fields{okTestClient(), testAuthorityName}, args{leaf, 24 * time.Hour, "request-id"}, nil, nil, true},
|
|
}
|
|
|
|
// Pre-calculate rand.Random
|
|
buf := new(bytes.Buffer)
|
|
setTeeReader(t, buf)
|
|
for i := 0; i < len(tests)-1; i++ {
|
|
_, err := uuid.NewRandomFromReader(rand.Reader)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
rand.Reader = buf
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
c := &CloudCAS{
|
|
client: tt.fields.client,
|
|
certificateAuthority: tt.fields.certificateAuthority,
|
|
}
|
|
got, got1, err := c.createCertificate(tt.args.tpl, tt.args.lifetime, tt.args.requestID)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("CloudCAS.createCertificate() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("CloudCAS.createCertificate() got = %v, want %v", got, tt.want)
|
|
}
|
|
if !reflect.DeepEqual(got1, tt.want1) {
|
|
t.Errorf("CloudCAS.createCertificate() got1 = %v, want %v", got1, tt.want1)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCloudCAS_RenewCertificate(t *testing.T) {
|
|
type fields struct {
|
|
client CertificateAuthorityClient
|
|
certificateAuthority string
|
|
}
|
|
type args struct {
|
|
req *apiv1.RenewCertificateRequest
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want *apiv1.RenewCertificateResponse
|
|
wantErr bool
|
|
}{
|
|
{"ok", fields{okTestClient(), testCertificateName}, args{&apiv1.RenewCertificateRequest{
|
|
Template: mustParseCertificate(t, testLeafCertificate),
|
|
Lifetime: 24 * time.Hour,
|
|
}}, &apiv1.RenewCertificateResponse{
|
|
Certificate: mustParseCertificate(t, testSignedCertificate),
|
|
CertificateChain: []*x509.Certificate{mustParseCertificate(t, testIntermediateCertificate)},
|
|
}, false},
|
|
{"fail Template", fields{okTestClient(), testCertificateName}, args{&apiv1.RenewCertificateRequest{
|
|
Lifetime: 24 * time.Hour,
|
|
}}, nil, true},
|
|
{"fail Lifetime", fields{okTestClient(), testCertificateName}, args{&apiv1.RenewCertificateRequest{
|
|
Template: mustParseCertificate(t, testLeafCertificate),
|
|
}}, nil, true},
|
|
{"fail CreateCertificate", fields{failTestClient(), testCertificateName}, args{&apiv1.RenewCertificateRequest{
|
|
Template: mustParseCertificate(t, testLeafCertificate),
|
|
Lifetime: 24 * time.Hour,
|
|
}}, nil, true},
|
|
{"fail Certificate", fields{badTestClient(), testCertificateName}, args{&apiv1.RenewCertificateRequest{
|
|
Template: mustParseCertificate(t, testLeafCertificate),
|
|
Lifetime: 24 * time.Hour,
|
|
}}, nil, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
c := &CloudCAS{
|
|
client: tt.fields.client,
|
|
certificateAuthority: tt.fields.certificateAuthority,
|
|
}
|
|
got, err := c.RenewCertificate(tt.args.req)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("CloudCAS.RenewCertificate() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("CloudCAS.RenewCertificate() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCloudCAS_RevokeCertificate(t *testing.T) {
|
|
badExtensionCert := mustParseCertificate(t, testSignedCertificate)
|
|
for i, ext := range badExtensionCert.Extensions {
|
|
if ext.Id.Equal(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 37476, 9000, 64, 2}) {
|
|
badExtensionCert.Extensions[i].Value = []byte("bad-data")
|
|
}
|
|
}
|
|
|
|
type fields struct {
|
|
client CertificateAuthorityClient
|
|
certificateAuthority string
|
|
}
|
|
type args struct {
|
|
req *apiv1.RevokeCertificateRequest
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want *apiv1.RevokeCertificateResponse
|
|
wantErr bool
|
|
}{
|
|
{"ok", fields{okTestClient(), testCertificateName}, args{&apiv1.RevokeCertificateRequest{
|
|
Certificate: mustParseCertificate(t, testSignedCertificate),
|
|
ReasonCode: 1,
|
|
}}, &apiv1.RevokeCertificateResponse{
|
|
Certificate: mustParseCertificate(t, testSignedCertificate),
|
|
CertificateChain: []*x509.Certificate{mustParseCertificate(t, testIntermediateCertificate)},
|
|
}, false},
|
|
{"fail Extension", fields{okTestClient(), testCertificateName}, args{&apiv1.RevokeCertificateRequest{
|
|
Certificate: mustParseCertificate(t, testLeafCertificate),
|
|
ReasonCode: 1,
|
|
}}, nil, true},
|
|
{"fail Extension Value", fields{okTestClient(), testCertificateName}, args{&apiv1.RevokeCertificateRequest{
|
|
Certificate: badExtensionCert,
|
|
ReasonCode: 1,
|
|
}}, nil, true},
|
|
{"fail Certificate", fields{okTestClient(), testCertificateName}, args{&apiv1.RevokeCertificateRequest{
|
|
ReasonCode: 2,
|
|
}}, nil, true},
|
|
{"fail ReasonCode", fields{okTestClient(), testCertificateName}, args{&apiv1.RevokeCertificateRequest{
|
|
Certificate: mustParseCertificate(t, testSignedCertificate),
|
|
ReasonCode: 100,
|
|
}}, nil, true},
|
|
{"fail ReasonCode 7", fields{okTestClient(), testCertificateName}, args{&apiv1.RevokeCertificateRequest{
|
|
Certificate: mustParseCertificate(t, testSignedCertificate),
|
|
ReasonCode: 7,
|
|
}}, nil, true},
|
|
{"fail ReasonCode 8", fields{okTestClient(), testCertificateName}, args{&apiv1.RevokeCertificateRequest{
|
|
Certificate: mustParseCertificate(t, testSignedCertificate),
|
|
ReasonCode: 8,
|
|
}}, nil, true},
|
|
{"fail RevokeCertificate", fields{failTestClient(), testCertificateName}, args{&apiv1.RevokeCertificateRequest{
|
|
Certificate: mustParseCertificate(t, testSignedCertificate),
|
|
ReasonCode: 1,
|
|
}}, nil, true},
|
|
{"fail ParseCertificate", fields{badTestClient(), testCertificateName}, args{&apiv1.RevokeCertificateRequest{
|
|
Certificate: mustParseCertificate(t, testSignedCertificate),
|
|
ReasonCode: 1,
|
|
}}, nil, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
c := &CloudCAS{
|
|
client: tt.fields.client,
|
|
certificateAuthority: tt.fields.certificateAuthority,
|
|
}
|
|
got, err := c.RevokeCertificate(tt.args.req)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("CloudCAS.RevokeCertificate() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("CloudCAS.RevokeCertificate() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_createCertificateID(t *testing.T) {
|
|
buf := new(bytes.Buffer)
|
|
setTeeReader(t, buf)
|
|
uuid, err := uuid.NewRandomFromReader(rand.Reader)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
rand.Reader = buf
|
|
|
|
tests := []struct {
|
|
name string
|
|
want string
|
|
wantErr bool
|
|
}{
|
|
{"ok", uuid.String(), false},
|
|
{"fail", "", true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := createCertificateID()
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("createCertificateID() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("createCertificateID() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_parseCertificate(t *testing.T) {
|
|
type args struct {
|
|
pemCert string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *x509.Certificate
|
|
wantErr bool
|
|
}{
|
|
{"ok", args{testLeafCertificate}, mustParseCertificate(t, testLeafCertificate), false},
|
|
{"ok intermediate", args{testIntermediateCertificate}, mustParseCertificate(t, testIntermediateCertificate), false},
|
|
{"fail pem", args{"not pem"}, nil, true},
|
|
{"fail parseCertificate", args{"-----BEGIN CERTIFICATE-----\nZm9vYmFyCg==\n-----END CERTIFICATE-----\n"}, nil, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := parseCertificate(tt.args.pemCert)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("parseCertificate() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("parseCertificate() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_getCertificateAndChain(t *testing.T) {
|
|
type args struct {
|
|
certpb *pb.Certificate
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *x509.Certificate
|
|
want1 []*x509.Certificate
|
|
wantErr bool
|
|
}{
|
|
{"ok", args{&pb.Certificate{
|
|
Name: testCertificateName,
|
|
PemCertificate: testSignedCertificate,
|
|
PemCertificateChain: []string{testIntermediateCertificate, testRootCertificate},
|
|
}}, mustParseCertificate(t, testSignedCertificate), []*x509.Certificate{mustParseCertificate(t, testIntermediateCertificate)}, false},
|
|
{"fail PemCertificate", args{&pb.Certificate{
|
|
Name: testCertificateName,
|
|
PemCertificate: "foobar",
|
|
PemCertificateChain: []string{testIntermediateCertificate, testRootCertificate},
|
|
}}, nil, nil, true},
|
|
{"fail PemCertificateChain", args{&pb.Certificate{
|
|
Name: testCertificateName,
|
|
PemCertificate: testSignedCertificate,
|
|
PemCertificateChain: []string{"foobar", testRootCertificate},
|
|
}}, nil, nil, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, got1, err := getCertificateAndChain(tt.args.certpb)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("getCertificateAndChain() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("getCertificateAndChain() got = %v, want %v", got, tt.want)
|
|
}
|
|
if !reflect.DeepEqual(got1, tt.want1) {
|
|
t.Errorf("getCertificateAndChain() got1 = %v, want %v", got1, tt.want1)
|
|
}
|
|
})
|
|
}
|
|
}
|