Skip to content

Commit 9b98352

Browse files
ellemoutonRoasbeef
authored andcommitted
macaroons: let ChangePassword re-encrypt all root keys
The ChangePasswords method should re-encrypt all the root keys found in the store, not just the default root key.
1 parent 143fc4c commit 9b98352

File tree

2 files changed

+53
-33
lines changed

2 files changed

+53
-33
lines changed

macaroons/store.go

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ var (
5454
// ErrEncKeyNotFound specifies that there was no encryption key found
5555
// even if one was expected to be generated.
5656
ErrEncKeyNotFound = fmt.Errorf("macaroon encryption key not found")
57+
58+
// ErrDefaultRootKeyNotFound is returned when the default root key is
59+
// not found in the DB when it is expected to be.
60+
ErrDefaultRootKeyNotFound = fmt.Errorf("default root key not found")
5761
)
5862

5963
// RootKeyStorage implements the bakery.RootKeyStorage interface.
@@ -140,8 +144,8 @@ func (r *RootKeyStorage) CreateUnlock(password *[]byte) error {
140144
}, func() {})
141145
}
142146

143-
// ChangePassword decrypts the macaroon root key with the old password and then
144-
// encrypts it again with the new password.
147+
// ChangePassword decrypts all the macaroon root keys with the old password and
148+
// then encrypts them again with the new password.
145149
func (r *RootKeyStorage) ChangePassword(oldPw, newPw []byte) error {
146150
// We need the store to already be unlocked. With this we can make sure
147151
// that there already is a key in the DB.
@@ -159,19 +163,18 @@ func (r *RootKeyStorage) ChangePassword(oldPw, newPw []byte) error {
159163
if bucket == nil {
160164
return ErrRootKeyBucketNotFound
161165
}
162-
encKeyDb := bucket.Get(encryptionKeyID)
163-
rootKeyDb := bucket.Get(DefaultRootKeyID)
164166

165-
// Both the encryption key and the root key must be present
166-
// otherwise we are in the wrong state to change the password.
167-
if len(encKeyDb) == 0 || len(rootKeyDb) == 0 {
167+
// The encryption key must be present, otherwise we are in the
168+
// wrong state to change the password.
169+
encKeyDB := bucket.Get(encryptionKeyID)
170+
if len(encKeyDB) == 0 {
168171
return ErrEncKeyNotFound
169172
}
170173

171174
// Unmarshal parameters for old encryption key and derive the
172175
// old key with them.
173176
encKeyOld := &snacl.SecretKey{}
174-
err := encKeyOld.Unmarshal(encKeyDb)
177+
err := encKeyOld.Unmarshal(encKeyDB)
175178
if err != nil {
176179
return err
177180
}
@@ -188,21 +191,42 @@ func (r *RootKeyStorage) ChangePassword(oldPw, newPw []byte) error {
188191
return err
189192
}
190193

191-
// Now try to decrypt the root key with the old encryption key,
192-
// encrypt it with the new one and then store it in the DB.
193-
decryptedKey, err := encKeyOld.Decrypt(rootKeyDb)
194-
if err != nil {
195-
return err
196-
}
197-
rootKey := make([]byte, len(decryptedKey))
198-
copy(rootKey, decryptedKey)
199-
encryptedKey, err := encKeyNew.Encrypt(rootKey)
194+
// foundDefaultRootKey is used to keep track of if we have
195+
// found and re-encrypted the default root key so that we can
196+
// return an error if it is not found.
197+
var foundDefaultRootKey bool
198+
err = bucket.ForEach(func(k, v []byte) error {
199+
// Skip the key if it is the encryption key ID since
200+
// we do not want to re-encrypt this.
201+
if bytes.Equal(k, encryptionKeyID) {
202+
return nil
203+
}
204+
205+
if bytes.Equal(k, DefaultRootKeyID) {
206+
foundDefaultRootKey = true
207+
}
208+
209+
// Now try to decrypt the root key with the old
210+
// encryption key, encrypt it with the new one and then
211+
// store it in the DB.
212+
decryptedKey, err := encKeyOld.Decrypt(v)
213+
if err != nil {
214+
return err
215+
}
216+
217+
encryptedKey, err := encKeyNew.Encrypt(decryptedKey)
218+
if err != nil {
219+
return err
220+
}
221+
222+
return bucket.Put(k, encryptedKey)
223+
})
200224
if err != nil {
201225
return err
202226
}
203-
err = bucket.Put(DefaultRootKeyID, encryptedKey)
204-
if err != nil {
205-
return err
227+
228+
if !foundDefaultRootKey {
229+
return ErrDefaultRootKeyNotFound
206230
}
207231

208232
// Finally, store the new encryption key parameters in the DB

macaroons/store_test.go

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,7 @@ func TestStoreSetRootKey(t *testing.T) {
209209
}
210210

211211
// TestStoreChangePassword tests that the password for the store can be changed
212-
// without changing the root key. The test also demonstrates that currently,
213-
// this change is only applied to the root key at the default root key ID
214-
// location and not to other root keys. This will be fixed in an upcoming
215-
// commit.
212+
// without changing the root keys.
216213
func TestStoreChangePassword(t *testing.T) {
217214
tempDir, store := newTestStore(t)
218215

@@ -222,16 +219,15 @@ func TestStoreChangePassword(t *testing.T) {
222219

223220
// Unlock the DB and read the current default root key and one other
224221
// non-default root key. Both of these should stay the same after
225-
// changing the password but currently only the default root key is
226-
// re-encrypted correclty.
222+
// changing the password for the test to succeed.
227223
pw := []byte("weks")
228224
err = store.CreateUnlock(&pw)
229225
require.NoError(t, err)
230226

231227
rootKey1, _, err := store.RootKey(defaultRootKeyIDContext)
232228
require.NoError(t, err)
233229

234-
_, _, err = store.RootKey(nonDefaultRootKeyIDContext)
230+
rootKey2, _, err := store.RootKey(nonDefaultRootKeyIDContext)
235231
require.NoError(t, err)
236232

237233
// Both passwords must be set.
@@ -266,12 +262,12 @@ func TestStoreChangePassword(t *testing.T) {
266262
require.NoError(t, err)
267263

268264
// Finally, read the root keys from the DB using the new password and
269-
// make sure the default root key stayed the same but that the
270-
// non-default root key could not be decrypted.
271-
rootKeyDb, _, err := store.RootKey(defaultRootKeyIDContext)
265+
// make sure that both root keys stayed the same.
266+
rootKeyDB1, _, err := store.RootKey(defaultRootKeyIDContext)
272267
require.NoError(t, err)
273-
require.Equal(t, rootKey1, rootKeyDb)
268+
require.Equal(t, rootKey1, rootKeyDB1)
274269

275-
_, _, err = store.RootKey(nonDefaultRootKeyIDContext)
276-
require.ErrorContains(t, err, "unable to decrypt")
270+
rootKeyDB2, _, err := store.RootKey(nonDefaultRootKeyIDContext)
271+
require.NoError(t, err)
272+
require.Equal(t, rootKey2, rootKeyDB2)
277273
}

0 commit comments

Comments
 (0)