mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-04 04:28:08 +00:00 
			
		
		
		
	* Ignore nonces when encrypting without convergence or with convergence versions > 1 * Honor nonce use warning in non-FIPS modes * Revert "Honor nonce use warning in non-FIPS modes" This reverts commit 2aee3dbdc11c4e333ecb20503539c7993b24ee57. * Add a test func that removes a nonce when not needed * err out rather than ignore the nonce * Alter unit test to cover, also cover convergent version 3 * More unit test work * Fix test 14 * changelog * tests not already in a nonce present path * Update unit test to not assume warning when nonce provided incorrectly * remove unused test field * Fix auto-squash events experiments When #22835 was merged, it was auto-squashed, so the `experiments` import was removed, but the test still referenced it. This removes the (now unnecessary) experiment from the test. * Allow nonces for managed keys, because we have no way of knowing if the backing cipher/mode needs one --------- Co-authored-by: Christopher Swenson <christopher.swenson@hashicorp.com>
		
			
				
	
	
		
			1069 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			1069 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (c) HashiCorp, Inc.
 | 
						|
// SPDX-License-Identifier: BUSL-1.1
 | 
						|
 | 
						|
package transit
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"encoding/json"
 | 
						|
	"fmt"
 | 
						|
	"net/http"
 | 
						|
	"reflect"
 | 
						|
	"strings"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"github.com/hashicorp/vault/sdk/helper/keysutil"
 | 
						|
 | 
						|
	uuid "github.com/hashicorp/go-uuid"
 | 
						|
	"github.com/hashicorp/vault/sdk/logical"
 | 
						|
	"github.com/mitchellh/mapstructure"
 | 
						|
)
 | 
						|
 | 
						|
