xref: /aosp_15_r20/external/tink/go/keyset/handle.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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