1// Copyright 2017 Google Inc. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14// 15//////////////////////////////////////////////////////////////////////////////// 16 17// Package gcpkms provides integration with the GCP Cloud KMS. 18// Tink APIs work with GCP and AWS KMS. 19package gcpkms 20 21import ( 22 "context" 23 "errors" 24 "fmt" 25 "runtime" 26 "strings" 27 28 "google.golang.org/api/cloudkms/v1" 29 "google.golang.org/api/option" 30 "github.com/google/tink/go/core/registry" 31 "github.com/google/tink/go/tink" 32) 33 34const ( 35 gcpPrefix = "gcp-kms://" 36) 37 38var ( 39 errCred = errors.New("invalid credential path") 40 tinkUserAgent = "Tink/" + tink.Version + " Golang/" + runtime.Version() 41) 42 43// gcpClient represents a client that connects to the GCP KMS backend. 44type gcpClient struct { 45 keyURIPrefix string 46 kms *cloudkms.Service 47} 48 49var _ registry.KMSClient = (*gcpClient)(nil) 50 51// NewClientWithOptions returns a new GCP KMS client with provided Google API 52// options to handle keys with uriPrefix prefix. 53// uriPrefix must have the following format: 'gcp-kms://[:path]'. 54func NewClientWithOptions(ctx context.Context, uriPrefix string, opts ...option.ClientOption) (registry.KMSClient, error) { 55 if !strings.HasPrefix(strings.ToLower(uriPrefix), gcpPrefix) { 56 return nil, fmt.Errorf("uriPrefix must start with %s", gcpPrefix) 57 } 58 59 opts = append(opts, option.WithUserAgent(tinkUserAgent)) 60 kmsService, err := cloudkms.NewService(ctx, opts...) 61 if err != nil { 62 return nil, err 63 } 64 65 return &gcpClient{ 66 keyURIPrefix: uriPrefix, 67 kms: kmsService, 68 }, nil 69} 70 71// Supported true if this client does support keyURI 72func (c *gcpClient) Supported(keyURI string) bool { 73 return strings.HasPrefix(keyURI, c.keyURIPrefix) 74} 75 76// GetAEAD gets an AEAD backend by keyURI. 77func (c *gcpClient) GetAEAD(keyURI string) (tink.AEAD, error) { 78 if !c.Supported(keyURI) { 79 return nil, errors.New("unsupported keyURI") 80 } 81 82 uri := strings.TrimPrefix(keyURI, gcpPrefix) 83 return newGCPAEAD(uri, c.kms), nil 84} 85