You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
smallstep-certificates/cas/cloudcas/cloudcas_test.go

736 lines
25 KiB
Go

package cloudcas
import (
"bytes"
"context"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"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)
}
})
}
}
func TestCloudCAS(t *testing.T) {
cas, err := New(context.Background(), apiv1.Options{
Type: "cloudCAS",
CertificateAuthority: "projects/smallstep-cas-test/locations/us-west1",
CredentialsFile: "/Users/mariano/smallstep-cas-test-8a068f3e4540.json",
})
if err != nil {
t.Fatal(err)
}
// resp, err := cas.CreateCertificateAuthority(&apiv1.CreateCertificateAuthorityRequest{
// Type: apiv1.RootCA,
// Template: &x509.Certificate{
// Subject: pkix.Name{
// CommonName: "Test Mariano Root CA",
// },
// BasicConstraintsValid: true,
// IsCA: true,
// MaxPathLen: 1,
// MaxPathLenZero: false,
// KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
// },
// Lifetime: time.Duration(30 * 24 * time.Hour),
// Project: "smallstep-cas-test",
// Location: "us-west1",
// })
// if err != nil {
// t.Fatal(err)
// }
// debug(resp)
resp := &apiv1.CreateCertificateAuthorityResponse{
Name: "projects/smallstep-cas-test/locations/us-west1/certificateAuthorities/9a593da4-61af-4426-a2f8-0650373b9c8e",
}
resp, err = cas.CreateCertificateAuthority(&apiv1.CreateCertificateAuthorityRequest{
Type: apiv1.IntermediateCA,
Template: &x509.Certificate{
Subject: pkix.Name{
Country: []string{"US"},
CommonName: "Test Mariano Intermediate CA",
},
BasicConstraintsValid: true,
IsCA: true,
MaxPathLen: 0,
MaxPathLenZero: true,
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
},
Lifetime: time.Duration(24 * time.Hour),
Parent: resp,
Project: "smallstep-cas-test",
Location: "us-west1",
})
if err != nil {
t.Fatal(err)
}
// debug(resp)
t.Error("foo")
}