forked from TrueCloudLab/certificates
Add tests for cloudkms.
This commit is contained in:
parent
264179cda3
commit
dff498f17f
6 changed files with 555 additions and 5 deletions
|
@ -107,8 +107,7 @@ func (k *CloudKMS) CreateSigner(req *apiv1.CreateSignerRequest) (crypto.Signer,
|
|||
|
||||
// CreateKey creates in Google's Cloud KMS a new asymmetric key for signing.
|
||||
func (k *CloudKMS) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyResponse, error) {
|
||||
switch {
|
||||
case req.Name == "":
|
||||
if req.Name == "" {
|
||||
return nil, errors.New("createKeyRequest 'name' cannot be empty")
|
||||
}
|
||||
|
||||
|
@ -137,7 +136,7 @@ func (k *CloudKMS) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyRespo
|
|||
|
||||
// Split `projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys/KEY_ID`
|
||||
// to `projects/PROJECT_ID/locations/global/keyRings/RING_ID` and `KEY_ID`.
|
||||
keyRing, keyId := Parent(req.Name)
|
||||
keyRing, keyID := Parent(req.Name)
|
||||
if err := k.createKeyRingIfNeeded(keyRing); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -148,7 +147,7 @@ func (k *CloudKMS) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyRespo
|
|||
// Create private key in CloudKMS.
|
||||
response, err := k.client.CreateCryptoKey(ctx, &kmspb.CreateCryptoKeyRequest{
|
||||
Parent: keyRing,
|
||||
CryptoKeyId: keyId,
|
||||
CryptoKeyId: keyID,
|
||||
CryptoKey: &kmspb.CryptoKey{
|
||||
Purpose: kmspb.CryptoKey_ASYMMETRIC_SIGN,
|
||||
VersionTemplate: &kmspb.CryptoKeyVersionTemplate{
|
||||
|
@ -224,6 +223,10 @@ func (k *CloudKMS) createKeyRingIfNeeded(name string) error {
|
|||
// follow the pattern:
|
||||
// projects/([^/]+)/locations/([a-zA-Z0-9_-]{1,63})/keyRings/([a-zA-Z0-9_-]{1,63})/cryptoKeys/([a-zA-Z0-9_-]{1,63})/cryptoKeyVersions/([a-zA-Z0-9_-]{1,63})
|
||||
func (k *CloudKMS) GetPublicKey(req *apiv1.GetPublicKeyRequest) (crypto.PublicKey, error) {
|
||||
if req.Name == "" {
|
||||
return nil, errors.New("createKeyRequest 'name' cannot be empty")
|
||||
}
|
||||
|
||||
ctx, cancel := defaultContext()
|
||||
defer cancel()
|
||||
|
||||
|
|
350
kms/cloudkms/cloudkms_test.go
Normal file
350
kms/cloudkms/cloudkms_test.go
Normal file
|
@ -0,0 +1,350 @@
|
|||
package cloudkms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
gax "github.com/googleapis/gax-go/v2"
|
||||
"github.com/smallstep/certificates/kms/apiv1"
|
||||
"github.com/smallstep/cli/crypto/pemutil"
|
||||
kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func TestParent(t *testing.T) {
|
||||
type args struct {
|
||||
name string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
want1 string
|
||||
}{
|
||||
{"zero", args{"child"}, "", "child"},
|
||||
{"one", args{"parent/child"}, "", "child"},
|
||||
{"two", args{"grandparent/parent/child"}, "grandparent", "child"},
|
||||
{"three", args{"great-grandparent/grandparent/parent/child"}, "great-grandparent/grandparent", "child"},
|
||||
{"empty", args{""}, "", ""},
|
||||
{"root", args{"/"}, "", ""},
|
||||
{"child", args{"/child"}, "", "child"},
|
||||
{"parent", args{"parent/"}, "", ""},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, got1 := Parent(tt.args.name)
|
||||
if got != tt.want {
|
||||
t.Errorf("Parent() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
if got1 != tt.want1 {
|
||||
t.Errorf("Parent() got1 = %v, want %v", got1, tt.want1)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
opts apiv1.Options
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *CloudKMS
|
||||
wantErr bool
|
||||
}{
|
||||
{"fail authentication", args{context.Background(), apiv1.Options{}}, nil, true},
|
||||
{"fail credentials", args{context.Background(), apiv1.Options{CredentialsFile: "testdata/missing"}}, 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 TestCloudKMS_Close(t *testing.T) {
|
||||
type fields struct {
|
||||
client keyManagementClient
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
wantErr bool
|
||||
}{
|
||||
{"ok", fields{&MockClient{close: func() error { return nil }}}, false},
|
||||
{"fail", fields{&MockClient{close: func() error { return fmt.Errorf("an error") }}}, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
k := &CloudKMS{
|
||||
client: tt.fields.client,
|
||||
}
|
||||
if err := k.Close(); (err != nil) != tt.wantErr {
|
||||
t.Errorf("CloudKMS.Close() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudKMS_CreateSigner(t *testing.T) {
|
||||
keyName := "projects/p/locations/l/keyRings/k/cryptoKeys/c/cryptoKeyVersions/1"
|
||||
type fields struct {
|
||||
client keyManagementClient
|
||||
}
|
||||
type args struct {
|
||||
req *apiv1.CreateSignerRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want crypto.Signer
|
||||
wantErr bool
|
||||
}{
|
||||
{"ok", fields{&MockClient{}}, args{&apiv1.CreateSignerRequest{SigningKey: keyName}}, &signer{client: &MockClient{}, signingKey: keyName}, false},
|
||||
{"fail", fields{&MockClient{}}, args{&apiv1.CreateSignerRequest{SigningKey: ""}}, nil, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
k := &CloudKMS{
|
||||
client: tt.fields.client,
|
||||
}
|
||||
got, err := k.CreateSigner(tt.args.req)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("CloudKMS.CreateSigner() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("CloudKMS.CreateSigner() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudKMS_CreateKey(t *testing.T) {
|
||||
keyName := "projects/p/locations/l/keyRings/k/cryptoKeys/c"
|
||||
testError := fmt.Errorf("an error")
|
||||
alreadyExists := status.Error(codes.AlreadyExists, "already exists")
|
||||
|
||||
pemBytes, err := ioutil.ReadFile("testdata/pub.pem")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pk, err := pemutil.ParseKey(pemBytes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
type fields struct {
|
||||
client keyManagementClient
|
||||
}
|
||||
type args struct {
|
||||
req *apiv1.CreateKeyRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want *apiv1.CreateKeyResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{"ok", fields{
|
||||
&MockClient{
|
||||
getKeyRing: func(_ context.Context, _ *kmspb.GetKeyRingRequest, _ ...gax.CallOption) (*kmspb.KeyRing, error) {
|
||||
return &kmspb.KeyRing{}, nil
|
||||
},
|
||||
createCryptoKey: func(_ context.Context, _ *kmspb.CreateCryptoKeyRequest, _ ...gax.CallOption) (*kmspb.CryptoKey, error) {
|
||||
return &kmspb.CryptoKey{Name: keyName}, nil
|
||||
},
|
||||
getPublicKey: func(_ context.Context, _ *kmspb.GetPublicKeyRequest, _ ...gax.CallOption) (*kmspb.PublicKey, error) {
|
||||
return &kmspb.PublicKey{Pem: string(pemBytes)}, nil
|
||||
},
|
||||
}},
|
||||
args{&apiv1.CreateKeyRequest{Name: keyName, ProtectionLevel: apiv1.HSM, SignatureAlgorithm: apiv1.ECDSAWithSHA256}},
|
||||
&apiv1.CreateKeyResponse{Name: keyName + "/cryptoKeyVersions/1", PublicKey: pk, CreateSignerRequest: apiv1.CreateSignerRequest{SigningKey: keyName + "/cryptoKeyVersions/1"}}, false},
|
||||
{"ok new key ring", fields{
|
||||
&MockClient{
|
||||
getKeyRing: func(_ context.Context, _ *kmspb.GetKeyRingRequest, _ ...gax.CallOption) (*kmspb.KeyRing, error) {
|
||||
return nil, testError
|
||||
},
|
||||
createKeyRing: func(_ context.Context, _ *kmspb.CreateKeyRingRequest, _ ...gax.CallOption) (*kmspb.KeyRing, error) {
|
||||
return nil, alreadyExists
|
||||
},
|
||||
createCryptoKey: func(_ context.Context, _ *kmspb.CreateCryptoKeyRequest, _ ...gax.CallOption) (*kmspb.CryptoKey, error) {
|
||||
return &kmspb.CryptoKey{Name: keyName}, nil
|
||||
},
|
||||
getPublicKey: func(_ context.Context, _ *kmspb.GetPublicKeyRequest, _ ...gax.CallOption) (*kmspb.PublicKey, error) {
|
||||
return &kmspb.PublicKey{Pem: string(pemBytes)}, nil
|
||||
},
|
||||
}},
|
||||
args{&apiv1.CreateKeyRequest{Name: keyName, ProtectionLevel: apiv1.Software, SignatureAlgorithm: apiv1.SHA256WithRSA, Bits: 3072}},
|
||||
&apiv1.CreateKeyResponse{Name: keyName + "/cryptoKeyVersions/1", PublicKey: pk, CreateSignerRequest: apiv1.CreateSignerRequest{SigningKey: keyName + "/cryptoKeyVersions/1"}}, false},
|
||||
{"ok new key version", fields{
|
||||
&MockClient{
|
||||
getKeyRing: func(_ context.Context, _ *kmspb.GetKeyRingRequest, _ ...gax.CallOption) (*kmspb.KeyRing, error) {
|
||||
return &kmspb.KeyRing{}, nil
|
||||
},
|
||||
createCryptoKey: func(_ context.Context, _ *kmspb.CreateCryptoKeyRequest, _ ...gax.CallOption) (*kmspb.CryptoKey, error) {
|
||||
return nil, alreadyExists
|
||||
},
|
||||
createCryptoKeyVersion: func(_ context.Context, _ *kmspb.CreateCryptoKeyVersionRequest, _ ...gax.CallOption) (*kmspb.CryptoKeyVersion, error) {
|
||||
return &kmspb.CryptoKeyVersion{Name: keyName + "/cryptoKeyVersions/2"}, nil
|
||||
},
|
||||
getPublicKey: func(_ context.Context, _ *kmspb.GetPublicKeyRequest, _ ...gax.CallOption) (*kmspb.PublicKey, error) {
|
||||
return &kmspb.PublicKey{Pem: string(pemBytes)}, nil
|
||||
},
|
||||
}},
|
||||
args{&apiv1.CreateKeyRequest{Name: keyName, ProtectionLevel: apiv1.HSM, SignatureAlgorithm: apiv1.ECDSAWithSHA256}},
|
||||
&apiv1.CreateKeyResponse{Name: keyName + "/cryptoKeyVersions/2", PublicKey: pk, CreateSignerRequest: apiv1.CreateSignerRequest{SigningKey: keyName + "/cryptoKeyVersions/2"}}, false},
|
||||
{"fail name", fields{&MockClient{}}, args{&apiv1.CreateKeyRequest{}}, nil, true},
|
||||
{"fail protection level", fields{&MockClient{}}, args{&apiv1.CreateKeyRequest{Name: keyName, ProtectionLevel: apiv1.ProtectionLevel(100)}}, nil, true},
|
||||
{"fail signature algorithm", fields{&MockClient{}}, args{&apiv1.CreateKeyRequest{Name: keyName, ProtectionLevel: apiv1.Software, SignatureAlgorithm: apiv1.SignatureAlgorithm(100)}}, nil, true},
|
||||
{"fail number of bits", fields{&MockClient{}}, args{&apiv1.CreateKeyRequest{Name: keyName, ProtectionLevel: apiv1.Software, SignatureAlgorithm: apiv1.SHA256WithRSA, Bits: 1024}},
|
||||
nil, true},
|
||||
{"fail create key ring", fields{
|
||||
&MockClient{
|
||||
getKeyRing: func(_ context.Context, _ *kmspb.GetKeyRingRequest, _ ...gax.CallOption) (*kmspb.KeyRing, error) {
|
||||
return nil, testError
|
||||
},
|
||||
createKeyRing: func(_ context.Context, _ *kmspb.CreateKeyRingRequest, _ ...gax.CallOption) (*kmspb.KeyRing, error) {
|
||||
return nil, testError
|
||||
},
|
||||
}},
|
||||
args{&apiv1.CreateKeyRequest{Name: keyName, ProtectionLevel: apiv1.HSM, SignatureAlgorithm: apiv1.ECDSAWithSHA256}},
|
||||
nil, true},
|
||||
{"fail create key", fields{
|
||||
&MockClient{
|
||||
getKeyRing: func(_ context.Context, _ *kmspb.GetKeyRingRequest, _ ...gax.CallOption) (*kmspb.KeyRing, error) {
|
||||
return &kmspb.KeyRing{}, nil
|
||||
},
|
||||
createCryptoKey: func(_ context.Context, _ *kmspb.CreateCryptoKeyRequest, _ ...gax.CallOption) (*kmspb.CryptoKey, error) {
|
||||
return nil, testError
|
||||
},
|
||||
}},
|
||||
args{&apiv1.CreateKeyRequest{Name: keyName, ProtectionLevel: apiv1.HSM, SignatureAlgorithm: apiv1.ECDSAWithSHA256}},
|
||||
nil, true},
|
||||
{"fail create key version", fields{
|
||||
&MockClient{
|
||||
getKeyRing: func(_ context.Context, _ *kmspb.GetKeyRingRequest, _ ...gax.CallOption) (*kmspb.KeyRing, error) {
|
||||
return &kmspb.KeyRing{}, nil
|
||||
},
|
||||
createCryptoKey: func(_ context.Context, _ *kmspb.CreateCryptoKeyRequest, _ ...gax.CallOption) (*kmspb.CryptoKey, error) {
|
||||
return nil, alreadyExists
|
||||
},
|
||||
createCryptoKeyVersion: func(_ context.Context, _ *kmspb.CreateCryptoKeyVersionRequest, _ ...gax.CallOption) (*kmspb.CryptoKeyVersion, error) {
|
||||
return nil, testError
|
||||
},
|
||||
}},
|
||||
args{&apiv1.CreateKeyRequest{Name: keyName, ProtectionLevel: apiv1.HSM, SignatureAlgorithm: apiv1.ECDSAWithSHA256}},
|
||||
nil, true},
|
||||
{"fail get public key", fields{
|
||||
&MockClient{
|
||||
getKeyRing: func(_ context.Context, _ *kmspb.GetKeyRingRequest, _ ...gax.CallOption) (*kmspb.KeyRing, error) {
|
||||
return &kmspb.KeyRing{}, nil
|
||||
},
|
||||
createCryptoKey: func(_ context.Context, _ *kmspb.CreateCryptoKeyRequest, _ ...gax.CallOption) (*kmspb.CryptoKey, error) {
|
||||
return &kmspb.CryptoKey{Name: keyName}, nil
|
||||
},
|
||||
getPublicKey: func(_ context.Context, _ *kmspb.GetPublicKeyRequest, _ ...gax.CallOption) (*kmspb.PublicKey, error) {
|
||||
return nil, testError
|
||||
},
|
||||
}},
|
||||
args{&apiv1.CreateKeyRequest{Name: keyName, ProtectionLevel: apiv1.HSM, SignatureAlgorithm: apiv1.ECDSAWithSHA256}},
|
||||
nil, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
k := &CloudKMS{
|
||||
client: tt.fields.client,
|
||||
}
|
||||
got, err := k.CreateKey(tt.args.req)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("CloudKMS.CreateKey() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("CloudKMS.CreateKey() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudKMS_GetPublicKey(t *testing.T) {
|
||||
keyName := "projects/p/locations/l/keyRings/k/cryptoKeys/c/cryptoKeyVersions/1"
|
||||
testError := fmt.Errorf("an error")
|
||||
|
||||
pemBytes, err := ioutil.ReadFile("testdata/pub.pem")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pk, err := pemutil.ParseKey(pemBytes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
type fields struct {
|
||||
client keyManagementClient
|
||||
}
|
||||
type args struct {
|
||||
req *apiv1.GetPublicKeyRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want crypto.PublicKey
|
||||
wantErr bool
|
||||
}{
|
||||
{"ok", fields{
|
||||
&MockClient{
|
||||
getPublicKey: func(_ context.Context, _ *kmspb.GetPublicKeyRequest, _ ...gax.CallOption) (*kmspb.PublicKey, error) {
|
||||
return &kmspb.PublicKey{Pem: string(pemBytes)}, nil
|
||||
},
|
||||
}},
|
||||
args{&apiv1.GetPublicKeyRequest{Name: keyName}}, pk, false},
|
||||
{"fail name", fields{&MockClient{}}, args{&apiv1.GetPublicKeyRequest{}}, nil, true},
|
||||
{"fail get public key", fields{
|
||||
&MockClient{
|
||||
getPublicKey: func(_ context.Context, _ *kmspb.GetPublicKeyRequest, _ ...gax.CallOption) (*kmspb.PublicKey, error) {
|
||||
return nil, testError
|
||||
},
|
||||
}},
|
||||
args{&apiv1.GetPublicKeyRequest{Name: keyName}}, nil, true},
|
||||
{"fail parse pem", fields{
|
||||
&MockClient{
|
||||
getPublicKey: func(_ context.Context, _ *kmspb.GetPublicKeyRequest, _ ...gax.CallOption) (*kmspb.PublicKey, error) {
|
||||
return &kmspb.PublicKey{Pem: string("bad pem")}, nil
|
||||
},
|
||||
}},
|
||||
args{&apiv1.GetPublicKeyRequest{Name: keyName}}, nil, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
k := &CloudKMS{
|
||||
client: tt.fields.client,
|
||||
}
|
||||
got, err := k.GetPublicKey(tt.args.req)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("CloudKMS.GetPublicKey() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("CloudKMS.GetPublicKey() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
46
kms/cloudkms/mock_test.go
Normal file
46
kms/cloudkms/mock_test.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
package cloudkms
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
gax "github.com/googleapis/gax-go/v2"
|
||||
kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
|
||||
)
|
||||
|
||||
type MockClient struct {
|
||||
close func() error
|
||||
getPublicKey func(context.Context, *kmspb.GetPublicKeyRequest, ...gax.CallOption) (*kmspb.PublicKey, error)
|
||||
asymmetricSign func(context.Context, *kmspb.AsymmetricSignRequest, ...gax.CallOption) (*kmspb.AsymmetricSignResponse, error)
|
||||
createCryptoKey func(context.Context, *kmspb.CreateCryptoKeyRequest, ...gax.CallOption) (*kmspb.CryptoKey, error)
|
||||
getKeyRing func(context.Context, *kmspb.GetKeyRingRequest, ...gax.CallOption) (*kmspb.KeyRing, error)
|
||||
createKeyRing func(context.Context, *kmspb.CreateKeyRingRequest, ...gax.CallOption) (*kmspb.KeyRing, error)
|
||||
createCryptoKeyVersion func(context.Context, *kmspb.CreateCryptoKeyVersionRequest, ...gax.CallOption) (*kmspb.CryptoKeyVersion, error)
|
||||
}
|
||||
|
||||
func (m *MockClient) Close() error {
|
||||
return m.close()
|
||||
}
|
||||
|
||||
func (m *MockClient) GetPublicKey(ctx context.Context, req *kmspb.GetPublicKeyRequest, opts ...gax.CallOption) (*kmspb.PublicKey, error) {
|
||||
return m.getPublicKey(ctx, req, opts...)
|
||||
}
|
||||
|
||||
func (m *MockClient) AsymmetricSign(ctx context.Context, req *kmspb.AsymmetricSignRequest, opts ...gax.CallOption) (*kmspb.AsymmetricSignResponse, error) {
|
||||
return m.asymmetricSign(ctx, req, opts...)
|
||||
}
|
||||
|
||||
func (m *MockClient) CreateCryptoKey(ctx context.Context, req *kmspb.CreateCryptoKeyRequest, opts ...gax.CallOption) (*kmspb.CryptoKey, error) {
|
||||
return m.createCryptoKey(ctx, req, opts...)
|
||||
}
|
||||
|
||||
func (m *MockClient) GetKeyRing(ctx context.Context, req *kmspb.GetKeyRingRequest, opts ...gax.CallOption) (*kmspb.KeyRing, error) {
|
||||
return m.getKeyRing(ctx, req, opts...)
|
||||
}
|
||||
|
||||
func (m *MockClient) CreateKeyRing(ctx context.Context, req *kmspb.CreateKeyRingRequest, opts ...gax.CallOption) (*kmspb.KeyRing, error) {
|
||||
return m.createKeyRing(ctx, req, opts...)
|
||||
}
|
||||
|
||||
func (m *MockClient) CreateCryptoKeyVersion(ctx context.Context, req *kmspb.CreateCryptoKeyVersionRequest, opts ...gax.CallOption) (*kmspb.CryptoKeyVersion, error) {
|
||||
return m.createCryptoKeyVersion(ctx, req, opts...)
|
||||
}
|
|
@ -36,7 +36,6 @@ func (s *signer) Public() crypto.PublicKey {
|
|||
|
||||
pk, err := pemutil.ParseKey([]byte(response.Pem))
|
||||
if err != nil {
|
||||
println(2, err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
148
kms/cloudkms/signer_test.go
Normal file
148
kms/cloudkms/signer_test.go
Normal file
|
@ -0,0 +1,148 @@
|
|||
package cloudkms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
gax "github.com/googleapis/gax-go/v2"
|
||||
"github.com/smallstep/cli/crypto/pemutil"
|
||||
kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
|
||||
)
|
||||
|
||||
func Test_newSigner(t *testing.T) {
|
||||
type args struct {
|
||||
c keyManagementClient
|
||||
signingKey string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *signer
|
||||
}{
|
||||
{"ok", args{&MockClient{}, "signingKey"}, &signer{client: &MockClient{}, signingKey: "signingKey"}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := newSigner(tt.args.c, tt.args.signingKey); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("newSigner() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_signer_Public(t *testing.T) {
|
||||
keyName := "projects/p/locations/l/keyRings/k/cryptoKeys/c/cryptoKeyVersions/1"
|
||||
testError := fmt.Errorf("an error")
|
||||
|
||||
pemBytes, err := ioutil.ReadFile("testdata/pub.pem")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pk, err := pemutil.ParseKey(pemBytes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
type fields struct {
|
||||
client keyManagementClient
|
||||
signingKey string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want crypto.PublicKey
|
||||
wantErr bool
|
||||
}{
|
||||
{"ok", fields{&MockClient{
|
||||
getPublicKey: func(_ context.Context, _ *kmspb.GetPublicKeyRequest, _ ...gax.CallOption) (*kmspb.PublicKey, error) {
|
||||
return &kmspb.PublicKey{Pem: string(pemBytes)}, nil
|
||||
},
|
||||
}, keyName}, pk, false},
|
||||
{"fail get public key", fields{&MockClient{
|
||||
getPublicKey: func(_ context.Context, _ *kmspb.GetPublicKeyRequest, _ ...gax.CallOption) (*kmspb.PublicKey, error) {
|
||||
return nil, testError
|
||||
},
|
||||
}, keyName}, nil, true},
|
||||
{"fail parse pem", fields{
|
||||
&MockClient{
|
||||
getPublicKey: func(_ context.Context, _ *kmspb.GetPublicKeyRequest, _ ...gax.CallOption) (*kmspb.PublicKey, error) {
|
||||
return &kmspb.PublicKey{Pem: string("bad pem")}, nil
|
||||
},
|
||||
}, keyName}, nil, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := &signer{
|
||||
client: tt.fields.client,
|
||||
signingKey: tt.fields.signingKey,
|
||||
}
|
||||
got := s.Public()
|
||||
if _, ok := got.(error); ok != tt.wantErr {
|
||||
t.Errorf("signer.Public() error = %v, wantErr %v", got, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !tt.wantErr && !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("signer.Public() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_signer_Sign(t *testing.T) {
|
||||
keyName := "projects/p/locations/l/keyRings/k/cryptoKeys/c/cryptoKeyVersions/1"
|
||||
okClient := &MockClient{
|
||||
asymmetricSign: func(_ context.Context, _ *kmspb.AsymmetricSignRequest, _ ...gax.CallOption) (*kmspb.AsymmetricSignResponse, error) {
|
||||
return &kmspb.AsymmetricSignResponse{Signature: []byte("ok signature")}, nil
|
||||
},
|
||||
}
|
||||
failClient := &MockClient{
|
||||
asymmetricSign: func(_ context.Context, _ *kmspb.AsymmetricSignRequest, _ ...gax.CallOption) (*kmspb.AsymmetricSignResponse, error) {
|
||||
return nil, fmt.Errorf("an error")
|
||||
},
|
||||
}
|
||||
|
||||
type fields struct {
|
||||
client keyManagementClient
|
||||
signingKey string
|
||||
}
|
||||
type args struct {
|
||||
rand io.Reader
|
||||
digest []byte
|
||||
opts crypto.SignerOpts
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want []byte
|
||||
wantErr bool
|
||||
}{
|
||||
{"ok sha256", fields{okClient, keyName}, args{rand.Reader, []byte("digest"), crypto.SHA256}, []byte("ok signature"), false},
|
||||
{"ok sha384", fields{okClient, keyName}, args{rand.Reader, []byte("digest"), crypto.SHA384}, []byte("ok signature"), false},
|
||||
{"ok sha512", fields{okClient, keyName}, args{rand.Reader, []byte("digest"), crypto.SHA512}, []byte("ok signature"), false},
|
||||
{"fail MD5", fields{okClient, keyName}, args{rand.Reader, []byte("digest"), crypto.MD5}, nil, true},
|
||||
{"fail asymmetric sign", fields{failClient, keyName}, args{rand.Reader, []byte("digest"), crypto.SHA256}, nil, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := &signer{
|
||||
client: tt.fields.client,
|
||||
signingKey: tt.fields.signingKey,
|
||||
}
|
||||
got, err := s.Sign(tt.args.rand, tt.args.digest, tt.args.opts)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("signer.Sign() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("signer.Sign() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
4
kms/cloudkms/testdata/pub.pem
vendored
Normal file
4
kms/cloudkms/testdata/pub.pem
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5VPD/W5RXn0lrs2MdoNteTSZ+sh1
|
||||
veT13hakPZF9YzaNVZgujqK3d1nt+4jPECU+ED/WQ1GgFZiVGUo3flvB/w==
|
||||
-----END PUBLIC KEY-----
|
Loading…
Reference in a new issue