macaroons: specify root key ID in bakery

This commit is contained in:
yyforyongyu committed 2020-08-11 19:17:48 +08:00
1 parent 37a29b4869
commit f362f7670b
6 files changed
+341 -21

No files matched your search

+106 -8
View File
@@ -1,6 +1,7 @@
package macaroons
import (
"bytes"
"context"
"crypto/rand"
"fmt"
@@ -21,11 +22,9 @@ var (
// rootKeyBucketName is the name of the root key store bucket.
rootKeyBucketName = []byte("macrootkeys")
// defaultRootKeyID is the ID of the default root key. The first is
// DefaultRootKeyID is the ID of the default root key. The first is
// just 0, to emulate the memory storage that comes with bakery.
//
// TODO(aakselrod): Add support for key rotation.
defaultRootKeyID = []byte("0")
DefaultRootKeyID = []byte("0")
// encryptedKeyID is the name of the database key that stores the
// encryption key, encrypted with a salted + hashed password. The
@@ -42,6 +41,10 @@ var (
// ErrPasswordRequired specifies that a nil password has been passed.
ErrPasswordRequired = fmt.Errorf("a non-nil password is required")
// ErrKeyValueForbidden is used when the root key ID uses encryptedKeyID as
// its value.
ErrKeyValueForbidden = fmt.Errorf("root key ID value is not allowed")
)
// RootKeyStorage implements the bakery.RootKeyStorage interface.
@@ -157,8 +160,7 @@ func (r *RootKeyStorage) Get(_ context.Context, id []byte) ([]byte, error) {
// RootKey implements the RootKey method for the bakery.RootKeyStorage
// interface.
// TODO(aakselrod): Add support for key rotation.
func (r *RootKeyStorage) RootKey(_ context.Context) ([]byte, []byte, error) {
func (r *RootKeyStorage) RootKey(ctx context.Context) ([]byte, []byte, error) {
r.encKeyMtx.RLock()
defer r.encKeyMtx.RUnlock()
@@ -166,8 +168,19 @@ func (r *RootKeyStorage) RootKey(_ context.Context) ([]byte, []byte, error) {
return nil, nil, ErrStoreLocked
}
var rootKey []byte
id := defaultRootKeyID
err := kvdb.Update(r, func(tx kvdb.RwTx) error {
// Read the root key ID from the context. If no key is specified in the
// context, an error will be returned.
id, err := RootKeyIDFromContext(ctx)
if err != nil {
return nil, nil, err
}
if bytes.Equal(id, encryptedKeyID) {
return nil, nil, ErrKeyValueForbidden
}
err = kvdb.Update(r, func(tx kvdb.RwTx) error {
ns := tx.ReadWriteBucket(rootKeyBucketName)
dbKey := ns.Get(id)
@@ -215,3 +228,88 @@ func (r *RootKeyStorage) Close() error {
}
return r.Backend.Close()
}
// ListMacaroonIDs returns all the root key ID values except the value of
// encryptedKeyID.
func (r *RootKeyStorage) ListMacaroonIDs(_ context.Context) ([][]byte, error) {
r.encKeyMtx.RLock()
defer r.encKeyMtx.RUnlock()
// Check it's unlocked.
if r.encKey == nil {
return nil, ErrStoreLocked
}
var rootKeySlice [][]byte
// Read all the items in the bucket and append the keys, which are the
// root key IDs we want.
err := kvdb.View(r, func(tx kvdb.RTx) error {
// appendRootKey is a function closure that appends root key ID
// to rootKeySlice.
appendRootKey := func(k, _ []byte) error {
// Only append when the key value is not encryptedKeyID.
if !bytes.Equal(k, encryptedKeyID) {
rootKeySlice = append(rootKeySlice, k)
}
return nil
}
return tx.ReadBucket(rootKeyBucketName).ForEach(appendRootKey)
})
if err != nil {
return nil, err
}
return rootKeySlice, nil
}
// DeleteMacaroonID removes one specific root key ID. If the root key ID is
// found and deleted, it will be returned.
func (r *RootKeyStorage) DeleteMacaroonID(
_ context.Context, rootKeyID []byte) ([]byte, error) {
r.encKeyMtx.RLock()
defer r.encKeyMtx.RUnlock()
// Check it's unlocked.
if r.encKey == nil {
return nil, ErrStoreLocked
}
// Check the rootKeyID is not empty.
if len(rootKeyID) == 0 {
return nil, ErrMissingRootKeyID
}
// Deleting encryptedKeyID or DefaultRootKeyID is not allowed.
if bytes.Equal(rootKeyID, encryptedKeyID) ||
bytes.Equal(rootKeyID, DefaultRootKeyID) {
return nil, ErrDeletionForbidden
}
var rootKeyIDDeleted []byte
err := kvdb.Update(r, func(tx kvdb.RwTx) error {
bucket := tx.ReadWriteBucket(rootKeyBucketName)
// Check the key can be found. If not, return nil.
if bucket.Get(rootKeyID) == nil {
return nil
}
// Once the key is found, we do the deletion.
if err := bucket.Delete(rootKeyID); err != nil {
return err
}
rootKeyIDDeleted = rootKeyID
return nil
})
if err != nil {
return nil, err
}
return rootKeyIDDeleted, nil
}