547 lines
12 KiB
Go
547 lines
12 KiB
Go
|
// Copyright (c) HashiCorp, Inc.
|
||
|
// SPDX-License-Identifier: MPL-2.0
|
||
|
|
||
|
package vault
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"crypto/rand"
|
||
|
"reflect"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/hashicorp/vault/sdk/logical"
|
||
|
)
|
||
|
|
||
|
func testBarrier(t *testing.T, b SecurityBarrier) {
|
||
|
err, e, key := testInitAndUnseal(t, b)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Operations should work
|
||
|
out, err := b.Get(context.Background(), "test")
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if out != nil {
|
||
|
t.Fatalf("bad: %v", out)
|
||
|
}
|
||
|
|
||
|
// List should have only "core/"
|
||
|
keys, err := b.List(context.Background(), "")
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if len(keys) != 1 || keys[0] != "core/" {
|
||
|
t.Fatalf("bad: %v", keys)
|
||
|
}
|
||
|
|
||
|
// Try to write
|
||
|
if err := b.Put(context.Background(), e); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Should be equal
|
||
|
out, err = b.Get(context.Background(), "test")
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if !reflect.DeepEqual(out, e) {
|
||
|
t.Fatalf("bad: %v exp: %v", out, e)
|
||
|
}
|
||
|
|
||
|
// List should show the items
|
||
|
keys, err = b.List(context.Background(), "")
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if len(keys) != 2 {
|
||
|
t.Fatalf("bad: %v", keys)
|
||
|
}
|
||
|
if keys[0] != "core/" || keys[1] != "test" {
|
||
|
t.Fatalf("bad: %v", keys)
|
||
|
}
|
||
|
|
||
|
// Delete should clear
|
||
|
err = b.Delete(context.Background(), "test")
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Double Delete is fine
|
||
|
err = b.Delete(context.Background(), "test")
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Should be nil
|
||
|
out, err = b.Get(context.Background(), "test")
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if out != nil {
|
||
|
t.Fatalf("bad: %v", out)
|
||
|
}
|
||
|
|
||
|
// List should have nothing
|
||
|
keys, err = b.List(context.Background(), "")
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if len(keys) != 1 || keys[0] != "core/" {
|
||
|
t.Fatalf("bad: %v", keys)
|
||
|
}
|
||
|
|
||
|
// Add the item back
|
||
|
if err := b.Put(context.Background(), e); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Reseal should prevent any updates
|
||
|
if err := b.Seal(); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// No access allowed
|
||
|
if _, err := b.Get(context.Background(), "test"); err != ErrBarrierSealed {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Unseal should work
|
||
|
if err := b.Unseal(context.Background(), key); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Should be equal
|
||
|
out, err = b.Get(context.Background(), "test")
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if !reflect.DeepEqual(out, e) {
|
||
|
t.Fatalf("bad: %v exp: %v", out, e)
|
||
|
}
|
||
|
|
||
|
// Final cleanup
|
||
|
err = b.Delete(context.Background(), "test")
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Reseal should prevent any updates
|
||
|
if err := b.Seal(); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Modify the key
|
||
|
key[0]++
|
||
|
|
||
|
// Unseal should fail
|
||
|
if err := b.Unseal(context.Background(), key); err != ErrBarrierInvalidKey {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func testInitAndUnseal(t *testing.T, b SecurityBarrier) (error, *logical.StorageEntry, []byte) {
|
||
|
// Should not be initialized
|
||
|
init, err := b.Initialized(context.Background())
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if init {
|
||
|
t.Fatalf("should not be initialized")
|
||
|
}
|
||
|
|
||
|
// Should start sealed
|
||
|
sealed, err := b.Sealed()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if !sealed {
|
||
|
t.Fatalf("should be sealed")
|
||
|
}
|
||
|
|
||
|
// Sealing should be a no-op
|
||
|
if err := b.Seal(); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// All operations should fail
|
||
|
e := &logical.StorageEntry{Key: "test", Value: []byte("test")}
|
||
|
if err := b.Put(context.Background(), e); err != ErrBarrierSealed {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if _, err := b.Get(context.Background(), "test"); err != ErrBarrierSealed {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if err := b.Delete(context.Background(), "test"); err != ErrBarrierSealed {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if _, err := b.List(context.Background(), ""); err != ErrBarrierSealed {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Get a new key
|
||
|
key, err := b.GenerateKey(rand.Reader)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Validate minimum key length
|
||
|
min, max := b.KeyLength()
|
||
|
if min < 16 {
|
||
|
t.Fatalf("minimum key size too small: %d", min)
|
||
|
}
|
||
|
if max < min {
|
||
|
t.Fatalf("maximum key size smaller than min")
|
||
|
}
|
||
|
|
||
|
// Unseal should not work
|
||
|
if err := b.Unseal(context.Background(), key); err != ErrBarrierNotInit {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Initialize the vault
|
||
|
if err := b.Initialize(context.Background(), key, nil, rand.Reader); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Double Initialize should fail
|
||
|
if err := b.Initialize(context.Background(), key, nil, rand.Reader); err != ErrBarrierAlreadyInit {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Should be initialized
|
||
|
init, err = b.Initialized(context.Background())
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if !init {
|
||
|
t.Fatalf("should be initialized")
|
||
|
}
|
||
|
|
||
|
// Should still be sealed
|
||
|
sealed, err = b.Sealed()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if !sealed {
|
||
|
t.Fatalf("should sealed")
|
||
|
}
|
||
|
|
||
|
// Unseal should work
|
||
|
if err := b.Unseal(context.Background(), key); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Unseal should no-op when done twice
|
||
|
if err := b.Unseal(context.Background(), key); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Should no longer be sealed
|
||
|
sealed, err = b.Sealed()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if sealed {
|
||
|
t.Fatalf("should be unsealed")
|
||
|
}
|
||
|
|
||
|
// Verify the root key
|
||
|
if err := b.VerifyRoot(key); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
return err, e, key
|
||
|
}
|
||
|
|
||
|
func testBarrier_Rotate(t *testing.T, b SecurityBarrier) {
|
||
|
// Initialize the barrier
|
||
|
key, _ := b.GenerateKey(rand.Reader)
|
||
|
b.Initialize(context.Background(), key, nil, rand.Reader)
|
||
|
err := b.Unseal(context.Background(), key)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Check the key info
|
||
|
info, err := b.ActiveKeyInfo()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if info.Term != 1 {
|
||
|
t.Fatalf("Bad term: %d", info.Term)
|
||
|
}
|
||
|
if time.Since(info.InstallTime) > time.Second {
|
||
|
t.Fatalf("Bad install: %v", info.InstallTime)
|
||
|
}
|
||
|
first := info.InstallTime
|
||
|
|
||
|
// Write a key
|
||
|
e1 := &logical.StorageEntry{Key: "test", Value: []byte("test")}
|
||
|
if err := b.Put(context.Background(), e1); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Rotate the encryption key
|
||
|
newTerm, err := b.Rotate(context.Background(), rand.Reader)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if newTerm != 2 {
|
||
|
t.Fatalf("bad: %v", newTerm)
|
||
|
}
|
||
|
|
||
|
// Check the key info
|
||
|
info, err = b.ActiveKeyInfo()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if info.Term != 2 {
|
||
|
t.Fatalf("Bad term: %d", info.Term)
|
||
|
}
|
||
|
if !info.InstallTime.After(first) {
|
||
|
t.Fatalf("Bad install: %v", info.InstallTime)
|
||
|
}
|
||
|
|
||
|
// Write another key
|
||
|
e2 := &logical.StorageEntry{Key: "foo", Value: []byte("test")}
|
||
|
if err := b.Put(context.Background(), e2); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Reading both should work
|
||
|
out, err := b.Get(context.Background(), e1.Key)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if out == nil {
|
||
|
t.Fatalf("bad: %v", out)
|
||
|
}
|
||
|
|
||
|
out, err = b.Get(context.Background(), e2.Key)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if out == nil {
|
||
|
t.Fatalf("bad: %v", out)
|
||
|
}
|
||
|
|
||
|
// Seal and unseal
|
||
|
err = b.Seal()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
err = b.Unseal(context.Background(), key)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Reading both should work
|
||
|
out, err = b.Get(context.Background(), e1.Key)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if out == nil {
|
||
|
t.Fatalf("bad: %v", out)
|
||
|
}
|
||
|
|
||
|
out, err = b.Get(context.Background(), e2.Key)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if out == nil {
|
||
|
t.Fatalf("bad: %v", out)
|
||
|
}
|
||
|
|
||
|
// Should be fine to reload keyring
|
||
|
err = b.ReloadKeyring(context.Background())
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func testBarrier_Rekey(t *testing.T, b SecurityBarrier) {
|
||
|
// Initialize the barrier
|
||
|
key, _ := b.GenerateKey(rand.Reader)
|
||
|
b.Initialize(context.Background(), key, nil, rand.Reader)
|
||
|
err := b.Unseal(context.Background(), key)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Write a key
|
||
|
e1 := &logical.StorageEntry{Key: "test", Value: []byte("test")}
|
||
|
if err := b.Put(context.Background(), e1); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Verify the master key
|
||
|
if err := b.VerifyRoot(key); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Rekey to a new key
|
||
|
newKey, _ := b.GenerateKey(rand.Reader)
|
||
|
err = b.Rekey(context.Background(), newKey)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Verify the old master key
|
||
|
if err := b.VerifyRoot(key); err != ErrBarrierInvalidKey {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Verify the new master key
|
||
|
if err := b.VerifyRoot(newKey); err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Reading should work
|
||
|
out, err := b.Get(context.Background(), e1.Key)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if out == nil {
|
||
|
t.Fatalf("bad: %v", out)
|
||
|
}
|
||
|
|
||
|
// Seal
|
||
|
err = b.Seal()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Unseal with old key should fail
|
||
|
err = b.Unseal(context.Background(), key)
|
||
|
if err == nil {
|
||
|
t.Fatalf("unseal should fail")
|
||
|
}
|
||
|
|
||
|
// Unseal with new keys should work
|
||
|
err = b.Unseal(context.Background(), newKey)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Reading should work
|
||
|
out, err = b.Get(context.Background(), e1.Key)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if out == nil {
|
||
|
t.Fatalf("bad: %v", out)
|
||
|
}
|
||
|
|
||
|
// Should be fine to reload keyring
|
||
|
err = b.ReloadKeyring(context.Background())
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func testBarrier_Upgrade(t *testing.T, b1, b2 SecurityBarrier) {
|
||
|
// Initialize the barrier
|
||
|
key, _ := b1.GenerateKey(rand.Reader)
|
||
|
b1.Initialize(context.Background(), key, nil, rand.Reader)
|
||
|
err := b1.Unseal(context.Background(), key)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
err = b2.Unseal(context.Background(), key)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Rotate the encryption key
|
||
|
newTerm, err := b1.Rotate(context.Background(), rand.Reader)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Create upgrade path
|
||
|
err = b1.CreateUpgrade(context.Background(), newTerm)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Check for an upgrade
|
||
|
did, updated, err := b2.CheckUpgrade(context.Background())
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if !did || updated != newTerm {
|
||
|
t.Fatalf("failed to upgrade")
|
||
|
}
|
||
|
|
||
|
// Should have no upgrades pending
|
||
|
did, updated, err = b2.CheckUpgrade(context.Background())
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if did {
|
||
|
t.Fatalf("should not have upgrade")
|
||
|
}
|
||
|
|
||
|
// Rotate the encryption key
|
||
|
newTerm, err = b1.Rotate(context.Background(), rand.Reader)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Create upgrade path
|
||
|
err = b1.CreateUpgrade(context.Background(), newTerm)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Destroy upgrade path
|
||
|
err = b1.DestroyUpgrade(context.Background(), newTerm)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Should have no upgrades pending
|
||
|
did, updated, err = b2.CheckUpgrade(context.Background())
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
if did {
|
||
|
t.Fatalf("should not have upgrade")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func testBarrier_Upgrade_Rekey(t *testing.T, b1, b2 SecurityBarrier) {
|
||
|
// Initialize the barrier
|
||
|
key, _ := b1.GenerateKey(rand.Reader)
|
||
|
b1.Initialize(context.Background(), key, nil, rand.Reader)
|
||
|
err := b1.Unseal(context.Background(), key)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
err = b2.Unseal(context.Background(), key)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Rekey to a new key
|
||
|
newKey, _ := b1.GenerateKey(rand.Reader)
|
||
|
err = b1.Rekey(context.Background(), newKey)
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Reload the master key
|
||
|
err = b2.ReloadRootKey(context.Background())
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
|
||
|
// Reload the keyring
|
||
|
err = b2.ReloadKeyring(context.Background())
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %v", err)
|
||
|
}
|
||
|
}
|