From 197c7eae5f94dde093d582dfbd43825ed775bd86 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Tue, 13 Sep 2016 12:00:04 -0400 Subject: [PATCH] Allow encrypting empty ciphertext values. (#1881) Replaces #1874 --- builtin/logical/transit/backend_test.go | 44 +++++++++++++++++++++++++ builtin/logical/transit/path_decrypt.go | 5 --- builtin/logical/transit/path_encrypt.go | 9 ++--- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/builtin/logical/transit/backend_test.go b/builtin/logical/transit/backend_test.go index 192f98f6e..b3ed0784d 100644 --- a/builtin/logical/transit/backend_test.go +++ b/builtin/logical/transit/backend_test.go @@ -31,6 +31,8 @@ func TestBackend_basic(t *testing.T) { testAccStepReadPolicy(t, "test", false, false), testAccStepEncrypt(t, "test", testPlaintext, decryptData), testAccStepDecrypt(t, "test", testPlaintext, decryptData), + testAccStepEncrypt(t, "test", "", decryptData), + testAccStepDecrypt(t, "test", "", decryptData), testAccStepDeleteNotDisabledPolicy(t, "test"), testAccStepEnableDeletion(t, "test"), testAccStepDeletePolicy(t, "test"), @@ -781,6 +783,48 @@ func testConvergentEncryptionCommon(t *testing.T, ver int) { if ciphertext3 == ciphertext5 { t.Fatalf("expected different ciphertexts") } + + // Finally, check operations on empty values + // First, check without setting a plaintext at all + req.Data = map[string]interface{}{ + "nonce": "b25ldHdvdGhyZWVl", // "onetwothreee" + "context": "pWZ6t/im3AORd0lVYE0zBdKpX6Bl3/SvFtoVTPWbdkzjG788XmMAnOlxandSdd7S", + } + resp, err = b.HandleRequest(req) + if resp == nil { + t.Fatal("expected non-nil response") + } + if !resp.IsError() { + t.Fatalf("expected error response, got: %#v", *resp) + } + + // Now set plaintext to empty + req.Data = map[string]interface{}{ + "plaintext": "", + "nonce": "b25ldHdvdGhyZWVl", // "onetwothreee" + "context": "pWZ6t/im3AORd0lVYE0zBdKpX6Bl3/SvFtoVTPWbdkzjG788XmMAnOlxandSdd7S", + } + resp, err = b.HandleRequest(req) + if resp == nil { + t.Fatal("expected non-nil response") + } + if resp.IsError() { + t.Fatalf("got error response: %#v", *resp) + } + ciphertext7 := resp.Data["ciphertext"].(string) + + resp, err = b.HandleRequest(req) + if resp == nil { + t.Fatal("expected non-nil response") + } + if resp.IsError() { + t.Fatalf("got error response: %#v", *resp) + } + ciphertext8 := resp.Data["ciphertext"].(string) + + if ciphertext7 != ciphertext8 { + t.Fatalf("expected the same ciphertext but got %s and %s", ciphertext7, ciphertext8) + } } func TestPolicyFuzzing(t *testing.T) { diff --git a/builtin/logical/transit/path_decrypt.go b/builtin/logical/transit/path_decrypt.go index 433c26a2e..3758a756d 100644 --- a/builtin/logical/transit/path_decrypt.go +++ b/builtin/logical/transit/path_decrypt.go @@ -2,7 +2,6 @@ package transit import ( "encoding/base64" - "fmt" "github.com/hashicorp/vault/helper/errutil" "github.com/hashicorp/vault/logical" @@ -97,10 +96,6 @@ func (b *backend) pathDecryptWrite( } } - if plaintext == "" { - return nil, fmt.Errorf("empty plaintext returned") - } - // Generate the response resp := &logical.Response{ Data: map[string]interface{}{ diff --git a/builtin/logical/transit/path_encrypt.go b/builtin/logical/transit/path_encrypt.go index 1d0b86d32..e1224ecd6 100644 --- a/builtin/logical/transit/path_encrypt.go +++ b/builtin/logical/transit/path_encrypt.go @@ -63,16 +63,17 @@ func (b *backend) pathEncryptExistenceCheck( func (b *backend) pathEncryptWrite( req *logical.Request, d *framework.FieldData) (*logical.Response, error) { name := d.Get("name").(string) - value := d.Get("plaintext").(string) - if len(value) == 0 { + + valueRaw, ok := d.GetOk("plaintext") + if !ok { return logical.ErrorResponse("missing plaintext to encrypt"), logical.ErrInvalidRequest } - - var err error + value := valueRaw.(string) // Decode the context if any contextRaw := d.Get("context").(string) var context []byte + var err error if len(contextRaw) != 0 { context, err = base64.StdEncoding.DecodeString(contextRaw) if err != nil {