1*e7b1675dSTing-Kang Chang// Copyright 2019 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 keyset 18*e7b1675dSTing-Kang Chang 19*e7b1675dSTing-Kang Changimport ( 20*e7b1675dSTing-Kang Chang "errors" 21*e7b1675dSTing-Kang Chang "fmt" 22*e7b1675dSTing-Kang Chang 23*e7b1675dSTing-Kang Chang "google.golang.org/protobuf/encoding/prototext" 24*e7b1675dSTing-Kang Chang "google.golang.org/protobuf/proto" 25*e7b1675dSTing-Kang Chang 26*e7b1675dSTing-Kang Chang "github.com/google/tink/go/core/primitiveset" 27*e7b1675dSTing-Kang Chang "github.com/google/tink/go/core/registry" 28*e7b1675dSTing-Kang Chang "github.com/google/tink/go/tink" 29*e7b1675dSTing-Kang Chang tinkpb "github.com/google/tink/go/proto/tink_go_proto" 30*e7b1675dSTing-Kang Chang) 31*e7b1675dSTing-Kang Chang 32*e7b1675dSTing-Kang Changvar errInvalidKeyset = fmt.Errorf("keyset.Handle: invalid keyset") 33*e7b1675dSTing-Kang Chang 34*e7b1675dSTing-Kang Chang// Handle provides access to a Keyset protobuf, to limit the exposure of actual protocol 35*e7b1675dSTing-Kang Chang// buffers that hold sensitive key material. 36*e7b1675dSTing-Kang Changtype Handle struct { 37*e7b1675dSTing-Kang Chang ks *tinkpb.Keyset 38*e7b1675dSTing-Kang Chang annotations map[string]string 39*e7b1675dSTing-Kang Chang} 40*e7b1675dSTing-Kang Chang 41*e7b1675dSTing-Kang Changfunc newWithOptions(ks *tinkpb.Keyset, opts ...Option) (*Handle, error) { 42*e7b1675dSTing-Kang Chang h := &Handle{ks: ks} 43*e7b1675dSTing-Kang Chang if err := applyOptions(h, opts...); err != nil { 44*e7b1675dSTing-Kang Chang return nil, err 45*e7b1675dSTing-Kang Chang } 46*e7b1675dSTing-Kang Chang return h, nil 47*e7b1675dSTing-Kang Chang} 48*e7b1675dSTing-Kang Chang 49*e7b1675dSTing-Kang Chang// NewHandle creates a keyset handle that contains a single fresh key generated according 50*e7b1675dSTing-Kang Chang// to the given KeyTemplate. 51*e7b1675dSTing-Kang Changfunc NewHandle(kt *tinkpb.KeyTemplate) (*Handle, error) { 52*e7b1675dSTing-Kang Chang manager := NewManager() 53*e7b1675dSTing-Kang Chang keyID, err := manager.Add(kt) 54*e7b1675dSTing-Kang Chang if err != nil { 55*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("keyset.Handle: cannot generate new keyset: %s", err) 56*e7b1675dSTing-Kang Chang } 57*e7b1675dSTing-Kang Chang err = manager.SetPrimary(keyID) 58*e7b1675dSTing-Kang Chang if err != nil { 59*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("keyset.Handle: cannot set primary: %s", err) 60*e7b1675dSTing-Kang Chang } 61*e7b1675dSTing-Kang Chang handle, err := manager.Handle() 62*e7b1675dSTing-Kang Chang if err != nil { 63*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("keyset.Handle: cannot get keyset handle: %s", err) 64*e7b1675dSTing-Kang Chang } 65*e7b1675dSTing-Kang Chang return handle, nil 66*e7b1675dSTing-Kang Chang} 67*e7b1675dSTing-Kang Chang 68*e7b1675dSTing-Kang Chang// NewHandleWithNoSecrets creates a new instance of KeysetHandle using the given keyset which does 69*e7b1675dSTing-Kang Chang// not contain any secret key material. 70*e7b1675dSTing-Kang Changfunc NewHandleWithNoSecrets(ks *tinkpb.Keyset) (*Handle, error) { 71*e7b1675dSTing-Kang Chang if ks == nil { 72*e7b1675dSTing-Kang Chang return nil, errors.New("keyset.Handle: nil keyset") 73*e7b1675dSTing-Kang Chang } 74*e7b1675dSTing-Kang Chang h := &Handle{ks: ks} 75*e7b1675dSTing-Kang Chang if h.hasSecrets() { 76*e7b1675dSTing-Kang Chang // If you need to do this, you have to use func insecurecleartextkeyset.Read() instead. 77*e7b1675dSTing-Kang Chang return nil, errors.New("importing unencrypted secret key material is forbidden") 78*e7b1675dSTing-Kang Chang } 79*e7b1675dSTing-Kang Chang return h, nil 80*e7b1675dSTing-Kang Chang} 81*e7b1675dSTing-Kang Chang 82*e7b1675dSTing-Kang Chang// Read tries to create a Handle from an encrypted keyset obtained via reader. 83*e7b1675dSTing-Kang Changfunc Read(reader Reader, masterKey tink.AEAD) (*Handle, error) { 84*e7b1675dSTing-Kang Chang return ReadWithAssociatedData(reader, masterKey, []byte{}) 85*e7b1675dSTing-Kang Chang} 86*e7b1675dSTing-Kang Chang 87*e7b1675dSTing-Kang Chang// ReadWithAssociatedData tries to create a Handle from an encrypted keyset obtained via reader using the provided associated data. 88*e7b1675dSTing-Kang Changfunc ReadWithAssociatedData(reader Reader, masterKey tink.AEAD, associatedData []byte) (*Handle, error) { 89*e7b1675dSTing-Kang Chang encryptedKeyset, err := reader.ReadEncrypted() 90*e7b1675dSTing-Kang Chang if err != nil { 91*e7b1675dSTing-Kang Chang return nil, err 92*e7b1675dSTing-Kang Chang } 93*e7b1675dSTing-Kang Chang ks, err := decrypt(encryptedKeyset, masterKey, associatedData) 94*e7b1675dSTing-Kang Chang if err != nil { 95*e7b1675dSTing-Kang Chang return nil, err 96*e7b1675dSTing-Kang Chang } 97*e7b1675dSTing-Kang Chang return &Handle{ks: ks}, nil 98*e7b1675dSTing-Kang Chang} 99*e7b1675dSTing-Kang Chang 100*e7b1675dSTing-Kang Chang// ReadWithNoSecrets tries to create a keyset.Handle from a keyset obtained via reader. 101*e7b1675dSTing-Kang Changfunc ReadWithNoSecrets(reader Reader) (*Handle, error) { 102*e7b1675dSTing-Kang Chang ks, err := reader.Read() 103*e7b1675dSTing-Kang Chang if err != nil { 104*e7b1675dSTing-Kang Chang return nil, err 105*e7b1675dSTing-Kang Chang } 106*e7b1675dSTing-Kang Chang return NewHandleWithNoSecrets(ks) 107*e7b1675dSTing-Kang Chang} 108*e7b1675dSTing-Kang Chang 109*e7b1675dSTing-Kang Chang// Public returns a Handle of the public keys if the managed keyset contains private keys. 110*e7b1675dSTing-Kang Changfunc (h *Handle) Public() (*Handle, error) { 111*e7b1675dSTing-Kang Chang privKeys := h.ks.Key 112*e7b1675dSTing-Kang Chang pubKeys := make([]*tinkpb.Keyset_Key, len(privKeys)) 113*e7b1675dSTing-Kang Chang 114*e7b1675dSTing-Kang Chang for i := 0; i < len(privKeys); i++ { 115*e7b1675dSTing-Kang Chang if privKeys[i] == nil || privKeys[i].KeyData == nil { 116*e7b1675dSTing-Kang Chang return nil, errInvalidKeyset 117*e7b1675dSTing-Kang Chang } 118*e7b1675dSTing-Kang Chang privKeyData := privKeys[i].KeyData 119*e7b1675dSTing-Kang Chang pubKeyData, err := publicKeyData(privKeyData) 120*e7b1675dSTing-Kang Chang if err != nil { 121*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("keyset.Handle: %s", err) 122*e7b1675dSTing-Kang Chang } 123*e7b1675dSTing-Kang Chang pubKeys[i] = &tinkpb.Keyset_Key{ 124*e7b1675dSTing-Kang Chang KeyData: pubKeyData, 125*e7b1675dSTing-Kang Chang Status: privKeys[i].Status, 126*e7b1675dSTing-Kang Chang KeyId: privKeys[i].KeyId, 127*e7b1675dSTing-Kang Chang OutputPrefixType: privKeys[i].OutputPrefixType, 128*e7b1675dSTing-Kang Chang } 129*e7b1675dSTing-Kang Chang } 130*e7b1675dSTing-Kang Chang ks := &tinkpb.Keyset{ 131*e7b1675dSTing-Kang Chang PrimaryKeyId: h.ks.PrimaryKeyId, 132*e7b1675dSTing-Kang Chang Key: pubKeys, 133*e7b1675dSTing-Kang Chang } 134*e7b1675dSTing-Kang Chang return &Handle{ks: ks}, nil 135*e7b1675dSTing-Kang Chang} 136*e7b1675dSTing-Kang Chang 137*e7b1675dSTing-Kang Chang// String returns a string representation of the managed keyset. 138*e7b1675dSTing-Kang Chang// The result does not contain any sensitive key material. 139*e7b1675dSTing-Kang Changfunc (h *Handle) String() string { 140*e7b1675dSTing-Kang Chang c, err := prototext.MarshalOptions{}.Marshal(getKeysetInfo(h.ks)) 141*e7b1675dSTing-Kang Chang if err != nil { 142*e7b1675dSTing-Kang Chang return "" 143*e7b1675dSTing-Kang Chang } 144*e7b1675dSTing-Kang Chang return string(c) 145*e7b1675dSTing-Kang Chang} 146*e7b1675dSTing-Kang Chang 147*e7b1675dSTing-Kang Chang// KeysetInfo returns KeysetInfo representation of the managed keyset. 148*e7b1675dSTing-Kang Chang// The result does not contain any sensitive key material. 149*e7b1675dSTing-Kang Changfunc (h *Handle) KeysetInfo() *tinkpb.KeysetInfo { 150*e7b1675dSTing-Kang Chang return getKeysetInfo(h.ks) 151*e7b1675dSTing-Kang Chang} 152*e7b1675dSTing-Kang Chang 153*e7b1675dSTing-Kang Chang// Write encrypts and writes the enclosing keyset. 154*e7b1675dSTing-Kang Changfunc (h *Handle) Write(writer Writer, masterKey tink.AEAD) error { 155*e7b1675dSTing-Kang Chang return h.WriteWithAssociatedData(writer, masterKey, []byte{}) 156*e7b1675dSTing-Kang Chang} 157*e7b1675dSTing-Kang Chang 158*e7b1675dSTing-Kang Chang// WriteWithAssociatedData encrypts and writes the enclosing keyset using the provided associated data. 159*e7b1675dSTing-Kang Changfunc (h *Handle) WriteWithAssociatedData(writer Writer, masterKey tink.AEAD, associatedData []byte) error { 160*e7b1675dSTing-Kang Chang encrypted, err := encrypt(h.ks, masterKey, associatedData) 161*e7b1675dSTing-Kang Chang if err != nil { 162*e7b1675dSTing-Kang Chang return err 163*e7b1675dSTing-Kang Chang } 164*e7b1675dSTing-Kang Chang return writer.WriteEncrypted(encrypted) 165*e7b1675dSTing-Kang Chang} 166*e7b1675dSTing-Kang Chang 167*e7b1675dSTing-Kang Chang// WriteWithNoSecrets exports the keyset in h to the given Writer w returning an error if the keyset 168*e7b1675dSTing-Kang Chang// contains secret key material. 169*e7b1675dSTing-Kang Changfunc (h *Handle) WriteWithNoSecrets(w Writer) error { 170*e7b1675dSTing-Kang Chang if h.hasSecrets() { 171*e7b1675dSTing-Kang Chang return errors.New("exporting unencrypted secret key material is forbidden") 172*e7b1675dSTing-Kang Chang } 173*e7b1675dSTing-Kang Chang 174*e7b1675dSTing-Kang Chang return w.Write(h.ks) 175*e7b1675dSTing-Kang Chang} 176*e7b1675dSTing-Kang Chang 177*e7b1675dSTing-Kang Chang// Primitives creates a set of primitives corresponding to the keys with 178*e7b1675dSTing-Kang Chang// status=ENABLED in the keyset of the given keyset handle, assuming all the 179*e7b1675dSTing-Kang Chang// corresponding key managers are present (keys with status!=ENABLED are skipped). 180*e7b1675dSTing-Kang Chang// 181*e7b1675dSTing-Kang Chang// The returned set is usually later "wrapped" into a class that implements 182*e7b1675dSTing-Kang Chang// the corresponding Primitive-interface. 183*e7b1675dSTing-Kang Changfunc (h *Handle) Primitives() (*primitiveset.PrimitiveSet, error) { 184*e7b1675dSTing-Kang Chang return h.PrimitivesWithKeyManager(nil) 185*e7b1675dSTing-Kang Chang} 186*e7b1675dSTing-Kang Chang 187*e7b1675dSTing-Kang Chang// PrimitivesWithKeyManager creates a set of primitives corresponding to 188*e7b1675dSTing-Kang Chang// the keys with status=ENABLED in the keyset of the given keysetHandle, using 189*e7b1675dSTing-Kang Chang// the given key manager (instead of registered key managers) for keys supported 190*e7b1675dSTing-Kang Chang// by it. Keys not supported by the key manager are handled by matching registered 191*e7b1675dSTing-Kang Chang// key managers (if present), and keys with status!=ENABLED are skipped. 192*e7b1675dSTing-Kang Chang// 193*e7b1675dSTing-Kang Chang// This enables custom treatment of keys, for example providing extra context 194*e7b1675dSTing-Kang Chang// (e.g. credentials for accessing keys managed by a KMS), or gathering custom 195*e7b1675dSTing-Kang Chang// monitoring/profiling information. 196*e7b1675dSTing-Kang Chang// 197*e7b1675dSTing-Kang Chang// The returned set is usually later "wrapped" into a class that implements 198*e7b1675dSTing-Kang Chang// the corresponding Primitive-interface. 199*e7b1675dSTing-Kang Changfunc (h *Handle) PrimitivesWithKeyManager(km registry.KeyManager) (*primitiveset.PrimitiveSet, error) { 200*e7b1675dSTing-Kang Chang if err := Validate(h.ks); err != nil { 201*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("registry.PrimitivesWithKeyManager: invalid keyset: %s", err) 202*e7b1675dSTing-Kang Chang } 203*e7b1675dSTing-Kang Chang primitiveSet := primitiveset.New() 204*e7b1675dSTing-Kang Chang primitiveSet.Annotations = h.annotations 205*e7b1675dSTing-Kang Chang for _, key := range h.ks.Key { 206*e7b1675dSTing-Kang Chang if key.Status != tinkpb.KeyStatusType_ENABLED { 207*e7b1675dSTing-Kang Chang continue 208*e7b1675dSTing-Kang Chang } 209*e7b1675dSTing-Kang Chang var primitive interface{} 210*e7b1675dSTing-Kang Chang var err error 211*e7b1675dSTing-Kang Chang if km != nil && km.DoesSupport(key.KeyData.TypeUrl) { 212*e7b1675dSTing-Kang Chang primitive, err = km.Primitive(key.KeyData.Value) 213*e7b1675dSTing-Kang Chang } else { 214*e7b1675dSTing-Kang Chang primitive, err = registry.PrimitiveFromKeyData(key.KeyData) 215*e7b1675dSTing-Kang Chang } 216*e7b1675dSTing-Kang Chang if err != nil { 217*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("registry.PrimitivesWithKeyManager: cannot get primitive from key: %s", err) 218*e7b1675dSTing-Kang Chang } 219*e7b1675dSTing-Kang Chang entry, err := primitiveSet.Add(primitive, key) 220*e7b1675dSTing-Kang Chang if err != nil { 221*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("registry.PrimitivesWithKeyManager: cannot add primitive: %s", err) 222*e7b1675dSTing-Kang Chang } 223*e7b1675dSTing-Kang Chang if key.KeyId == h.ks.PrimaryKeyId { 224*e7b1675dSTing-Kang Chang primitiveSet.Primary = entry 225*e7b1675dSTing-Kang Chang } 226*e7b1675dSTing-Kang Chang } 227*e7b1675dSTing-Kang Chang return primitiveSet, nil 228*e7b1675dSTing-Kang Chang} 229*e7b1675dSTing-Kang Chang 230*e7b1675dSTing-Kang Chang// hasSecrets returns true if the keyset handle contains key material considered secret. This 231*e7b1675dSTing-Kang Chang// includes symmetric keys, private keys of asymmetric crypto systems, and keys of an unknown type. 232*e7b1675dSTing-Kang Changfunc (h *Handle) hasSecrets() bool { 233*e7b1675dSTing-Kang Chang for _, k := range h.ks.Key { 234*e7b1675dSTing-Kang Chang if k == nil || k.KeyData == nil { 235*e7b1675dSTing-Kang Chang continue 236*e7b1675dSTing-Kang Chang } 237*e7b1675dSTing-Kang Chang if k.KeyData.KeyMaterialType == tinkpb.KeyData_UNKNOWN_KEYMATERIAL { 238*e7b1675dSTing-Kang Chang return true 239*e7b1675dSTing-Kang Chang } 240*e7b1675dSTing-Kang Chang if k.KeyData.KeyMaterialType == tinkpb.KeyData_ASYMMETRIC_PRIVATE { 241*e7b1675dSTing-Kang Chang return true 242*e7b1675dSTing-Kang Chang } 243*e7b1675dSTing-Kang Chang if k.KeyData.KeyMaterialType == tinkpb.KeyData_SYMMETRIC { 244*e7b1675dSTing-Kang Chang return true 245*e7b1675dSTing-Kang Chang } 246*e7b1675dSTing-Kang Chang } 247*e7b1675dSTing-Kang Chang return false 248*e7b1675dSTing-Kang Chang} 249*e7b1675dSTing-Kang Chang 250*e7b1675dSTing-Kang Changfunc publicKeyData(privKeyData *tinkpb.KeyData) (*tinkpb.KeyData, error) { 251*e7b1675dSTing-Kang Chang if privKeyData.KeyMaterialType != tinkpb.KeyData_ASYMMETRIC_PRIVATE { 252*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("keyset.Handle: keyset contains a non-private key") 253*e7b1675dSTing-Kang Chang } 254*e7b1675dSTing-Kang Chang km, err := registry.GetKeyManager(privKeyData.TypeUrl) 255*e7b1675dSTing-Kang Chang if err != nil { 256*e7b1675dSTing-Kang Chang return nil, err 257*e7b1675dSTing-Kang Chang } 258*e7b1675dSTing-Kang Chang pkm, ok := km.(registry.PrivateKeyManager) 259*e7b1675dSTing-Kang Chang if !ok { 260*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("keyset.Handle: %s does not belong to a PrivateKeyManager", privKeyData.TypeUrl) 261*e7b1675dSTing-Kang Chang } 262*e7b1675dSTing-Kang Chang return pkm.PublicKeyData(privKeyData.Value) 263*e7b1675dSTing-Kang Chang} 264*e7b1675dSTing-Kang Chang 265*e7b1675dSTing-Kang Changfunc decrypt(encryptedKeyset *tinkpb.EncryptedKeyset, masterKey tink.AEAD, associatedData []byte) (*tinkpb.Keyset, error) { 266*e7b1675dSTing-Kang Chang if encryptedKeyset == nil || masterKey == nil { 267*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("keyset.Handle: invalid encrypted keyset") 268*e7b1675dSTing-Kang Chang } 269*e7b1675dSTing-Kang Chang decrypted, err := masterKey.Decrypt(encryptedKeyset.EncryptedKeyset, associatedData) 270*e7b1675dSTing-Kang Chang if err != nil { 271*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("keyset.Handle: decryption failed: %s", err) 272*e7b1675dSTing-Kang Chang } 273*e7b1675dSTing-Kang Chang keyset := new(tinkpb.Keyset) 274*e7b1675dSTing-Kang Chang if err := proto.Unmarshal(decrypted, keyset); err != nil { 275*e7b1675dSTing-Kang Chang return nil, errInvalidKeyset 276*e7b1675dSTing-Kang Chang } 277*e7b1675dSTing-Kang Chang return keyset, nil 278*e7b1675dSTing-Kang Chang} 279*e7b1675dSTing-Kang Chang 280*e7b1675dSTing-Kang Changfunc encrypt(keyset *tinkpb.Keyset, masterKey tink.AEAD, associatedData []byte) (*tinkpb.EncryptedKeyset, error) { 281*e7b1675dSTing-Kang Chang serializedKeyset, err := proto.Marshal(keyset) 282*e7b1675dSTing-Kang Chang if err != nil { 283*e7b1675dSTing-Kang Chang return nil, errInvalidKeyset 284*e7b1675dSTing-Kang Chang } 285*e7b1675dSTing-Kang Chang encrypted, err := masterKey.Encrypt(serializedKeyset, associatedData) 286*e7b1675dSTing-Kang Chang if err != nil { 287*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("keyset.Handle: encrypted failed: %s", err) 288*e7b1675dSTing-Kang Chang } 289*e7b1675dSTing-Kang Chang // get keyset info 290*e7b1675dSTing-Kang Chang encryptedKeyset := &tinkpb.EncryptedKeyset{ 291*e7b1675dSTing-Kang Chang EncryptedKeyset: encrypted, 292*e7b1675dSTing-Kang Chang KeysetInfo: getKeysetInfo(keyset), 293*e7b1675dSTing-Kang Chang } 294*e7b1675dSTing-Kang Chang return encryptedKeyset, nil 295*e7b1675dSTing-Kang Chang} 296*e7b1675dSTing-Kang Chang 297*e7b1675dSTing-Kang Chang// getKeysetInfo returns a KeysetInfo from a Keyset protobuf. 298*e7b1675dSTing-Kang Changfunc getKeysetInfo(keyset *tinkpb.Keyset) *tinkpb.KeysetInfo { 299*e7b1675dSTing-Kang Chang if keyset == nil { 300*e7b1675dSTing-Kang Chang panic("keyset.Handle: keyset must be non nil") 301*e7b1675dSTing-Kang Chang } 302*e7b1675dSTing-Kang Chang nKey := len(keyset.Key) 303*e7b1675dSTing-Kang Chang keyInfos := make([]*tinkpb.KeysetInfo_KeyInfo, nKey) 304*e7b1675dSTing-Kang Chang for i, key := range keyset.Key { 305*e7b1675dSTing-Kang Chang keyInfos[i] = getKeyInfo(key) 306*e7b1675dSTing-Kang Chang } 307*e7b1675dSTing-Kang Chang return &tinkpb.KeysetInfo{ 308*e7b1675dSTing-Kang Chang PrimaryKeyId: keyset.PrimaryKeyId, 309*e7b1675dSTing-Kang Chang KeyInfo: keyInfos, 310*e7b1675dSTing-Kang Chang } 311*e7b1675dSTing-Kang Chang} 312*e7b1675dSTing-Kang Chang 313*e7b1675dSTing-Kang Chang// getKeyInfo returns a KeyInfo from a Key protobuf. 314*e7b1675dSTing-Kang Changfunc getKeyInfo(key *tinkpb.Keyset_Key) *tinkpb.KeysetInfo_KeyInfo { 315*e7b1675dSTing-Kang Chang return &tinkpb.KeysetInfo_KeyInfo{ 316*e7b1675dSTing-Kang Chang TypeUrl: key.KeyData.TypeUrl, 317*e7b1675dSTing-Kang Chang Status: key.Status, 318*e7b1675dSTing-Kang Chang KeyId: key.KeyId, 319*e7b1675dSTing-Kang Chang OutputPrefixType: key.OutputPrefixType, 320*e7b1675dSTing-Kang Chang } 321*e7b1675dSTing-Kang Chang} 322