func TestTransit_MissingPlaintext(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(context.Background(), policyReq)
 | 
						|
	if err != nil || (resp != nil && resp.IsError()) {
 | 
						|
		t.Fatalf("err:%v resp:%#v", err, resp)
 | 
						|
	}
 | 
						|
 | 
						|
	encReq := &logical.Request{
 | 
						|
		Operation: logical.UpdateOperation,
 | 
						|
		Path:      "encrypt/existing_key",
 | 
						|
		Storage:   s,
 | 
						|
		Data:      map[string]interface{}{},
 | 
						|
	}
 | 
						|
	resp, err = b.HandleRequest(context.Background(), encReq)
 | 
						|
	if resp == nil || !resp.IsError() {
 | 
						|
		t.Fatalf("expected error due to missing plaintext in request, err:%v resp:%#v", err, resp)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestTransit_MissingPlaintextInBatchInput(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(context.Background(), policyReq)
 | 
						|
	if err != nil || (resp != nil && resp.IsError()) {
 | 
						|
		t.Fatalf("err:%v resp:%#v", err, resp)
 | 
						|
	}
 | 
						|
 | 
						|
	batchInput := []interface{}{
 | 
						|
		map[string]interface{}{}, // Note that there is no map entry for plaintext
 | 
						|
	}
 | 
						|
 | 
						|
	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(context.Background(), batchReq)
 | 
						|
	if err == nil {
 | 
						|
		t.Fatalf("expected error due to missing plaintext in request, err:%v resp:%#v", err, resp)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// 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(context.Background(), policyReq)
 | 
						|
	if err != nil || (resp != nil && resp.IsError()) {
 | 
						|
		t.Fatalf("err:%v resp:%#v", err, resp)
 | 
						|
	}
 | 
						|
 | 
						|
	plaintext := "dGhlIHF1aWNrIGJyb3duIGZveA==" // "the quick brown fox"
 | 
						|
 | 
						|
	encData := map[string]interface{}{
 | 
						|
		"plaintext": plaintext,
 | 
						|
	}
 | 
						|
 | 
						|
	encReq := &logical.Request{
 | 
						|
		Operation: logical.UpdateOperation,
 | 
						|
		Path:      "encrypt/existing_key",
 | 
						|
		Storage:   s,
 | 
						|
		Data:      encData,
 | 
						|
	}
 | 
						|
	resp, err = b.HandleRequest(context.Background(), encReq)
 | 
						|
	if err != nil || (resp != nil && resp.IsError()) {
 | 
						|
		t.Fatalf("err:%v resp:%#v", err, resp)
 | 
						|
	}
 | 
						|
 | 
						|
	keyVersion := resp.Data["key_version"].(int)
 | 
						|
	if keyVersion != 1 {
 | 
						|
		t.Fatalf("unexpected key version; got: %d, expected: %d", keyVersion, 1)
 | 
						|
	}
 | 
						|
 | 
						|
	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(context.Background(), 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(context.Background(), encReq)
 | 
						|
	if err != nil || (resp != nil && resp.IsError()) {
 | 
						|
		t.Fatalf("err:%v resp:%#v", err, resp)
 | 
						|
	}
 | 
						|
 | 
						|
	keyVersion := resp.Data["key_version"].(int)
 | 
						|
	if keyVersion != 1 {
 | 
						|
		t.Fatalf("unexpected key version; got: %d, expected: %d", keyVersion, 1)
 | 
						|
	}
 | 
						|
 | 
						|
	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(context.Background(), 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(context.Background(), 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(context.Background(), batchReq)
 | 
						|
	if err == nil {
 | 
						|
		t.Fatal("expected an error")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Case4: Test batch encryption with an existing key (and test references)
 | 
						|
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(context.Background(), policyReq)
 | 
						|
	if err != nil || (resp != nil && resp.IsError()) {
 | 
						|
		t.Fatalf("err:%v resp:%#v", err, resp)
 | 
						|
	}
 | 
						|
 | 
						|
	batchInput := []interface{}{
 | 
						|
		map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "reference": "b"},
 | 
						|
		map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "reference": "a"},
 | 
						|
	}
 | 
						|
 | 
						|
	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(context.Background(), batchReq)
 | 
						|
	if err != nil || (resp != nil && resp.IsError()) {
 | 
						|
		t.Fatalf("err:%v resp:%#v", err, resp)
 | 
						|
	}
 | 
						|
 | 
						|
	batchResponseItems := resp.Data["batch_results"].([]EncryptBatchResponseItem)
 | 
						|
 | 
						|
	decReq := &logical.Request{
 | 
						|
		Operation: logical.UpdateOperation,
 | 
						|
		Path:      "decrypt/existing_key",
 | 
						|
		Storage:   s,
 | 
						|
	}
 | 
						|
 | 
						|
	plaintext := "dGhlIHF1aWNrIGJyb3duIGZveA=="
 | 
						|
 | 
						|
	for i, item := range batchResponseItems {
 | 
						|
		if item.KeyVersion != 1 {
 | 
						|
			t.Fatalf("unexpected key version; got: %d, expected: %d", item.KeyVersion, 1)
 | 
						|
		}
 | 
						|
 | 
						|
		decReq.Data = map[string]interface{}{
 | 
						|
			"ciphertext": item.Ciphertext,
 | 
						|
		}
 | 
						|
		resp, err = b.HandleRequest(context.Background(), 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"])
 | 
						|
		}
 | 
						|
		inputItem := batchInput[i].(map[string]interface{})
 | 
						|
		if item.Reference != inputItem["reference"] {
 | 
						|
			t.Fatalf("reference mismatch.  Expected %s, Actual: %s", inputItem["reference"], item.Reference)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// 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(context.Background(), 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(context.Background(), batchReq)
 | 
						|
	if err != nil || (resp != nil && resp.IsError()) {
 | 
						|
		t.Fatalf("err:%v resp:%#v", err, resp)
 | 
						|
	}
 | 
						|
 | 
						|
	batchResponseItems := resp.Data["batch_results"].([]EncryptBatchResponseItem)
 | 
						|
 | 
						|
	decReq := &logical.Request{
 | 
						|
		Operation: logical.UpdateOperation,
 | 
						|
		Path:      "decrypt/existing_key",
 | 
						|
		Storage:   s,
 | 
						|
	}
 | 
						|
 | 
						|
	plaintext := "dGhlIHF1aWNrIGJyb3duIGZveA=="
 | 
						|
 | 
						|
	for _, item := range batchResponseItems {
 | 
						|
		if item.KeyVersion != 1 {
 | 
						|
			t.Fatalf("unexpected key version; got: %d, expected: %d", item.KeyVersion, 1)
 | 
						|
		}
 | 
						|
 | 
						|
		decReq.Data = map[string]interface{}{
 | 
						|
			"ciphertext": item.Ciphertext,
 | 
						|
			"context":    "dmlzaGFsCg==",
 | 
						|
		}
 | 
						|
		resp, err = b.HandleRequest(context.Background(), 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(context.Background(), batchReq)
 | 
						|
	if err != nil || (resp != nil && resp.IsError()) {
 | 
						|
		t.Fatalf("err:%v resp:%#v", err, resp)
 | 
						|
	}
 | 
						|
 | 
						|
	batchResponseItems := resp.Data["batch_results"].([]EncryptBatchResponseItem)
 | 
						|
 | 
						|
	decReq := &logical.Request{
 | 
						|
		Operation: logical.UpdateOperation,
 | 
						|
		Path:      "decrypt/upserted_key",
 | 
						|
		Storage:   s,
 | 
						|
	}
 | 
						|
 | 
						|
	plaintext := "dGhlIHF1aWNrIGJyb3duIGZveA=="
 | 
						|
 | 
						|
	for _, responseItem := range batchResponseItems {
 | 
						|
		var item EncryptBatchResponseItem
 | 
						|
		if err := mapstructure.Decode(responseItem, &item); err != nil {
 | 
						|
			t.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		if item.KeyVersion != 1 {
 | 
						|
			t.Fatalf("unexpected key version; got: %d, expected: %d", item.KeyVersion, 1)
 | 
						|
		}
 | 
						|
 | 
						|
		decReq.Data = map[string]interface{}{
 | 
						|
			"ciphertext": item.Ciphertext,
 | 
						|
		}
 | 
						|
		resp, err = b.HandleRequest(context.Background(), 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(context.Background(), batchReq)
 | 
						|
	if err != nil || (resp != nil && resp.IsError()) {
 | 
						|
		t.Fatalf("err:%v resp:%#v", err, resp)
 | 
						|
	}
 | 
						|
 | 
						|
	batchResponseItems := resp.Data["batch_results"].([]EncryptBatchResponseItem)
 | 
						|
 | 
						|
	decReq := &logical.Request{
 | 
						|
		Operation: logical.UpdateOperation,
 | 
						|
		Path:      "decrypt/upserted_key",
 | 
						|
		Storage:   s,
 | 
						|
	}
 | 
						|
 | 
						|
	plaintext := "dGhlIHF1aWNrIGJyb3duIGZveA=="
 | 
						|
 | 
						|
	for _, item := range batchResponseItems {
 | 
						|
		if item.KeyVersion != 1 {
 | 
						|
			t.Fatalf("unexpected key version; got: %d, expected: %d", item.KeyVersion, 1)
 | 
						|
		}
 | 
						|
 | 
						|
		decReq.Data = map[string]interface{}{
 | 
						|
			"ciphertext": item.Ciphertext,
 | 
						|
			"context":    "dmlzaGFsCg==",
 | 
						|
		}
 | 
						|
		resp, err = b.HandleRequest(context.Background(), 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(context.Background(), 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(context.Background(), 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(context.Background(), 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(context.Background(), 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(context.Background(), 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(context.Background(), 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(context.Background(), batchReq)
 | 
						|
	if err == nil {
 | 
						|
		t.Fatalf("expected an error")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Case13: Incorrect input for nonce when we aren't in convergent encryption should fail the operation
 | 
						|
func TestTransit_EncryptionCase13(t *testing.T) {
 | 
						|
	var err error
 | 
						|
 | 
						|
	b, s := createBackendWithStorage(t)
 | 
						|
 | 
						|
	// Non-batch first
 | 
						|
	data := map[string]interface{}{"plaintext": "bXkgc2VjcmV0IGRhdGE=", "nonce": "R80hr9eNUIuFV52e"}
 | 
						|
	req := &logical.Request{
 | 
						|
		Operation: logical.CreateOperation,
 | 
						|
		Path:      "encrypt/my-key",
 | 
						|
		Storage:   s,
 | 
						|
		Data:      data,
 | 
						|
	}
 | 
						|
	resp, err := b.HandleRequest(context.Background(), req)
 | 
						|
	if err == nil {
 | 
						|
		t.Fatal("expected invalid request")
 | 
						|
	}
 | 
						|
 | 
						|
	batchInput := []interface{}{
 | 
						|
		map[string]interface{}{"plaintext": "bXkgc2VjcmV0IGRhdGE=", "nonce": "R80hr9eNUIuFV52e"},
 | 
						|
	}
 | 
						|
 | 
						|
	batchData := map[string]interface{}{
 | 
						|
		"batch_input": batchInput,
 | 
						|
	}
 | 
						|
	batchReq := &logical.Request{
 | 
						|
		Operation: logical.CreateOperation,
 | 
						|
		Path:      "encrypt/my-key",
 | 
						|
		Storage:   s,
 | 
						|
		Data:      batchData,
 | 
						|
	}
 | 
						|
	resp, err = b.HandleRequest(context.Background(), batchReq)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
 | 
						|
	if v, ok := resp.Data["http_status_code"]; !ok || v.(int) != http.StatusBadRequest {
 | 
						|
		t.Fatal("expected request error")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Case14: Incorrect input for nonce when we are in convergent version 3 should fail
 | 
						|
func TestTransit_EncryptionCase14(t *testing.T) {
 | 
						|
	var err error
 | 
						|
 | 
						|
	b, s := createBackendWithStorage(t)
 | 
						|
 | 
						|
	cReq := &logical.Request{
 | 
						|
		Operation: logical.UpdateOperation,
 | 
						|
		Path:      "keys/my-key",
 | 
						|
		Storage:   s,
 | 
						|
		Data: map[string]interface{}{
 | 
						|
			"convergent_encryption": "true",
 | 
						|
			"derived":               "true",
 | 
						|
		},
 | 
						|
	}
 | 
						|
	resp, err := b.HandleRequest(context.Background(), cReq)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
 | 
						|
	// Non-batch first
 | 
						|
	data := map[string]interface{}{"plaintext": "bXkgc2VjcmV0IGRhdGE=", "context": "SGVsbG8sIFdvcmxkCg==", "nonce": "R80hr9eNUIuFV52e"}
 | 
						|
	req := &logical.Request{
 | 
						|
		Operation: logical.CreateOperation,
 | 
						|
		Path:      "encrypt/my-key",
 | 
						|
		Storage:   s,
 | 
						|
		Data:      data,
 | 
						|
	}
 | 
						|
 | 
						|
	resp, err = b.HandleRequest(context.Background(), req)
 | 
						|
	if err == nil {
 | 
						|
		t.Fatal("expected invalid request")
 | 
						|
	}
 | 
						|
 | 
						|
	batchInput := []interface{}{
 | 
						|
		data,
 | 
						|
	}
 | 
						|
 | 
						|
	batchData := map[string]interface{}{
 | 
						|
		"batch_input": batchInput,
 | 
						|
	}
 | 
						|
	batchReq := &logical.Request{
 | 
						|
		Operation: logical.CreateOperation,
 | 
						|
		Path:      "encrypt/my-key",
 | 
						|
		Storage:   s,
 | 
						|
		Data:      batchData,
 | 
						|
	}
 | 
						|
	resp, err = b.HandleRequest(context.Background(), batchReq)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
 | 
						|
	if v, ok := resp.Data["http_status_code"]; !ok || v.(int) != http.StatusBadRequest {
 | 
						|
		t.Fatal("expected request error")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Test that the fast path function decodeBatchRequestItems behave like mapstructure.Decode() to decode []BatchRequestItem.
 | 
						|
func TestTransit_decodeBatchRequestItems(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		name              string
 | 
						|
		src               interface{}
 | 
						|
		requirePlaintext  bool
 | 
						|
		requireCiphertext bool
 | 
						|
		dest              []BatchRequestItem
 | 
						|
		wantErrContains   string
 | 
						|
	}{
 | 
						|
		// basic edge cases of nil values
 | 
						|
		{name: "nil-nil", src: nil, dest: nil},
 | 
						|
		{name: "nil-empty", src: nil, dest: []BatchRequestItem{}},
 | 
						|
		{name: "empty-nil", src: []interface{}{}, dest: nil},
 | 
						|
		{
 | 
						|
			name: "src-nil",
 | 
						|
			src:  []interface{}{map[string]interface{}{}},
 | 
						|
			dest: nil,
 | 
						|
		},
 | 
						|
		// empty src & dest
 | 
						|
		{
 | 
						|
			name: "src-dest",
 | 
						|
			src:  []interface{}{map[string]interface{}{}},
 | 
						|
			dest: []BatchRequestItem{},
 | 
						|
		},
 | 
						|
		// empty src but with already populated dest, mapstructure discard pre-populated data.
 | 
						|
		{
 | 
						|
			name: "src-dest_pre_filled",
 | 
						|
			src:  []interface{}{map[string]interface{}{}},
 | 
						|
			dest: []BatchRequestItem{{}},
 | 
						|
		},
 | 
						|
		// two test per properties to test valid and invalid input
 | 
						|
		{
 | 
						|
			name: "src_plaintext-dest",
 | 
						|
			src:  []interface{}{map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA=="}},
 | 
						|
			dest: []BatchRequestItem{},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "src_plaintext_invalid-dest",
 | 
						|
			src:             []interface{}{map[string]interface{}{"plaintext": 666}},
 | 
						|
			dest:            []BatchRequestItem{},
 | 
						|
			wantErrContains: "expected type 'string', got unconvertible type 'int'",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "src_ciphertext-dest",
 | 
						|
			src:  []interface{}{map[string]interface{}{"ciphertext": "dGhlIHF1aWNrIGJyb3duIGZveA=="}},
 | 
						|
			dest: []BatchRequestItem{},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "src_ciphertext_invalid-dest",
 | 
						|
			src:             []interface{}{map[string]interface{}{"ciphertext": 666}},
 | 
						|
			dest:            []BatchRequestItem{},
 | 
						|
			wantErrContains: "expected type 'string', got unconvertible type 'int'",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "src_key_version-dest",
 | 
						|
			src:  []interface{}{map[string]interface{}{"key_version": 1}},
 | 
						|
			dest: []BatchRequestItem{},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "src_key_version_invalid-dest",
 | 
						|
			src:             []interface{}{map[string]interface{}{"key_version": "666"}},
 | 
						|
			dest:            []BatchRequestItem{},
 | 
						|
			wantErrContains: "expected type 'int', got unconvertible type 'string'",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "src_key_version_invalid-number-dest",
 | 
						|
			src:             []interface{}{map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "key_version": json.Number("1.1")}},
 | 
						|
			dest:            []BatchRequestItem{},
 | 
						|
			wantErrContains: "error decoding json.Number into [0].key_version",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "src_nonce-dest",
 | 
						|
			src:  []interface{}{map[string]interface{}{"nonce": "dGVzdGNvbnRleHQ="}},
 | 
						|
			dest: []BatchRequestItem{},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "src_nonce_invalid-dest",
 | 
						|
			src:             []interface{}{map[string]interface{}{"nonce": 666}},
 | 
						|
			dest:            []BatchRequestItem{},
 | 
						|
			wantErrContains: "expected type 'string', got unconvertible type 'int'",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "src_context-dest",
 | 
						|
			src:  []interface{}{map[string]interface{}{"context": "dGVzdGNvbnRleHQ="}},
 | 
						|
			dest: []BatchRequestItem{},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "src_context_invalid-dest",
 | 
						|
			src:             []interface{}{map[string]interface{}{"context": 666}},
 | 
						|
			dest:            []BatchRequestItem{},
 | 
						|
			wantErrContains: "expected type 'string', got unconvertible type 'int'",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "src_multi_order-dest",
 | 
						|
			src: []interface{}{
 | 
						|
				map[string]interface{}{"context": "1"},
 | 
						|
				map[string]interface{}{"context": "2"},
 | 
						|
				map[string]interface{}{"context": "3"},
 | 
						|
			},
 | 
						|
			dest: []BatchRequestItem{},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "src_multi_with_invalid-dest",
 | 
						|
			src: []interface{}{
 | 
						|
				map[string]interface{}{"context": "1"},
 | 
						|
				map[string]interface{}{"context": "2", "key_version": "666"},
 | 
						|
				map[string]interface{}{"context": "3"},
 | 
						|
			},
 | 
						|
			dest:            []BatchRequestItem{},
 | 
						|
			wantErrContains: "expected type 'int', got unconvertible type 'string'",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "src_multi_with_multi_invalid-dest",
 | 
						|
			src: []interface{}{
 | 
						|
				map[string]interface{}{"context": "1"},
 | 
						|
				map[string]interface{}{"context": "2", "key_version": "666"},
 | 
						|
				map[string]interface{}{"context": "3", "key_version": "1337"},
 | 
						|
			},
 | 
						|
			dest:            []BatchRequestItem{},
 | 
						|
			wantErrContains: "expected type 'int', got unconvertible type 'string'",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "src_plaintext-nil-nonce",
 | 
						|
			src:  []interface{}{map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "nonce": "null"}},
 | 
						|
			dest: []BatchRequestItem{},
 | 
						|
		},
 | 
						|
		// required fields
 | 
						|
		{
 | 
						|
			name:             "required_plaintext_present",
 | 
						|
			src:              []interface{}{map[string]interface{}{"plaintext": ""}},
 | 
						|
			requirePlaintext: true,
 | 
						|
			dest:             []BatchRequestItem{},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:             "required_plaintext_missing",
 | 
						|
			src:              []interface{}{map[string]interface{}{}},
 | 
						|
			requirePlaintext: true,
 | 
						|
			dest:             []BatchRequestItem{},
 | 
						|
			wantErrContains:  "missing plaintext",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:              "required_ciphertext_present",
 | 
						|
			src:               []interface{}{map[string]interface{}{"ciphertext": "dGhlIHF1aWNrIGJyb3duIGZveA=="}},
 | 
						|
			requireCiphertext: true,
 | 
						|
			dest:              []BatchRequestItem{},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:              "required_ciphertext_missing",
 | 
						|
			src:               []interface{}{map[string]interface{}{}},
 | 
						|
			requireCiphertext: true,
 | 
						|
			dest:              []BatchRequestItem{},
 | 
						|
			wantErrContains:   "missing ciphertext",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:              "required_plaintext_and_ciphertext_missing",
 | 
						|
			src:               []interface{}{map[string]interface{}{}},
 | 
						|
			requirePlaintext:  true,
 | 
						|
			requireCiphertext: true,
 | 
						|
			dest:              []BatchRequestItem{},
 | 
						|
			wantErrContains:   "missing ciphertext",
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			expectedDest := append(tt.dest[:0:0], tt.dest...) // copy of the dest state
 | 
						|
			expectedErr := mapstructure.Decode(tt.src, &expectedDest) != nil || tt.wantErrContains != ""
 | 
						|
 | 
						|
			gotErr := decodeBatchRequestItems(tt.src, tt.requirePlaintext, tt.requireCiphertext, &tt.dest)
 | 
						|
			gotDest := tt.dest
 | 
						|
 | 
						|
			if expectedErr {
 | 
						|
				if gotErr == nil {
 | 
						|
					t.Fatal("decodeBatchRequestItems unexpected error value; expected error but got none")
 | 
						|
				}
 | 
						|
				if tt.wantErrContains == "" {
 | 
						|
					t.Fatal("missing error condition")
 | 
						|
				}
 | 
						|
				if !strings.Contains(gotErr.Error(), tt.wantErrContains) {
 | 
						|
					t.Errorf("decodeBatchRequestItems unexpected error value, want err contains: '%v', got: '%v'", tt.wantErrContains, gotErr)
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if !reflect.DeepEqual(expectedDest, gotDest) {
 | 
						|
				t.Errorf("decodeBatchRequestItems unexpected dest value, want: '%v', got: '%v'", expectedDest, gotDest)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestShouldWarnAboutNonceUsage(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		name                 string
 | 
						|
		keyTypes             []keysutil.KeyType
 | 
						|
		nonce                []byte
 | 
						|
		convergentEncryption bool
 | 
						|
		convergentVersion    int
 | 
						|
		expected             bool
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name:                 "-NoConvergent-WithNonce",
 | 
						|
			keyTypes:             []keysutil.KeyType{keysutil.KeyType_AES256_GCM96, keysutil.KeyType_AES128_GCM96, keysutil.KeyType_ChaCha20_Poly1305},
 | 
						|
			nonce:                []byte("testnonce"),
 | 
						|
			convergentEncryption: false,
 | 
						|
			convergentVersion:    -1,
 | 
						|
			expected:             true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:                 "-NoConvergent-NoNonce",
 | 
						|
			keyTypes:             []keysutil.KeyType{keysutil.KeyType_AES256_GCM96, keysutil.KeyType_AES128_GCM96, keysutil.KeyType_ChaCha20_Poly1305},
 | 
						|
			nonce:                []byte{},
 | 
						|
			convergentEncryption: false,
 | 
						|
			convergentVersion:    -1,
 | 
						|
			expected:             false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:                 "-Convergentv1-WithNonce",
 | 
						|
			keyTypes:             []keysutil.KeyType{keysutil.KeyType_AES256_GCM96, keysutil.KeyType_AES128_GCM96, keysutil.KeyType_ChaCha20_Poly1305},
 | 
						|
			nonce:                []byte("testnonce"),
 | 
						|
			convergentEncryption: true,
 | 
						|
			convergentVersion:    1,
 | 
						|
			expected:             true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:                 "-Convergentv2-WithNonce",
 | 
						|
			keyTypes:             []keysutil.KeyType{keysutil.KeyType_AES256_GCM96, keysutil.KeyType_AES128_GCM96, keysutil.KeyType_ChaCha20_Poly1305},
 | 
						|
			nonce:                []byte("testnonce"),
 | 
						|
			convergentEncryption: true,
 | 
						|
			convergentVersion:    2,
 | 
						|
			expected:             false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:                 "-Convergentv3-WithNonce",
 | 
						|
			keyTypes:             []keysutil.KeyType{keysutil.KeyType_AES256_GCM96, keysutil.KeyType_AES128_GCM96, keysutil.KeyType_ChaCha20_Poly1305},
 | 
						|
			nonce:                []byte("testnonce"),
 | 
						|
			convergentEncryption: true,
 | 
						|
			convergentVersion:    3,
 | 
						|
			expected:             false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:                 "-NoConvergent-WithNonce",
 | 
						|
			keyTypes:             []keysutil.KeyType{keysutil.KeyType_RSA2048, keysutil.KeyType_RSA4096},
 | 
						|
			nonce:                []byte("testnonce"),
 | 
						|
			convergentEncryption: false,
 | 
						|
			convergentVersion:    -1,
 | 
						|
			expected:             false,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, tt := range tests {
 | 
						|
		for _, keyType := range tt.keyTypes {
 | 
						|
			testName := keyType.String() + tt.name
 | 
						|
			t.Run(testName, func(t *testing.T) {
 | 
						|
				p := keysutil.Policy{
 | 
						|
					ConvergentEncryption: tt.convergentEncryption,
 | 
						|
					ConvergentVersion:    tt.convergentVersion,
 | 
						|
					Type:                 keyType,
 | 
						|
				}
 | 
						|
 | 
						|
				actual := shouldWarnAboutNonceUsage(&p, tt.nonce)
 | 
						|
 | 
						|
				if actual != tt.expected {
 | 
						|
					t.Errorf("Expected actual '%v' but got '%v'", tt.expected, actual)
 | 
						|
				}
 | 
						|
			})
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestTransit_EncryptWithRSAPublicKey(t *testing.T) {
 | 
						|
	generateKeys(t)
 | 
						|
	b, s := createBackendWithStorage(t)
 | 
						|
	keyType := "rsa-2048"
 | 
						|
	keyID, err := uuid.GenerateUUID()
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to generate key ID: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	// Get key
 | 
						|
	privateKey := getKey(t, keyType)
 | 
						|
	publicKeyBytes, err := getPublicKey(privateKey, keyType)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
 | 
						|
	// Import key
 | 
						|
	req := &logical.Request{
 | 
						|
		Storage:   s,
 | 
						|
		Operation: logical.UpdateOperation,
 | 
						|
		Path:      fmt.Sprintf("keys/%s/import", keyID),
 | 
						|
		Data: map[string]interface{}{
 | 
						|
			"public_key": publicKeyBytes,
 | 
						|
			"type":       keyType,
 | 
						|
		},
 | 
						|
	}
 | 
						|
	_, err = b.HandleRequest(context.Background(), req)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to import public key: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	req = &logical.Request{
 | 
						|
		Operation: logical.CreateOperation,
 | 
						|
		Path:      fmt.Sprintf("encrypt/%s", keyID),
 | 
						|
		Storage:   s,
 | 
						|
		Data: map[string]interface{}{
 | 
						|
			"plaintext": "bXkgc2VjcmV0IGRhdGE=",
 | 
						|
		},
 | 
						|
	}
 | 
						|
	_, err = b.HandleRequest(context.Background(), req)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
}
 |