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