Skip to content

Commit fcbe684

Browse files
committed
Merge branch 'v0-16-3-branch-7705' into v0-16-3-branch
2 parents b26be81 + bd43def commit fcbe684

File tree

3 files changed

+116
-38
lines changed

3 files changed

+116
-38
lines changed

docs/release-notes/release-notes-0.16.3.md

+7
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,12 @@ Optimized [mempool
66
management](https://github.com/lightningnetwork/lnd/pull/7681) to lower the CPU
77
usage.
88

9+
## Bug Fixes
10+
11+
* [Re-encrypt/regenerate](https://github.com/lightningnetwork/lnd/pull/7705)
12+
all macaroon DB root keys on `ChangePassword`/`GenerateNewRootKey`
13+
respectively.
14+
915
# Contributors (Alphabetical Order)
16+
* Elle Mouton
1017
* Yong Yu

macaroons/store.go

+69-21
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
@@ -325,10 +349,34 @@ func (r *RootKeyStorage) GenerateNewRootKey() error {
325349
if bucket == nil {
326350
return ErrRootKeyBucketNotFound
327351
}
352+
353+
// The default root key should be created even if it does not
354+
// yet exist, so we do this separately from the rest of the
355+
// root keys.
328356
_, err := generateAndStoreNewRootKey(
329357
bucket, DefaultRootKeyID, r.encKey,
330358
)
331-
return err
359+
if err != nil {
360+
return err
361+
}
362+
363+
// Now iterate over all the other root keys that may exist
364+
// and re-generate each of them.
365+
return bucket.ForEach(func(k, v []byte) error {
366+
if bytes.Equal(k, encryptionKeyID) {
367+
return nil
368+
}
369+
370+
if bytes.Equal(k, DefaultRootKeyID) {
371+
return nil
372+
}
373+
374+
_, err := generateAndStoreNewRootKey(
375+
bucket, k, r.encKey,
376+
)
377+
378+
return err
379+
})
332380
}, func() {})
333381
}
334382

macaroons/store_test.go

+40-17
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ var (
1616
defaultRootKeyIDContext = macaroons.ContextWithRootKeyID(
1717
context.Background(), macaroons.DefaultRootKeyID,
1818
)
19+
20+
nonDefaultRootKeyIDContext = macaroons.ContextWithRootKeyID(
21+
context.Background(), []byte{1},
22+
)
1923
)
2024

2125
// newTestStore creates a new bolt DB in a temporary directory and then
@@ -131,32 +135,42 @@ func TestStore(t *testing.T) {
131135
require.Equal(t, rootID, id)
132136
}
133137

134-
// TestStoreGenerateNewRootKey tests that a root key can be replaced with a new
135-
// one in the store without changing the password.
138+
// TestStoreGenerateNewRootKey tests that root keys can be replaced with new
139+
// ones in the store without changing the password.
136140
func TestStoreGenerateNewRootKey(t *testing.T) {
137141
_, store := newTestStore(t)
138142

139143
// The store must be unlocked to replace the root key.
140144
err := store.GenerateNewRootKey()
141145
require.Equal(t, macaroons.ErrStoreLocked, err)
142146

143-
// Unlock the store and read the current key.
147+
// Unlock the store.
144148
pw := []byte("weks")
145149
err = store.CreateUnlock(&pw)
146150
require.NoError(t, err)
147-
oldRootKey, _, err := store.RootKey(defaultRootKeyIDContext)
151+
152+
// Read the default root key.
153+
oldRootKey1, _, err := store.RootKey(defaultRootKeyIDContext)
148154
require.NoError(t, err)
149155

150-
// Replace the root key with a new random key.
156+
// Read the non-default root-key.
157+
oldRootKey2, _, err := store.RootKey(nonDefaultRootKeyIDContext)
158+
require.NoError(t, err)
159+
160+
// Replace the root keys with new random keys.
151161
err = store.GenerateNewRootKey()
152162
require.NoError(t, err)
153163

154-
// Finally, read the root key from the DB and compare it to the one
164+
// Finally, read both root keys from the DB and compare them to the ones
155165
// we got returned earlier. This makes sure that the encryption/
156166
// decryption of the key in the DB worked as expected too.
157-
newRootKey, _, err := store.RootKey(defaultRootKeyIDContext)
167+
newRootKey1, _, err := store.RootKey(defaultRootKeyIDContext)
158168
require.NoError(t, err)
159-
require.NotEqual(t, oldRootKey, newRootKey)
169+
require.NotEqual(t, oldRootKey1, newRootKey1)
170+
171+
newRootKey2, _, err := store.RootKey(nonDefaultRootKeyIDContext)
172+
require.NoError(t, err)
173+
require.NotEqual(t, oldRootKey2, newRootKey2)
160174
}
161175

162176
// TestStoreSetRootKey tests that a root key can be set to a specified value.
@@ -195,20 +209,25 @@ func TestStoreSetRootKey(t *testing.T) {
195209
}
196210

197211
// TestStoreChangePassword tests that the password for the store can be changed
198-
// without changing the root key.
212+
// without changing the root keys.
199213
func TestStoreChangePassword(t *testing.T) {
200214
tempDir, store := newTestStore(t)
201215

202-
// The store must be unlocked to replace the root key.
216+
// The store must be unlocked to replace the root keys.
203217
err := store.ChangePassword(nil, nil)
204218
require.Equal(t, macaroons.ErrStoreLocked, err)
205219

206-
// Unlock the DB and read the current root key. This will need to stay
207-
// the same after changing the password for the test to succeed.
220+
// Unlock the DB and read the current default root key and one other
221+
// non-default root key. Both of these should stay the same after
222+
// changing the password for the test to succeed.
208223
pw := []byte("weks")
209224
err = store.CreateUnlock(&pw)
210225
require.NoError(t, err)
211-
rootKey, _, err := store.RootKey(defaultRootKeyIDContext)
226+
227+
rootKey1, _, err := store.RootKey(defaultRootKeyIDContext)
228+
require.NoError(t, err)
229+
230+
rootKey2, _, err := store.RootKey(nonDefaultRootKeyIDContext)
212231
require.NoError(t, err)
213232

214233
// Both passwords must be set.
@@ -242,9 +261,13 @@ func TestStoreChangePassword(t *testing.T) {
242261
err = store.CreateUnlock(&newPw)
243262
require.NoError(t, err)
244263

245-
// Finally read the root key from the DB using the new password and
246-
// make sure the root key stayed the same.
247-
rootKeyDb, _, err := store.RootKey(defaultRootKeyIDContext)
264+
// Finally, read the root keys from the DB using the new password and
265+
// make sure that both root keys stayed the same.
266+
rootKeyDB1, _, err := store.RootKey(defaultRootKeyIDContext)
267+
require.NoError(t, err)
268+
require.Equal(t, rootKey1, rootKeyDB1)
269+
270+
rootKeyDB2, _, err := store.RootKey(nonDefaultRootKeyIDContext)
248271
require.NoError(t, err)
249-
require.Equal(t, rootKey, rootKeyDb)
272+
require.Equal(t, rootKey2, rootKeyDB2)
250273
}

0 commit comments

Comments
 (0)