vault: Adding keyring

This commit is contained in:
Armon Dadgar 2015-05-22 17:04:40 -07:00
parent 70b3b37ffb
commit 57c763a3fa
2 changed files with 327 additions and 0 deletions

158
vault/keyring.go Normal file
View File

@ -0,0 +1,158 @@
package vault
import (
"bytes"
"encoding/json"
"fmt"
"sync"
)
// Keyring is used to manage multiple encryption keys used by
// the barrier. New keys can be installed and each has a sequential term.
// The term used to encrypt a key is prefixed to the key written out.
// All data is encrypted with the latest key, but storing the old keys
// allows for decryption of keys written previously. Along with the encryption
// keys, the keyring also tracks the master key. This is necessary so that
// when a new key is added to the keyring, we can encrypt with the master key
// and write out the new keyring.
type Keyring struct {
masterKey []byte
keys map[uint32]*Key
activeTerm uint32
l sync.RWMutex
}
// EncodedKeyring is used for serialization of the keyring
type EncodedKeyring struct {
MasterKey []byte
Keys []*Key
}
// Key represents a single term, along with the key used.
type Key struct {
Term uint32
Value []byte
}
// NewKeyring creates a new keyring
func NewKeyring() *Keyring {
k := &Keyring{
keys: make(map[uint32]*Key),
activeTerm: 0,
}
return k
}
// AddKey adds a new key to the keyring
func (k *Keyring) AddKey(term uint32, value []byte) error {
k.l.Lock()
defer k.l.Unlock()
// Ensure there is no confict
if key, ok := k.keys[term]; ok {
if !bytes.Equal(key.Value, value) {
return fmt.Errorf("Conflicting key for term %d already installed", term)
}
return nil
}
// Install the new key
key := &Key{
Term: term,
Value: value,
}
k.keys[term] = key
// Update the active term if newer
if term > k.activeTerm {
k.activeTerm = term
}
return nil
}
// RemoveKey removes a new key to the keyring
func (k *Keyring) RemoveKey(term uint32) error {
k.l.Lock()
defer k.l.Unlock()
// Ensure this is not the active key
if term == k.activeTerm {
return fmt.Errorf("Cannot remove active key")
}
// Delete the key
delete(k.keys, term)
return nil
}
// ActiveTerm returns the currently active term
func (k *Keyring) ActiveTerm() uint32 {
k.l.RLock()
defer k.l.RUnlock()
return k.activeTerm
}
// ActiveKey returns the active encryption key, or nil
func (k *Keyring) ActiveKey() *Key {
k.l.RLock()
defer k.l.RUnlock()
return k.keys[k.activeTerm]
}
// TermKey returns the key for the given term, or nil
func (k *Keyring) TermKey(term uint32) *Key {
k.l.RLock()
defer k.l.RUnlock()
return k.keys[term]
}
// SetMasterKey is used to update the master key
func (k *Keyring) SetMasterKey(val []byte) {
k.l.Lock()
defer k.l.Unlock()
k.masterKey = val
}
// MasterKey returns the master key
func (k *Keyring) MasterKey() []byte {
k.l.RLock()
defer k.l.RUnlock()
return k.masterKey
}
// Serialize is used to create a byte encoded keyring
func (k *Keyring) Serialize() ([]byte, error) {
k.l.RLock()
defer k.l.RUnlock()
// Create the encoded entry
enc := EncodedKeyring{
MasterKey: k.masterKey,
}
for _, key := range k.keys {
enc.Keys = append(enc.Keys, key)
}
// JSON encode the keyring
buf, err := json.Marshal(enc)
return buf, err
}
// DeserializeKeyring is used to deserialize and return a new keyring
func DeserializeKeyring(buf []byte) (*Keyring, error) {
// Deserialize the keyring
var enc EncodedKeyring
if err := json.Unmarshal(buf, &enc); err != nil {
return nil, fmt.Errorf("deserialization failed: %v", err)
}
// Create a new keyring
k := NewKeyring()
k.SetMasterKey(enc.MasterKey)
for _, key := range enc.Keys {
if err := k.AddKey(key.Term, key.Value); err != nil {
return nil, fmt.Errorf("failed to add key for term %d: %v", key.Term, err)
}
}
return k, nil
}

