open-vault/vault/keyring.go

167 lines
3.8 KiB
Go

package vault
import (
"bytes"
"encoding/json"
"fmt"
"time"
)
// 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
}
// 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
Version int
Value []byte
InstallTime time.Time
}
// NewKeyring creates a new keyring
func NewKeyring() *Keyring {
k := &Keyring{
keys: make(map[uint32]*Key),
activeTerm: 0,
}
return k
}
// Clone returns a new copy of the keyring
func (k *Keyring) Clone() *Keyring {
clone := &Keyring{
masterKey: k.masterKey,
keys: make(map[uint32]*Key, len(k.keys)),
activeTerm: k.activeTerm,
}
for idx, key := range k.keys {
clone.keys[idx] = key
}
return clone
}
// AddKey adds a new key to the keyring
func (k *Keyring) AddKey(key *Key) (*Keyring, error) {
// Ensure there is no confict
if exist, ok := k.keys[key.Term]; ok {
if !bytes.Equal(key.Value, exist.Value) {
return nil, fmt.Errorf("Conflicting key for term %d already installed", key.Term)
}
return k, nil
}
// Add a time if none
if key.InstallTime.IsZero() {
key.InstallTime = time.Now()
}
// Make a new keyring
clone := k.Clone()
// Install the new key
clone.keys[key.Term] = key
// Update the active term if newer
if key.Term > clone.activeTerm {
clone.activeTerm = key.Term
}
return clone, nil
}
// RemoveKey removes a new key to the keyring
func (k *Keyring) RemoveKey(term uint32) (*Keyring, error) {
// Ensure this is not the active key
if term == k.activeTerm {
return nil, fmt.Errorf("Cannot remove active key")
}
// Check if this term does not exist
if _, ok := k.keys[term]; !ok {
return k, nil
}
// Delete the key
clone := k.Clone()
delete(clone.keys, term)
return clone, nil
}
// ActiveTerm returns the currently active term
func (k *Keyring) ActiveTerm() uint32 {
return k.activeTerm
}
// ActiveKey returns the active encryption key, or nil
func (k *Keyring) ActiveKey() *Key {
return k.keys[k.activeTerm]
}
// TermKey returns the key for the given term, or nil
func (k *Keyring) TermKey(term uint32) *Key {
return k.keys[term]
}
// SetMasterKey is used to update the master key
func (k *Keyring) SetMasterKey(val []byte) *Keyring {
clone := k.Clone()
clone.masterKey = val
return clone
}
// MasterKey returns the master key
func (k *Keyring) MasterKey() []byte {
return k.masterKey
}
// Serialize is used to create a byte encoded keyring
func (k *Keyring) Serialize() ([]byte, error) {
// 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.masterKey = enc.MasterKey
for _, key := range enc.Keys {
k.keys[key.Term] = key
if key.Term > k.activeTerm {
k.activeTerm = key.Term
}
}
return k, nil
}