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