169
vault/keyring_test.go Normal file
View File

@ -0,0 +1,169 @@
package vault
import (
"bytes"
"reflect"
"testing"
)
func TestKeyring(t *testing.T) {
k := NewKeyring()
// Term should be 0
if term := k.ActiveTerm(); term != 0 {
t.Fatalf("bad: %d", term)
}
// Should have no key
if key := k.ActiveKey(); key != nil {
t.Fatalf("bad: %v", key)
}
// Add a key
testKey := []byte("testing")
err := k.AddKey(1, testKey)
if err != nil {
t.Fatalf("err: %v", err)
}
// Term should be 1
if term := k.ActiveTerm(); term != 1 {
t.Fatalf("bad: %d", term)
}
// Should have key
key := k.ActiveKey()
if key == nil {
t.Fatalf("bad: %v", key)
}
if !bytes.Equal(key.Value, testKey) {
t.Fatalf("bad: %v", key)
}
if tKey := k.TermKey(1); tKey != key {
t.Fatalf("bad: %v", tKey)
}
// Should handle idempotent set
err = k.AddKey(1, testKey)
if err != nil {
t.Fatalf("err: %v", err)
}
// Should not allow conficting set
testConflict := []byte("nope")
err = k.AddKey(1, testConflict)
if err == nil {
t.Fatalf("err: %v", err)
}
// Add a new key
testSecond := []byte("second")
err = k.AddKey(2, testSecond)
if err != nil {
t.Fatalf("err: %v", err)
}
// Term should be 2
if term := k.ActiveTerm(); term != 2 {
t.Fatalf("bad: %d", term)
}
// Should have key
newKey := k.ActiveKey()
if newKey == nil {
t.Fatalf("bad: %v", key)
}
if !bytes.Equal(newKey.Value, testSecond) {
t.Fatalf("bad: %v", key)
}
if tKey := k.TermKey(2); tKey != newKey {
t.Fatalf("bad: %v", tKey)
}
// Read of old key should work
if tKey := k.TermKey(1); tKey != key {
t.Fatalf("bad: %v", tKey)
}
// Remove the old key
err = k.RemoveKey(1)
if err != nil {
t.Fatalf("err: %v", err)
}
// Read of old key should not work
if tKey := k.TermKey(1); tKey != nil {
t.Fatalf("bad: %v", tKey)
}
// Remove the active key should fail
err = k.RemoveKey(2)
if err == nil {
t.Fatalf("err: %v", err)
}
}
func TestKeyring_MasterKey(t *testing.T) {
k := NewKeyring()
master := []byte("test")
master2 := []byte("test2")
// Check no master
out := k.MasterKey()
if out != nil {
t.Fatalf("bad: %v", out)
}
// Set master
k.SetMasterKey(master)
out = k.MasterKey()
if !bytes.Equal(out, master) {
t.Fatalf("bad: %v", out)
}
// Update master
k.SetMasterKey(master2)
out = k.MasterKey()
if !bytes.Equal(out, master2) {
t.Fatalf("bad: %v", out)
}
}
func TestKeyring_Serialize(t *testing.T) {
k := NewKeyring()
master := []byte("test")
k.SetMasterKey(master)
testKey := []byte("testing")
testSecond := []byte("second")
k.AddKey(1, testKey)
k.AddKey(2, testSecond)
buf, err := k.Serialize()
if err != nil {
t.Fatalf("err: %v", err)
}
k2, err := DeserializeKeyring(buf)
if err != nil {
t.Fatalf("err: %v", err)
}
out := k2.MasterKey()
if !bytes.Equal(out, master) {
t.Fatalf("bad: %v", out)
}
if k2.ActiveTerm() != k.ActiveTerm() {
t.Fatalf("Term mismatch")
}
var i uint32
for i = 1; i < k.ActiveTerm(); i++ {
key1 := k2.TermKey(i)
key2 := k.TermKey(i)
if !reflect.DeepEqual(key1, key2) {
t.Fatalf("bad: %v %v", key1, key2)
}
}
}