2015-04-16 00:08:12 +00:00
|
|
|
package transit
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/base64"
|
|
|
|
"fmt"
|
2015-09-14 20:28:46 +00:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
2015-04-16 00:08:12 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/hashicorp/vault/logical"
|
|
|
|
logicaltest "github.com/hashicorp/vault/logical/testing"
|
|
|
|
"github.com/mitchellh/mapstructure"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
testPlaintext = "the quick brown fox"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestBackend_basic(t *testing.T) {
|
|
|
|
decryptData := make(map[string]interface{})
|
|
|
|
logicaltest.Test(t, logicaltest.TestCase{
|
2016-01-27 21:24:11 +00:00
|
|
|
Factory: Factory,
|
2015-04-16 00:08:12 +00:00
|
|
|
Steps: []logicaltest.TestStep{
|
2015-07-05 21:30:45 +00:00
|
|
|
testAccStepWritePolicy(t, "test", false),
|
|
|
|
testAccStepReadPolicy(t, "test", false, false),
|
2015-04-16 00:08:12 +00:00
|
|
|
testAccStepEncrypt(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
2015-09-14 20:28:46 +00:00
|
|
|
testAccStepDeleteNotDisabledPolicy(t, "test"),
|
2015-09-17 22:49:50 +00:00
|
|
|
testAccStepEnableDeletion(t, "test"),
|
2015-09-14 20:28:46 +00:00
|
|
|
testAccStepDeletePolicy(t, "test"),
|
|
|
|
testAccStepWritePolicy(t, "test", false),
|
2015-09-17 22:49:50 +00:00
|
|
|
testAccStepEnableDeletion(t, "test"),
|
|
|
|
testAccStepDisableDeletion(t, "test"),
|
2015-09-14 20:28:46 +00:00
|
|
|
testAccStepDeleteNotDisabledPolicy(t, "test"),
|
2015-09-17 22:49:50 +00:00
|
|
|
testAccStepEnableDeletion(t, "test"),
|
2015-09-14 20:28:46 +00:00
|
|
|
testAccStepDeletePolicy(t, "test"),
|
|
|
|
testAccStepReadPolicy(t, "test", true, false),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-02-02 14:58:12 +00:00
|
|
|
func TestBackend_upsert(t *testing.T) {
|
|
|
|
decryptData := make(map[string]interface{})
|
|
|
|
logicaltest.Test(t, logicaltest.TestCase{
|
|
|
|
Factory: Factory,
|
|
|
|
Steps: []logicaltest.TestStep{
|
|
|
|
testAccStepReadPolicy(t, "test", true, false),
|
|
|
|
testAccStepEncryptUpsert(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepReadPolicy(t, "test", false, false),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-09-18 13:50:53 +00:00
|
|
|
func TestBackend_datakey(t *testing.T) {
|
|
|
|
dataKeyInfo := make(map[string]interface{})
|
|
|
|
logicaltest.Test(t, logicaltest.TestCase{
|
2016-01-27 21:24:11 +00:00
|
|
|
Factory: Factory,
|
2015-09-18 13:50:53 +00:00
|
|
|
Steps: []logicaltest.TestStep{
|
|
|
|
testAccStepWritePolicy(t, "test", false),
|
|
|
|
testAccStepReadPolicy(t, "test", false, false),
|
|
|
|
testAccStepWriteDatakey(t, "test", false, 256, dataKeyInfo),
|
|
|
|
testAccStepDecryptDatakey(t, "test", dataKeyInfo),
|
|
|
|
testAccStepWriteDatakey(t, "test", true, 128, dataKeyInfo),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-09-14 20:28:46 +00:00
|
|
|
func TestBackend_rotation(t *testing.T) {
|
|
|
|
decryptData := make(map[string]interface{})
|
|
|
|
encryptHistory := make(map[int]map[string]interface{})
|
|
|
|
logicaltest.Test(t, logicaltest.TestCase{
|
2016-01-27 21:24:11 +00:00
|
|
|
Factory: Factory,
|
2015-09-14 20:28:46 +00:00
|
|
|
Steps: []logicaltest.TestStep{
|
|
|
|
testAccStepWritePolicy(t, "test", false),
|
|
|
|
testAccStepEncryptVX(t, "test", testPlaintext, decryptData, 0, encryptHistory),
|
|
|
|
testAccStepEncryptVX(t, "test", testPlaintext, decryptData, 1, encryptHistory),
|
|
|
|
testAccStepRotate(t, "test"), // now v2
|
|
|
|
testAccStepEncryptVX(t, "test", testPlaintext, decryptData, 2, encryptHistory),
|
|
|
|
testAccStepRotate(t, "test"), // now v3
|
|
|
|
testAccStepEncryptVX(t, "test", testPlaintext, decryptData, 3, encryptHistory),
|
|
|
|
testAccStepRotate(t, "test"), // now v4
|
|
|
|
testAccStepEncryptVX(t, "test", testPlaintext, decryptData, 4, encryptHistory),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepEncryptVX(t, "test", testPlaintext, decryptData, 99, encryptHistory),
|
|
|
|
testAccStepDecryptExpectFailure(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepLoadVX(t, "test", decryptData, 0, encryptHistory),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepLoadVX(t, "test", decryptData, 1, encryptHistory),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepLoadVX(t, "test", decryptData, 2, encryptHistory),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepLoadVX(t, "test", decryptData, 3, encryptHistory),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepLoadVX(t, "test", decryptData, 99, encryptHistory),
|
|
|
|
testAccStepDecryptExpectFailure(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepLoadVX(t, "test", decryptData, 4, encryptHistory),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepDeleteNotDisabledPolicy(t, "test"),
|
|
|
|
testAccStepAdjustPolicy(t, "test", 3),
|
|
|
|
testAccStepLoadVX(t, "test", decryptData, 0, encryptHistory),
|
|
|
|
testAccStepDecryptExpectFailure(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepLoadVX(t, "test", decryptData, 1, encryptHistory),
|
|
|
|
testAccStepDecryptExpectFailure(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepLoadVX(t, "test", decryptData, 2, encryptHistory),
|
|
|
|
testAccStepDecryptExpectFailure(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepLoadVX(t, "test", decryptData, 3, encryptHistory),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepLoadVX(t, "test", decryptData, 4, encryptHistory),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepAdjustPolicy(t, "test", 1),
|
|
|
|
testAccStepLoadVX(t, "test", decryptData, 0, encryptHistory),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepLoadVX(t, "test", decryptData, 1, encryptHistory),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepLoadVX(t, "test", decryptData, 2, encryptHistory),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
|
|
|
testAccStepRewrap(t, "test", decryptData, 4),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
2015-09-17 22:49:50 +00:00
|
|
|
testAccStepEnableDeletion(t, "test"),
|
2015-04-16 00:08:12 +00:00
|
|
|
testAccStepDeletePolicy(t, "test"),
|
2015-07-05 21:30:45 +00:00
|
|
|
testAccStepReadPolicy(t, "test", true, false),
|
2015-04-16 00:08:12 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-07-05 21:30:45 +00:00
|
|
|
func TestBackend_basic_derived(t *testing.T) {
|
|
|
|
decryptData := make(map[string]interface{})
|
|
|
|
logicaltest.Test(t, logicaltest.TestCase{
|
2016-01-27 21:24:11 +00:00
|
|
|
Factory: Factory,
|
2015-07-05 21:30:45 +00:00
|
|
|
Steps: []logicaltest.TestStep{
|
|
|
|
testAccStepWritePolicy(t, "test", true),
|
|
|
|
testAccStepReadPolicy(t, "test", false, true),
|
|
|
|
testAccStepEncryptContext(t, "test", testPlaintext, "my-cool-context", decryptData),
|
|
|
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
2015-09-17 22:49:50 +00:00
|
|
|
testAccStepEnableDeletion(t, "test"),
|
2015-07-05 21:30:45 +00:00
|
|
|
testAccStepDeletePolicy(t, "test"),
|
|
|
|
testAccStepReadPolicy(t, "test", true, true),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAccStepWritePolicy(t *testing.T, name string, derived bool) logicaltest.TestStep {
|
2015-04-16 00:08:12 +00:00
|
|
|
return logicaltest.TestStep{
|
2016-01-07 15:30:47 +00:00
|
|
|
Operation: logical.UpdateOperation,
|
2015-04-27 20:52:47 +00:00
|
|
|
Path: "keys/" + name,
|
2015-07-05 21:30:45 +00:00
|
|
|
Data: map[string]interface{}{
|
|
|
|
"derived": derived,
|
|
|
|
},
|
2015-04-16 00:08:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-17 22:49:50 +00:00
|
|
|
func testAccStepAdjustPolicy(t *testing.T, name string, minVer int) logicaltest.TestStep {
|
2015-09-14 20:28:46 +00:00
|
|
|
return logicaltest.TestStep{
|
2016-01-07 15:30:47 +00:00
|
|
|
Operation: logical.UpdateOperation,
|
2015-09-17 22:49:50 +00:00
|
|
|
Path: "keys/" + name + "/config",
|
|
|
|
Data: map[string]interface{}{
|
|
|
|
"min_decryption_version": minVer,
|
|
|
|
},
|
2015-09-14 20:28:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-17 22:49:50 +00:00
|
|
|
func testAccStepDisableDeletion(t *testing.T, name string) logicaltest.TestStep {
|
2015-09-14 20:28:46 +00:00
|
|
|
return logicaltest.TestStep{
|
2016-01-07 15:30:47 +00:00
|
|
|
Operation: logical.UpdateOperation,
|
2015-09-14 20:28:46 +00:00
|
|
|
Path: "keys/" + name + "/config",
|
|
|
|
Data: map[string]interface{}{
|
2015-09-17 22:49:50 +00:00
|
|
|
"deletion_allowed": false,
|
2015-09-14 20:28:46 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-17 22:49:50 +00:00
|
|
|
func testAccStepEnableDeletion(t *testing.T, name string) logicaltest.TestStep {
|
2015-09-14 20:28:46 +00:00
|
|
|
return logicaltest.TestStep{
|
2016-01-07 15:30:47 +00:00
|
|
|
Operation: logical.UpdateOperation,
|
2015-09-17 22:49:50 +00:00
|
|
|
Path: "keys/" + name + "/config",
|
|
|
|
Data: map[string]interface{}{
|
|
|
|
"deletion_allowed": true,
|
|
|
|
},
|
2015-09-14 20:28:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-16 00:08:12 +00:00
|
|
|
func testAccStepDeletePolicy(t *testing.T, name string) logicaltest.TestStep {
|
|
|
|
return logicaltest.TestStep{
|
|
|
|
Operation: logical.DeleteOperation,
|
2015-04-27 20:52:47 +00:00
|
|
|
Path: "keys/" + name,
|
2015-04-16 00:08:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-14 20:28:46 +00:00
|
|
|
func testAccStepDeleteNotDisabledPolicy(t *testing.T, name string) logicaltest.TestStep {
|
2015-04-16 00:08:12 +00:00
|
|
|
return logicaltest.TestStep{
|
2015-09-14 20:28:46 +00:00
|
|
|
Operation: logical.DeleteOperation,
|
2015-04-27 20:52:47 +00:00
|
|
|
Path: "keys/" + name,
|
2015-09-14 20:28:46 +00:00
|
|
|
ErrorOk: true,
|
2015-04-16 00:08:12 +00:00
|
|
|
Check: func(resp *logical.Response) error {
|
2015-09-17 22:49:50 +00:00
|
|
|
if resp == nil {
|
|
|
|
return fmt.Errorf("Got nil response instead of error")
|
|
|
|
}
|
2015-09-14 20:28:46 +00:00
|
|
|
if resp.IsError() {
|
2015-06-18 01:42:23 +00:00
|
|
|
return nil
|
|
|
|
}
|
2015-09-14 20:28:46 +00:00
|
|
|
return fmt.Errorf("expected error but did not get one")
|
2015-06-18 01:42:23 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-14 20:28:46 +00:00
|
|
|
func testAccStepReadPolicy(t *testing.T, name string, expectNone, derived bool) logicaltest.TestStep {
|
2015-06-18 01:42:23 +00:00
|
|
|
return logicaltest.TestStep{
|
|
|
|
Operation: logical.ReadOperation,
|
2015-09-14 20:28:46 +00:00
|
|
|
Path: "keys/" + name,
|
2015-06-18 01:42:23 +00:00
|
|
|
Check: func(resp *logical.Response) error {
|
|
|
|
if resp == nil && !expectNone {
|
2015-04-16 00:08:12 +00:00
|
|
|
return fmt.Errorf("missing response")
|
|
|
|
} else if expectNone {
|
|
|
|
if resp != nil {
|
|
|
|
return fmt.Errorf("response when expecting none")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
var d struct {
|
2015-09-17 22:49:50 +00:00
|
|
|
Name string `mapstructure:"name"`
|
|
|
|
Key []byte `mapstructure:"key"`
|
|
|
|
Keys map[string]int64 `mapstructure:"keys"`
|
|
|
|
CipherMode string `mapstructure:"cipher_mode"`
|
|
|
|
Derived bool `mapstructure:"derived"`
|
|
|
|
KDFMode string `mapstructure:"kdf_mode"`
|
|
|
|
DeletionAllowed bool `mapstructure:"deletion_allowed"`
|
2015-04-16 00:08:12 +00:00
|
|
|
}
|
|
|
|
if err := mapstructure.Decode(resp.Data, &d); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if d.Name != name {
|
|
|
|
return fmt.Errorf("bad: %#v", d)
|
|
|
|
}
|
|
|
|
if d.CipherMode != "aes-gcm" {
|
|
|
|
return fmt.Errorf("bad: %#v", d)
|
|
|
|
}
|
2015-09-14 20:28:46 +00:00
|
|
|
// Should NOT get a key back
|
|
|
|
if d.Key != nil {
|
|
|
|
return fmt.Errorf("bad: %#v", d)
|
|
|
|
}
|
2015-09-17 22:49:50 +00:00
|
|
|
if d.Keys == nil {
|
2015-09-14 20:28:46 +00:00
|
|
|
return fmt.Errorf("bad: %#v", d)
|
|
|
|
}
|
2015-09-17 22:49:50 +00:00
|
|
|
if d.DeletionAllowed == true {
|
2015-04-16 00:08:12 +00:00
|
|
|
return fmt.Errorf("bad: %#v", d)
|
|
|
|
}
|
2015-07-05 21:30:45 +00:00
|
|
|
if d.Derived != derived {
|
|
|
|
return fmt.Errorf("bad: %#v", d)
|
|
|
|
}
|
2015-07-06 01:58:31 +00:00
|
|
|
if derived && d.KDFMode != kdfMode {
|
2015-07-05 21:30:45 +00:00
|
|
|
return fmt.Errorf("bad: %#v", d)
|
|
|
|
}
|
2015-04-16 00:08:12 +00:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAccStepEncrypt(
|
|
|
|
t *testing.T, name, plaintext string, decryptData map[string]interface{}) logicaltest.TestStep {
|
|
|
|
return logicaltest.TestStep{
|
2016-01-07 15:30:47 +00:00
|
|
|
Operation: logical.UpdateOperation,
|
2015-04-16 00:08:12 +00:00
|
|
|
Path: "encrypt/" + name,
|
|
|
|
Data: map[string]interface{}{
|
|
|
|
"plaintext": base64.StdEncoding.EncodeToString([]byte(plaintext)),
|
|
|
|
},
|
|
|
|
Check: func(resp *logical.Response) error {
|
|
|
|
var d struct {
|
|
|
|
Ciphertext string `mapstructure:"ciphertext"`
|
2016-02-02 14:58:12 +00:00
|
|
|
}
|
|
|
|
if err := mapstructure.Decode(resp.Data, &d); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if d.Ciphertext == "" {
|
|
|
|
return fmt.Errorf("missing ciphertext")
|
|
|
|
}
|
|
|
|
decryptData["ciphertext"] = d.Ciphertext
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAccStepEncryptUpsert(
|
|
|
|
t *testing.T, name, plaintext string, decryptData map[string]interface{}) logicaltest.TestStep {
|
|
|
|
return logicaltest.TestStep{
|
|
|
|
Operation: logical.CreateOperation,
|
|
|
|
Path: "encrypt/" + name,
|
|
|
|
Data: map[string]interface{}{
|
|
|
|
"plaintext": base64.StdEncoding.EncodeToString([]byte(plaintext)),
|
|
|
|
},
|
|
|
|
Check: func(resp *logical.Response) error {
|
|
|
|
var d struct {
|
|
|
|
Ciphertext string `mapstructure:"ciphertext"`
|
2015-04-16 00:08:12 +00:00
|
|
|
}
|
|
|
|
if err := mapstructure.Decode(resp.Data, &d); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if d.Ciphertext == "" {
|
|
|
|
return fmt.Errorf("missing ciphertext")
|
|
|
|
}
|
|
|
|
decryptData["ciphertext"] = d.Ciphertext
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-05 21:30:45 +00:00
|
|
|
func testAccStepEncryptContext(
|
|
|
|
t *testing.T, name, plaintext, context string, decryptData map[string]interface{}) logicaltest.TestStep {
|
|
|
|
return logicaltest.TestStep{
|
2016-01-07 15:30:47 +00:00
|
|
|
Operation: logical.UpdateOperation,
|
2015-07-05 21:30:45 +00:00
|
|
|
Path: "encrypt/" + name,
|
|
|
|
Data: map[string]interface{}{
|
|
|
|
"plaintext": base64.StdEncoding.EncodeToString([]byte(plaintext)),
|
2015-07-05 21:37:51 +00:00
|
|
|
"context": base64.StdEncoding.EncodeToString([]byte(context)),
|
2015-07-05 21:30:45 +00:00
|
|
|
},
|
|
|
|
Check: func(resp *logical.Response) error {
|
|
|
|
var d struct {
|
|
|
|
Ciphertext string `mapstructure:"ciphertext"`
|
|
|
|
}
|
|
|
|
if err := mapstructure.Decode(resp.Data, &d); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if d.Ciphertext == "" {
|
|
|
|
return fmt.Errorf("missing ciphertext")
|
|
|
|
}
|
|
|
|
decryptData["ciphertext"] = d.Ciphertext
|
2015-07-05 21:37:51 +00:00
|
|
|
decryptData["context"] = base64.StdEncoding.EncodeToString([]byte(context))
|
2015-07-05 21:30:45 +00:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-16 00:08:12 +00:00
|
|
|
func testAccStepDecrypt(
|
|
|
|
t *testing.T, name, plaintext string, decryptData map[string]interface{}) logicaltest.TestStep {
|
|
|
|
return logicaltest.TestStep{
|
2016-01-07 15:30:47 +00:00
|
|
|
Operation: logical.UpdateOperation,
|
2015-04-16 00:08:12 +00:00
|
|
|
Path: "decrypt/" + name,
|
|
|
|
Data: decryptData,
|
|
|
|
Check: func(resp *logical.Response) error {
|
|
|
|
var d struct {
|
|
|
|
Plaintext string `mapstructure:"plaintext"`
|
|
|
|
}
|
|
|
|
if err := mapstructure.Decode(resp.Data, &d); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decode the base64
|
|
|
|
plainRaw, err := base64.StdEncoding.DecodeString(d.Plaintext)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if string(plainRaw) != plaintext {
|
2015-09-14 20:28:46 +00:00
|
|
|
return fmt.Errorf("plaintext mismatch: %s expect: %s, decryptData was %#v", plainRaw, plaintext, decryptData)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAccStepRewrap(
|
|
|
|
t *testing.T, name string, decryptData map[string]interface{}, expectedVer int) logicaltest.TestStep {
|
|
|
|
return logicaltest.TestStep{
|
2016-01-07 15:30:47 +00:00
|
|
|
Operation: logical.UpdateOperation,
|
2015-09-14 20:28:46 +00:00
|
|
|
Path: "rewrap/" + name,
|
|
|
|
Data: decryptData,
|
|
|
|
Check: func(resp *logical.Response) error {
|
|
|
|
var d struct {
|
|
|
|
Ciphertext string `mapstructure:"ciphertext"`
|
|
|
|
}
|
|
|
|
if err := mapstructure.Decode(resp.Data, &d); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if d.Ciphertext == "" {
|
|
|
|
return fmt.Errorf("missing ciphertext")
|
|
|
|
}
|
|
|
|
splitStrings := strings.Split(d.Ciphertext, ":")
|
|
|
|
verString := splitStrings[1][1:]
|
|
|
|
ver, err := strconv.Atoi(verString)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error pulling out version from verString '%s', ciphertext was %s", verString, d.Ciphertext)
|
2015-04-16 00:08:12 +00:00
|
|
|
}
|
2015-09-14 20:28:46 +00:00
|
|
|
if ver != expectedVer {
|
|
|
|
return fmt.Errorf("Did not get expected version")
|
|
|
|
}
|
|
|
|
decryptData["ciphertext"] = d.Ciphertext
|
2015-04-16 00:08:12 +00:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2015-09-14 20:28:46 +00:00
|
|
|
|
|
|
|
func testAccStepEncryptVX(
|
|
|
|
t *testing.T, name, plaintext string, decryptData map[string]interface{},
|
|
|
|
ver int, encryptHistory map[int]map[string]interface{}) logicaltest.TestStep {
|
|
|
|
return logicaltest.TestStep{
|
2016-01-07 15:30:47 +00:00
|
|
|
Operation: logical.UpdateOperation,
|
2015-09-14 20:28:46 +00:00
|
|
|
Path: "encrypt/" + name,
|
|
|
|
Data: map[string]interface{}{
|
|
|
|
"plaintext": base64.StdEncoding.EncodeToString([]byte(plaintext)),
|
|
|
|
},
|
|
|
|
Check: func(resp *logical.Response) error {
|
|
|
|
var d struct {
|
|
|
|
Ciphertext string `mapstructure:"ciphertext"`
|
|
|
|
}
|
|
|
|
if err := mapstructure.Decode(resp.Data, &d); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if d.Ciphertext == "" {
|
|
|
|
return fmt.Errorf("missing ciphertext")
|
|
|
|
}
|
|
|
|
splitStrings := strings.Split(d.Ciphertext, ":")
|
|
|
|
splitStrings[1] = "v" + strconv.Itoa(ver)
|
|
|
|
ciphertext := strings.Join(splitStrings, ":")
|
|
|
|
decryptData["ciphertext"] = ciphertext
|
|
|
|
encryptHistory[ver] = map[string]interface{}{
|
|
|
|
"ciphertext": ciphertext,
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAccStepLoadVX(
|
|
|
|
t *testing.T, name string, decryptData map[string]interface{},
|
|
|
|
ver int, encryptHistory map[int]map[string]interface{}) logicaltest.TestStep {
|
|
|
|
// This is really a no-op to allow us to do data manip in the check function
|
|
|
|
return logicaltest.TestStep{
|
|
|
|
Operation: logical.ReadOperation,
|
|
|
|
Path: "keys/" + name,
|
|
|
|
Check: func(resp *logical.Response) error {
|
|
|
|
decryptData["ciphertext"] = encryptHistory[ver]["ciphertext"].(string)
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAccStepDecryptExpectFailure(
|
|
|
|
t *testing.T, name, plaintext string, decryptData map[string]interface{}) logicaltest.TestStep {
|
|
|
|
return logicaltest.TestStep{
|
2016-01-07 15:30:47 +00:00
|
|
|
Operation: logical.UpdateOperation,
|
2015-09-14 20:28:46 +00:00
|
|
|
Path: "decrypt/" + name,
|
|
|
|
Data: decryptData,
|
|
|
|
ErrorOk: true,
|
|
|
|
Check: func(resp *logical.Response) error {
|
|
|
|
if !resp.IsError() {
|
|
|
|
return fmt.Errorf("expected error")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAccStepRotate(t *testing.T, name string) logicaltest.TestStep {
|
|
|
|
return logicaltest.TestStep{
|
2016-01-07 15:30:47 +00:00
|
|
|
Operation: logical.UpdateOperation,
|
2015-09-14 20:28:46 +00:00
|
|
|
Path: "keys/" + name + "/rotate",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-18 13:50:53 +00:00
|
|
|
func testAccStepWriteDatakey(t *testing.T, name string,
|
|
|
|
noPlaintext bool, bits int,
|
|
|
|
dataKeyInfo map[string]interface{}) logicaltest.TestStep {
|
|
|
|
data := map[string]interface{}{}
|
2015-09-18 18:40:06 +00:00
|
|
|
subPath := "plaintext"
|
2015-09-18 13:50:53 +00:00
|
|
|
if noPlaintext {
|
2015-09-18 18:40:06 +00:00
|
|
|
subPath = "wrapped"
|
2015-09-18 13:50:53 +00:00
|
|
|
}
|
|
|
|
if bits != 256 {
|
|
|
|
data["bits"] = bits
|
|
|
|
}
|
|
|
|
return logicaltest.TestStep{
|
2016-01-07 15:30:47 +00:00
|
|
|
Operation: logical.UpdateOperation,
|
2015-09-18 18:40:06 +00:00
|
|
|
Path: "datakey/" + subPath + "/" + name,
|
2015-09-18 13:50:53 +00:00
|
|
|
Data: data,
|
|
|
|
Check: func(resp *logical.Response) error {
|
|
|
|
var d struct {
|
|
|
|
Plaintext string `mapstructure:"plaintext"`
|
|
|
|
Ciphertext string `mapstructure:"ciphertext"`
|
|
|
|
}
|
|
|
|
if err := mapstructure.Decode(resp.Data, &d); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if noPlaintext && len(d.Plaintext) != 0 {
|
|
|
|
return fmt.Errorf("received plaintxt when we disabled it")
|
|
|
|
}
|
|
|
|
if !noPlaintext {
|
|
|
|
if len(d.Plaintext) == 0 {
|
|
|
|
return fmt.Errorf("did not get plaintext when we expected it")
|
|
|
|
}
|
|
|
|
dataKeyInfo["plaintext"] = d.Plaintext
|
|
|
|
plainBytes, err := base64.StdEncoding.DecodeString(d.Plaintext)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not base64 decode plaintext string '%s'", d.Plaintext)
|
|
|
|
}
|
|
|
|
if len(plainBytes)*8 != bits {
|
|
|
|
return fmt.Errorf("returned key does not have correct bit length")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dataKeyInfo["ciphertext"] = d.Ciphertext
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAccStepDecryptDatakey(t *testing.T, name string,
|
|
|
|
dataKeyInfo map[string]interface{}) logicaltest.TestStep {
|
|
|
|
return logicaltest.TestStep{
|
2016-01-07 15:30:47 +00:00
|
|
|
Operation: logical.UpdateOperation,
|
2015-09-18 13:50:53 +00:00
|
|
|
Path: "decrypt/" + name,
|
|
|
|
Data: dataKeyInfo,
|
|
|
|
Check: func(resp *logical.Response) error {
|
|
|
|
var d struct {
|
|
|
|
Plaintext string `mapstructure:"plaintext"`
|
|
|
|
}
|
|
|
|
if err := mapstructure.Decode(resp.Data, &d); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if d.Plaintext != dataKeyInfo["plaintext"].(string) {
|
|
|
|
return fmt.Errorf("plaintext mismatch: got '%s', expected '%s', decryptData was %#v", d.Plaintext, dataKeyInfo["plaintext"].(string))
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-14 20:28:46 +00:00
|
|
|
func TestKeyUpgrade(t *testing.T) {
|
|
|
|
p := &Policy{
|
|
|
|
Name: "test",
|
|
|
|
Key: []byte(testPlaintext),
|
|
|
|
CipherMode: "aes-gcm",
|
|
|
|
}
|
|
|
|
|
|
|
|
p.migrateKeyToKeysMap()
|
|
|
|
|
|
|
|
if p.Key != nil ||
|
|
|
|
p.Keys == nil ||
|
|
|
|
len(p.Keys) != 1 ||
|
|
|
|
string(p.Keys[1].Key) != testPlaintext {
|
|
|
|
t.Errorf("bad key migration, result is %#v", p.Keys)
|
|
|
|
}
|
|
|
|
}
|