xref: /aosp_15_r20/external/tink/go/keyset/manager.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1// Copyright 2019 Google LLC
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
17package keyset
18
19import (
20	"errors"
21	"fmt"
22
23	"github.com/google/tink/go/core/registry"
24	"github.com/google/tink/go/subtle/random"
25
26	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
27)
28
29// Manager manages a Keyset-proto, with convenience methods that rotate, disable, enable or destroy keys.
30// Note: It is not thread-safe.
31type Manager struct {
32	ks *tinkpb.Keyset
33}
34
35// NewManager creates a new instance with an empty Keyset.
36func NewManager() *Manager {
37	ret := new(Manager)
38	ret.ks = new(tinkpb.Keyset)
39	return ret
40}
41
42// NewManagerFromHandle creates a new instance from the given Handle.
43func NewManagerFromHandle(kh *Handle) *Manager {
44	ret := new(Manager)
45	ret.ks = kh.ks
46	return ret
47}
48
49// Add generates and adds a fresh key using the given key template.
50// the key is enabled on creation, but not set to primary.
51// It returns the ID of the new key
52func (km *Manager) Add(kt *tinkpb.KeyTemplate) (uint32, error) {
53	if kt == nil {
54		return 0, errors.New("keyset_manager: cannot add key, need key template")
55	}
56	if kt.OutputPrefixType == tinkpb.OutputPrefixType_UNKNOWN_PREFIX {
57		return 0, errors.New("keyset_manager: unknown output prefix type")
58	}
59	if km.ks == nil {
60		return 0, errors.New("keyset_manager: cannot add key to nil keyset")
61	}
62	keyData, err := registry.NewKeyData(kt)
63	if err != nil {
64		return 0, fmt.Errorf("keyset_manager: cannot create KeyData: %s", err)
65	}
66	keyID := km.newKeyID()
67	key := &tinkpb.Keyset_Key{
68		KeyData:          keyData,
69		Status:           tinkpb.KeyStatusType_ENABLED,
70		KeyId:            keyID,
71		OutputPrefixType: kt.OutputPrefixType,
72	}
73	km.ks.Key = append(km.ks.Key, key)
74	return keyID, nil
75}
76
77// SetPrimary sets the key with given keyID as primary.
78// Returns an error if the key is not found or not enabled.
79func (km *Manager) SetPrimary(keyID uint32) error {
80	if km.ks == nil {
81		return errors.New("keyset_manager: cannot set primary, no keyset")
82	}
83	for _, key := range km.ks.Key {
84		if key.KeyId != keyID {
85			continue
86		}
87		if key.Status == tinkpb.KeyStatusType_ENABLED {
88			km.ks.PrimaryKeyId = keyID
89			return nil
90		}
91		return errors.New("keyset_manager: cannot set key as primary because it's not enabled")
92
93	}
94	return fmt.Errorf("keyset_manager: key with id %d not found", keyID)
95}
96
97// Enable will enable the key with given keyID.
98// Returns an error if the key is not found or is not enabled or disabled already.
99func (km *Manager) Enable(keyID uint32) error {
100	if km.ks == nil {
101		return errors.New("keyset_manager: cannot enable key, no keyset")
102	}
103	for i, key := range km.ks.Key {
104		if key.KeyId != keyID {
105			continue
106		}
107		if key.Status == tinkpb.KeyStatusType_ENABLED || key.Status == tinkpb.KeyStatusType_DISABLED {
108			km.ks.Key[i].Status = tinkpb.KeyStatusType_ENABLED
109			return nil
110		}
111		return fmt.Errorf("keyset_manager: cannot enable key with id %d with status %s", keyID, key.Status.String())
112	}
113	return fmt.Errorf("keyset_manager: key with id %d not found", keyID)
114}
115
116// Disable will disable the key with given keyID.
117// Returns an error if the key is not found or it is the primary key.
118func (km *Manager) Disable(keyID uint32) error {
119	if km.ks == nil {
120		return errors.New("keyset_manager: cannot disable key, no keyset")
121	}
122	if km.ks.PrimaryKeyId == keyID {
123		return errors.New("keyset_manager: cannot disable the primary key")
124	}
125	for i, key := range km.ks.Key {
126		if key.KeyId != keyID {
127			continue
128		}
129		if key.Status == tinkpb.KeyStatusType_ENABLED || key.Status == tinkpb.KeyStatusType_DISABLED {
130			km.ks.Key[i].Status = tinkpb.KeyStatusType_DISABLED
131			return nil
132		}
133		return fmt.Errorf("keyset_manager: cannot disable key with id %d with status %s", keyID, key.Status.String())
134	}
135	return fmt.Errorf("keyset_manager: key with id %d not found", keyID)
136}
137
138// Delete will delete the key with given keyID, removing the key from the keyset entirely.
139// Returns an error if the key is not found or it is the primary key.
140func (km *Manager) Delete(keyID uint32) error {
141	if km.ks == nil {
142		return errors.New("keyset_manager: cannot delete key, no keyset")
143	}
144	if km.ks.PrimaryKeyId == keyID {
145		return errors.New("keyset_manager: cannot delete the primary key")
146	}
147	deleteIdx, found := 0, false
148	for i, key := range km.ks.Key {
149		if key.KeyId == keyID {
150			found = true
151			deleteIdx = i
152		}
153	}
154	if !found {
155		return fmt.Errorf("keyset_manager: key with id %d not found", keyID)
156	}
157	// swap elements
158	km.ks.Key[deleteIdx] = km.ks.Key[len(km.ks.Key)-1]
159	// trim last element
160	km.ks.Key = km.ks.Key[:len(km.ks.Key)-1]
161	return nil
162}
163
164// Handle creates a new Handle for the managed keyset.
165func (km *Manager) Handle() (*Handle, error) {
166	return &Handle{ks: km.ks}, nil
167}
168
169// newKeyID generates a key id that has not been used by any key in the keyset.
170func (km *Manager) newKeyID() uint32 {
171	for {
172		ret := random.GetRandomUint32()
173		ok := true
174		for _, key := range km.ks.Key {
175			if key.KeyId == ret {
176				ok = false
177				break
178			}
179		}
180		if ok {
181			return ret
182		}
183	}
184}
185