1*e7b1675dSTing-Kang Chang// Copyright 2022 Google LLC 2*e7b1675dSTing-Kang Chang// 3*e7b1675dSTing-Kang Chang// Licensed under the Apache License, Version 2.0 (the "License"); 4*e7b1675dSTing-Kang Chang// you may not use this file except in compliance with the License. 5*e7b1675dSTing-Kang Chang// You may obtain a copy of the License at 6*e7b1675dSTing-Kang Chang// 7*e7b1675dSTing-Kang Chang// http://www.apache.org/licenses/LICENSE-2.0 8*e7b1675dSTing-Kang Chang// 9*e7b1675dSTing-Kang Chang// Unless required by applicable law or agreed to in writing, software 10*e7b1675dSTing-Kang Chang// distributed under the License is distributed on an "AS IS" BASIS, 11*e7b1675dSTing-Kang Chang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*e7b1675dSTing-Kang Chang// See the License for the specific language governing permissions and 13*e7b1675dSTing-Kang Chang// limitations under the License. 14*e7b1675dSTing-Kang Chang// 15*e7b1675dSTing-Kang Chang//////////////////////////////////////////////////////////////////////////////// 16*e7b1675dSTing-Kang Chang 17*e7b1675dSTing-Kang Changpackage internalregistry 18*e7b1675dSTing-Kang Chang 19*e7b1675dSTing-Kang Changimport ( 20*e7b1675dSTing-Kang Chang "fmt" 21*e7b1675dSTing-Kang Chang "io" 22*e7b1675dSTing-Kang Chang "sync" 23*e7b1675dSTing-Kang Chang 24*e7b1675dSTing-Kang Chang "google.golang.org/protobuf/proto" 25*e7b1675dSTing-Kang Chang "github.com/google/tink/go/core/registry" 26*e7b1675dSTing-Kang Chang tinkpb "github.com/google/tink/go/proto/tink_go_proto" 27*e7b1675dSTing-Kang Chang) 28*e7b1675dSTing-Kang Chang 29*e7b1675dSTing-Kang Changvar ( 30*e7b1675dSTing-Kang Chang derivableKeyManagersMu sync.RWMutex 31*e7b1675dSTing-Kang Chang 32*e7b1675dSTing-Kang Chang // derivableKeyManagers is the set of all key managers allowed to derive keys. 33*e7b1675dSTing-Kang Chang // It is keyed by the key manager's type URL, i.e. typeURL -> true. All type 34*e7b1675dSTing-Kang Chang // URLs in this map correspond to key managers that are 35*e7b1675dSTing-Kang Chang // - in the registry and 36*e7b1675dSTing-Kang Chang // - implement key derivation. 37*e7b1675dSTing-Kang Chang // 38*e7b1675dSTing-Kang Chang // This exists because of Golang's weak type system and the desire to keep key 39*e7b1675dSTing-Kang Chang // derivation non-public. If we do not explicitly restrict derivable key 40*e7b1675dSTing-Kang Chang // managers, users would be able to register any custom key manager that 41*e7b1675dSTing-Kang Chang // implements DeriveKey() and be able to derive keys with it, even without 42*e7b1675dSTing-Kang Chang // access to this library, internalregistry. 43*e7b1675dSTing-Kang Chang derivableKeyManagers = make(map[string]bool) 44*e7b1675dSTing-Kang Chang) 45*e7b1675dSTing-Kang Chang 46*e7b1675dSTing-Kang Chang// AllowKeyDerivation adds the type URL to derivableKeyManagers if the 47*e7b1675dSTing-Kang Chang// corresponding key manager is in the registry and implements key derivation. 48*e7b1675dSTing-Kang Changfunc AllowKeyDerivation(typeURL string) error { 49*e7b1675dSTing-Kang Chang km, err := registry.GetKeyManager(typeURL) 50*e7b1675dSTing-Kang Chang if err != nil { 51*e7b1675dSTing-Kang Chang return err 52*e7b1675dSTing-Kang Chang } 53*e7b1675dSTing-Kang Chang if _, ok := km.(DerivableKeyManager); !ok { 54*e7b1675dSTing-Kang Chang return fmt.Errorf("key manager for type %s does not implement key derivation", typeURL) 55*e7b1675dSTing-Kang Chang } 56*e7b1675dSTing-Kang Chang derivableKeyManagersMu.Lock() 57*e7b1675dSTing-Kang Chang derivableKeyManagers[typeURL] = true 58*e7b1675dSTing-Kang Chang derivableKeyManagersMu.Unlock() 59*e7b1675dSTing-Kang Chang return nil 60*e7b1675dSTing-Kang Chang} 61*e7b1675dSTing-Kang Chang 62*e7b1675dSTing-Kang Chang// CanDeriveKeys returns true if typeURL is in derivableKeyManagers. 63*e7b1675dSTing-Kang Changfunc CanDeriveKeys(typeURL string) bool { 64*e7b1675dSTing-Kang Chang derivableKeyManagersMu.Lock() 65*e7b1675dSTing-Kang Chang defer derivableKeyManagersMu.Unlock() 66*e7b1675dSTing-Kang Chang return derivableKeyManagers[typeURL] 67*e7b1675dSTing-Kang Chang} 68*e7b1675dSTing-Kang Chang 69*e7b1675dSTing-Kang Chang// DeriveKey derives a new key from template and pseudorandomness. 70*e7b1675dSTing-Kang Changfunc DeriveKey(keyTemplate *tinkpb.KeyTemplate, pseudorandomness io.Reader) (*tinkpb.KeyData, error) { 71*e7b1675dSTing-Kang Chang if !CanDeriveKeys(keyTemplate.GetTypeUrl()) { 72*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("key manager for type %s is not allowed to derive keys", keyTemplate.GetTypeUrl()) 73*e7b1675dSTing-Kang Chang } 74*e7b1675dSTing-Kang Chang km, err := registry.GetKeyManager(keyTemplate.GetTypeUrl()) 75*e7b1675dSTing-Kang Chang if err != nil { 76*e7b1675dSTing-Kang Chang return nil, err 77*e7b1675dSTing-Kang Chang } 78*e7b1675dSTing-Kang Chang keyManager, ok := km.(DerivableKeyManager) 79*e7b1675dSTing-Kang Chang if !ok { 80*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("key manager for type %s does not implement key derivation", keyTemplate.GetTypeUrl()) 81*e7b1675dSTing-Kang Chang } 82*e7b1675dSTing-Kang Chang key, err := keyManager.DeriveKey(keyTemplate.GetValue(), pseudorandomness) 83*e7b1675dSTing-Kang Chang if err != nil { 84*e7b1675dSTing-Kang Chang return nil, err 85*e7b1675dSTing-Kang Chang } 86*e7b1675dSTing-Kang Chang serializedKey, err := proto.Marshal(key) 87*e7b1675dSTing-Kang Chang if err != nil { 88*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("failed to serialize derived key: %v", err) 89*e7b1675dSTing-Kang Chang } 90*e7b1675dSTing-Kang Chang return &tinkpb.KeyData{ 91*e7b1675dSTing-Kang Chang TypeUrl: keyTemplate.GetTypeUrl(), 92*e7b1675dSTing-Kang Chang Value: serializedKey, 93*e7b1675dSTing-Kang Chang KeyMaterialType: keyManager.KeyMaterialType(), 94*e7b1675dSTing-Kang Chang }, nil 95*e7b1675dSTing-Kang Chang} 96