fakekms/crypto_key_rpcs.go (139 lines of code) (raw):
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fakekms
import (
"context"
"sort"
"cloud.google.com/go/kms/apiv1/kmspb"
"google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/timestamppb"
)
// CreateCryptoKey fakes a Cloud KMS API function.
func (f *fakeKMS) CreateCryptoKey(ctx context.Context, req *kmspb.CreateCryptoKeyRequest) (*kmspb.CryptoKey, error) {
if err := allowlist("parent", "crypto_key_id", "skip_initial_version_creation",
"crypto_key.purpose", "crypto_key.version_template.algorithm",
"crypto_key.version_template.protection_level").check(req); err != nil {
return nil, err
}
krName, err := parseKeyRingName(req.Parent)
if err != nil {
return nil, err
}
if err := checkID(req.CryptoKeyId); err != nil {
return nil, err
}
name := cryptoKeyName{keyRingName: krName, CryptoKeyID: req.CryptoKeyId}
purpose := req.GetCryptoKey().GetPurpose()
if purpose == kmspb.CryptoKey_CRYPTO_KEY_PURPOSE_UNSPECIFIED {
return nil, errRequiredField("crypto_key.purpose")
}
alg := req.GetCryptoKey().GetVersionTemplate().GetAlgorithm()
if alg == kmspb.CryptoKeyVersion_CRYPTO_KEY_VERSION_ALGORITHM_UNSPECIFIED {
alg = kmspb.CryptoKeyVersion_GOOGLE_SYMMETRIC_ENCRYPTION
}
if err := validateAlgorithm(alg, purpose); err != nil {
return nil, err
}
protLevel := req.GetCryptoKey().GetVersionTemplate().GetProtectionLevel()
if protLevel == kmspb.ProtectionLevel_PROTECTION_LEVEL_UNSPECIFIED {
protLevel = kmspb.ProtectionLevel_SOFTWARE
}
if err := validateProtectionLevel(protLevel); err != nil {
return nil, err
}
kr, ok := f.keyRings[krName]
if !ok {
return nil, errNotFound(krName)
}
if _, ok := kr.keys[name]; ok {
return nil, errAlreadyExists(name)
}
pb := &kmspb.CryptoKey{
Name: name.String(),
CreateTime: timestamppb.Now(),
Purpose: purpose,
VersionTemplate: &kmspb.CryptoKeyVersionTemplate{
ProtectionLevel: protLevel,
Algorithm: alg,
},
DestroyScheduledDuration: &durationpb.Duration{Seconds: 2592000},
}
ck := &cryptoKey{
pb: pb,
versions: make(map[cryptoKeyVersionName]*cryptoKeyVersion),
}
if !req.SkipInitialVersionCreation {
ckv := f.createVersion(ck)
if purpose == kmspb.CryptoKey_ENCRYPT_DECRYPT {
pb.Primary = ckv
}
}
kr.keys[name] = ck
return pb, nil
}
// GetCryptoKey fakes a Cloud KMS API function.
func (f *fakeKMS) GetCryptoKey(ctx context.Context, req *kmspb.GetCryptoKeyRequest) (*kmspb.CryptoKey, error) {
if err := allowlist("name").check(req); err != nil {
return nil, err
}
name, err := parseCryptoKeyName(req.Name)
if err != nil {
return nil, err
}
ck, err := f.cryptoKey(name)
if err != nil {
return nil, err
}
return ck.pb, nil
}
// ListCryptoKeys fakes a Cloud KMS API function.
func (f *fakeKMS) ListCryptoKeys(ctx context.Context, req *kmspb.ListCryptoKeysRequest) (*kmspb.ListCryptoKeysResponse, error) {
if err := allowlist("parent").check(req); err != nil {
return nil, err
}
parent, err := parseKeyRingName(req.Parent)
if err != nil {
return nil, err
}
kr, ok := f.keyRings[parent]
if !ok {
return nil, errNotFound(parent)
}
r := make([]*kmspb.CryptoKey, 0, len(kr.keys))
for _, ck := range kr.keys {
r = append(r, ck.pb)
}
if len(r) > maxPageSize {
return nil, errMaxPageSize(len(r))
}
sort.Slice(r, func(i, j int) bool {
return r[i].Name < r[j].Name
})
return &kmspb.ListCryptoKeysResponse{
CryptoKeys: r,
TotalSize: int32(len(r)),
}, nil
}
// UpdateCryptoKey fakes a Cloud KMS API function.
func (f *fakeKMS) UpdateCryptoKey(ctx context.Context, req *kmspb.UpdateCryptoKeyRequest) (*kmspb.CryptoKey, error) {
if err := allowlist("crypto_key", "update_mask").check(req); err != nil {
return nil, err
}
if len(req.UpdateMask.GetPaths()) == 0 {
return nil, errInvalidArgument("no fields selected for update")
}
name, err := parseCryptoKeyName(req.CryptoKey.Name)
if err != nil {
return nil, err
}
ck, err := f.cryptoKey(name)
if err != nil {
return nil, err
}
for _, p := range req.UpdateMask.Paths {
switch p {
case "version_template.algorithm":
if err := validateAlgorithm(req.CryptoKey.VersionTemplate.Algorithm, ck.pb.Purpose); err != nil {
return nil, err
}
ck.pb.VersionTemplate.Algorithm = req.CryptoKey.VersionTemplate.Algorithm
default:
return nil, errInvalidArgument("unsupported update path: %s", p)
}
}
return ck.pb, nil
}