7f2717b74a
* transit: change batch input format * transit: no json-in-json for batch response * docs: transit: update batch input format * transit: fix tests after changing response format
548 lines
14 KiB
Go
548 lines
14 KiB
Go
package transit
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/hashicorp/vault/logical"
|
|
"github.com/mitchellh/mapstructure"
|
|
)
|
|
|
|
// Case1: Ensure that batch encryption did not affect the normal flow of
|
|
// encrypting the plaintext with a pre-existing key.
|
|
func TestTransit_BatchEncryptionCase1(t *testing.T) {
|
|
var resp *logical.Response
|
|
var err error
|
|
|
|
b, s := createBackendWithStorage(t)
|
|
|
|
// Create the policy
|
|
policyReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "keys/existing_key",
|
|
Storage: s,
|
|
}
|
|
resp, err = b.HandleRequest(policyReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
plaintext := "dGhlIHF1aWNrIGJyb3duIGZveA=="
|
|
|
|
encData := map[string]interface{}{
|
|
"plaintext": plaintext,
|
|
}
|
|
|
|
encReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "encrypt/existing_key",
|
|
Storage: s,
|
|
Data: encData,
|
|
}
|
|
resp, err = b.HandleRequest(encReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
ciphertext := resp.Data["ciphertext"]
|
|
|
|
decData := map[string]interface{}{
|
|
"ciphertext": ciphertext,
|
|
}
|
|
decReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "decrypt/existing_key",
|
|
Storage: s,
|
|
Data: decData,
|
|
}
|
|
resp, err = b.HandleRequest(decReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
if resp.Data["plaintext"] != plaintext {
|
|
t.Fatalf("bad: plaintext. Expected: %q, Actual: %q", plaintext, resp.Data["plaintext"])
|
|
}
|
|
}
|
|
|
|
// Case2: Ensure that batch encryption did not affect the normal flow of
|
|
// encrypting the plaintext with the key upserted.
|
|
func TestTransit_BatchEncryptionCase2(t *testing.T) {
|
|
var resp *logical.Response
|
|
var err error
|
|
b, s := createBackendWithStorage(t)
|
|
|
|
// Upsert the key and encrypt the data
|
|
plaintext := "dGhlIHF1aWNrIGJyb3duIGZveA=="
|
|
|
|
encData := map[string]interface{}{
|
|
"plaintext": plaintext,
|
|
}
|
|
|
|
encReq := &logical.Request{
|
|
Operation: logical.CreateOperation,
|
|
Path: "encrypt/upserted_key",
|
|
Storage: s,
|
|
Data: encData,
|
|
}
|
|
resp, err = b.HandleRequest(encReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
ciphertext := resp.Data["ciphertext"]
|
|
decData := map[string]interface{}{
|
|
"ciphertext": ciphertext,
|
|
}
|
|
|
|
policyReq := &logical.Request{
|
|
Operation: logical.ReadOperation,
|
|
Path: "keys/upserted_key",
|
|
Storage: s,
|
|
}
|
|
|
|
resp, err = b.HandleRequest(policyReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
decReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "decrypt/upserted_key",
|
|
Storage: s,
|
|
Data: decData,
|
|
}
|
|
resp, err = b.HandleRequest(decReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
if resp.Data["plaintext"] != plaintext {
|
|
t.Fatalf("bad: plaintext. Expected: %q, Actual: %q", plaintext, resp.Data["plaintext"])
|
|
}
|
|
}
|
|
|
|
// Case3: If batch encryption input is not base64 encoded, it should fail.
|
|
func TestTransit_BatchEncryptionCase3(t *testing.T) {
|
|
var err error
|
|
|
|
b, s := createBackendWithStorage(t)
|
|
|
|
batchInput := `[{"plaintext":"dGhlIHF1aWNrIGJyb3duIGZveA=="}]`
|
|
batchData := map[string]interface{}{
|
|
"batch_input": batchInput,
|
|
}
|
|
|
|
batchReq := &logical.Request{
|
|
Operation: logical.CreateOperation,
|
|
Path: "encrypt/upserted_key",
|
|
Storage: s,
|
|
Data: batchData,
|
|
}
|
|
_, err = b.HandleRequest(batchReq)
|
|
if err == nil {
|
|
t.Fatal("expected an error")
|
|
}
|
|
}
|
|
|
|
// Case4: Test batch encryption with an existing key
|
|
func TestTransit_BatchEncryptionCase4(t *testing.T) {
|
|
var resp *logical.Response
|
|
var err error
|
|
|
|
b, s := createBackendWithStorage(t)
|
|
|
|
policyReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "keys/existing_key",
|
|
Storage: s,
|
|
}
|
|
resp, err = b.HandleRequest(policyReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
batchInput := []interface{}{
|
|
map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA=="},
|
|
map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA=="},
|
|
}
|
|
|
|
batchData := map[string]interface{}{
|
|
"batch_input": batchInput,
|
|
}
|
|
batchReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "encrypt/existing_key",
|
|
Storage: s,
|
|
Data: batchData,
|
|
}
|
|
resp, err = b.HandleRequest(batchReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
batchResponseItems := resp.Data["batch_results"].([]BatchResponseItem)
|
|
|
|
decReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "decrypt/existing_key",
|
|
Storage: s,
|
|
}
|
|
|
|
plaintext := "dGhlIHF1aWNrIGJyb3duIGZveA=="
|
|
|
|
for _, item := range batchResponseItems {
|
|
decReq.Data = map[string]interface{}{
|
|
"ciphertext": item.Ciphertext,
|
|
}
|
|
resp, err = b.HandleRequest(decReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
if resp.Data["plaintext"] != plaintext {
|
|
t.Fatalf("bad: plaintext. Expected: %q, Actual: %q", plaintext, resp.Data["plaintext"])
|
|
}
|
|
}
|
|
}
|
|
|
|
// Case5: Test batch encryption with an existing derived key
|
|
func TestTransit_BatchEncryptionCase5(t *testing.T) {
|
|
var resp *logical.Response
|
|
var err error
|
|
|
|
b, s := createBackendWithStorage(t)
|
|
|
|
policyData := map[string]interface{}{
|
|
"derived": true,
|
|
}
|
|
|
|
policyReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "keys/existing_key",
|
|
Storage: s,
|
|
Data: policyData,
|
|
}
|
|
|
|
resp, err = b.HandleRequest(policyReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
batchInput := []interface{}{
|
|
map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "context": "dmlzaGFsCg=="},
|
|
map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "context": "dmlzaGFsCg=="},
|
|
}
|
|
|
|
batchData := map[string]interface{}{
|
|
"batch_input": batchInput,
|
|
}
|
|
|
|
batchReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "encrypt/existing_key",
|
|
Storage: s,
|
|
Data: batchData,
|
|
}
|
|
resp, err = b.HandleRequest(batchReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
batchResponseItems := resp.Data["batch_results"].([]BatchResponseItem)
|
|
|
|
decReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "decrypt/existing_key",
|
|
Storage: s,
|
|
}
|
|
|
|
plaintext := "dGhlIHF1aWNrIGJyb3duIGZveA=="
|
|
|
|
for _, item := range batchResponseItems {
|
|
decReq.Data = map[string]interface{}{
|
|
"ciphertext": item.Ciphertext,
|
|
"context": "dmlzaGFsCg==",
|
|
}
|
|
resp, err = b.HandleRequest(decReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
if resp.Data["plaintext"] != plaintext {
|
|
t.Fatalf("bad: plaintext. Expected: %q, Actual: %q", plaintext, resp.Data["plaintext"])
|
|
}
|
|
}
|
|
}
|
|
|
|
// Case6: Test batch encryption with an upserted non-derived key
|
|
func TestTransit_BatchEncryptionCase6(t *testing.T) {
|
|
var resp *logical.Response
|
|
var err error
|
|
|
|
b, s := createBackendWithStorage(t)
|
|
|
|
batchInput := []interface{}{
|
|
map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA=="},
|
|
map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA=="},
|
|
}
|
|
|
|
batchData := map[string]interface{}{
|
|
"batch_input": batchInput,
|
|
}
|
|
batchReq := &logical.Request{
|
|
Operation: logical.CreateOperation,
|
|
Path: "encrypt/upserted_key",
|
|
Storage: s,
|
|
Data: batchData,
|
|
}
|
|
resp, err = b.HandleRequest(batchReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
batchResponseItems := resp.Data["batch_results"].([]BatchResponseItem)
|
|
|
|
decReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "decrypt/upserted_key",
|
|
Storage: s,
|
|
}
|
|
|
|
plaintext := "dGhlIHF1aWNrIGJyb3duIGZveA=="
|
|
|
|
for _, responseItem := range batchResponseItems {
|
|
var item BatchResponseItem
|
|
if err := mapstructure.Decode(responseItem, &item); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
decReq.Data = map[string]interface{}{
|
|
"ciphertext": item.Ciphertext,
|
|
}
|
|
resp, err = b.HandleRequest(decReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
if resp.Data["plaintext"] != plaintext {
|
|
t.Fatalf("bad: plaintext. Expected: %q, Actual: %q", plaintext, resp.Data["plaintext"])
|
|
}
|
|
}
|
|
}
|
|
|
|
// Case7: Test batch encryption with an upserted derived key
|
|
func TestTransit_BatchEncryptionCase7(t *testing.T) {
|
|
var resp *logical.Response
|
|
var err error
|
|
|
|
b, s := createBackendWithStorage(t)
|
|
|
|
batchInput := []interface{}{
|
|
map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "context": "dmlzaGFsCg=="},
|
|
map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "context": "dmlzaGFsCg=="},
|
|
}
|
|
|
|
batchData := map[string]interface{}{
|
|
"batch_input": batchInput,
|
|
}
|
|
batchReq := &logical.Request{
|
|
Operation: logical.CreateOperation,
|
|
Path: "encrypt/upserted_key",
|
|
Storage: s,
|
|
Data: batchData,
|
|
}
|
|
resp, err = b.HandleRequest(batchReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
batchResponseItems := resp.Data["batch_results"].([]BatchResponseItem)
|
|
|
|
decReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "decrypt/upserted_key",
|
|
Storage: s,
|
|
}
|
|
|
|
plaintext := "dGhlIHF1aWNrIGJyb3duIGZveA=="
|
|
|
|
for _, item := range batchResponseItems {
|
|
decReq.Data = map[string]interface{}{
|
|
"ciphertext": item.Ciphertext,
|
|
"context": "dmlzaGFsCg==",
|
|
}
|
|
resp, err = b.HandleRequest(decReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
if resp.Data["plaintext"] != plaintext {
|
|
t.Fatalf("bad: plaintext. Expected: %q, Actual: %q", plaintext, resp.Data["plaintext"])
|
|
}
|
|
}
|
|
}
|
|
|
|
// Case8: If plaintext is not base64 encoded, encryption should fail
|
|
func TestTransit_BatchEncryptionCase8(t *testing.T) {
|
|
var resp *logical.Response
|
|
var err error
|
|
|
|
b, s := createBackendWithStorage(t)
|
|
|
|
// Create the policy
|
|
policyReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "keys/existing_key",
|
|
Storage: s,
|
|
}
|
|
resp, err = b.HandleRequest(policyReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
batchInput := []interface{}{
|
|
map[string]interface{}{"plaintext": "simple_plaintext"},
|
|
}
|
|
batchData := map[string]interface{}{
|
|
"batch_input": batchInput,
|
|
}
|
|
batchReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "encrypt/existing_key",
|
|
Storage: s,
|
|
Data: batchData,
|
|
}
|
|
resp, err = b.HandleRequest(batchReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
plaintext := "simple plaintext"
|
|
|
|
encData := map[string]interface{}{
|
|
"plaintext": plaintext,
|
|
}
|
|
|
|
encReq := &logical.Request{
|
|
Operation: logical.UpdateOperation,
|
|
Path: "encrypt/existing_key",
|
|
Storage: s,
|
|
Data: encData,
|
|
}
|
|
resp, err = b.HandleRequest(encReq)
|
|
if err == nil {
|
|
t.Fatal("expected an error")
|
|
}
|
|
}
|
|
|
|
// Case9: If both plaintext and batch inputs are supplied, plaintext should be
|
|
// ignored.
|
|
func TestTransit_BatchEncryptionCase9(t *testing.T) {
|
|
var resp *logical.Response
|
|
var err error
|
|
|
|
b, s := createBackendWithStorage(t)
|
|
|
|
batchInput := []interface{}{
|
|
map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA=="},
|
|
map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA=="},
|
|
}
|
|
plaintext := "dGhlIHF1aWNrIGJyb3duIGZveA=="
|
|
batchData := map[string]interface{}{
|
|
"batch_input": batchInput,
|
|
"plaintext": plaintext,
|
|
}
|
|
batchReq := &logical.Request{
|
|
Operation: logical.CreateOperation,
|
|
Path: "encrypt/upserted_key",
|
|
Storage: s,
|
|
Data: batchData,
|
|
}
|
|
resp, err = b.HandleRequest(batchReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
|
}
|
|
|
|
_, ok := resp.Data["ciphertext"]
|
|
if ok {
|
|
t.Fatal("ciphertext field should not be set")
|
|
}
|
|
}
|
|
|
|
// Case10: Inconsistent presence of 'context' in batch input should be caught
|
|
func TestTransit_BatchEncryptionCase10(t *testing.T) {
|
|
var err error
|
|
|
|
b, s := createBackendWithStorage(t)
|
|
|
|
batchInput := []interface{}{
|
|
map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA=="},
|
|
map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "context": "dmlzaGFsCg=="},
|
|
}
|
|
|
|
batchData := map[string]interface{}{
|
|
"batch_input": batchInput,
|
|
}
|
|
|
|
batchReq := &logical.Request{
|
|
Operation: logical.CreateOperation,
|
|
Path: "encrypt/upserted_key",
|
|
Storage: s,
|
|
Data: batchData,
|
|
}
|
|
_, err = b.HandleRequest(batchReq)
|
|
if err == nil {
|
|
t.Fatalf("expected an error")
|
|
}
|
|
}
|
|
|
|
// Case11: Incorrect inputs for context and nonce should not fail the operation
|
|
func TestTransit_BatchEncryptionCase11(t *testing.T) {
|
|
var err error
|
|
|
|
b, s := createBackendWithStorage(t)
|
|
|
|
batchInput := []interface{}{
|
|
map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "context": "dmlzaGFsCg=="},
|
|
map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "context": "not-encoded"},
|
|
}
|
|
|
|
batchData := map[string]interface{}{
|
|
"batch_input": batchInput,
|
|
}
|
|
batchReq := &logical.Request{
|
|
Operation: logical.CreateOperation,
|
|
Path: "encrypt/upserted_key",
|
|
Storage: s,
|
|
Data: batchData,
|
|
}
|
|
_, err = b.HandleRequest(batchReq)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// Case12: Invalid batch input
|
|
func TestTransit_BatchEncryptionCase12(t *testing.T) {
|
|
var err error
|
|
b, s := createBackendWithStorage(t)
|
|
|
|
batchInput := []interface{}{
|
|
map[string]interface{}{},
|
|
"unexpected_interface",
|
|
}
|
|
|
|
batchData := map[string]interface{}{
|
|
"batch_input": batchInput,
|
|
}
|
|
batchReq := &logical.Request{
|
|
Operation: logical.CreateOperation,
|
|
Path: "encrypt/upserted_key",
|
|
Storage: s,
|
|
Data: batchData,
|
|
}
|
|
_, err = b.HandleRequest(batchReq)
|
|
if err == nil {
|
|
t.Fatalf("expected an error")
|
|
}
|
|
}
|