macaroons: specify root key ID in bakery
This commit is contained in:
6 files changed
+341
-21
No files matched your search
+106
-8
@@ -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
|
||||
}
|
||||
Reference in new issue
Block a user