2023-03-15 16:00:52 +00:00
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
2015-04-16 00:08:12 +00:00
package transit
import (
2018-01-08 18:31:38 +00:00
"context"
2022-11-23 17:57:23 +00:00
"crypto"
2023-05-24 15:26:35 +00:00
"crypto/ed25519"
2019-10-17 17:33:00 +00:00
cryptoRand "crypto/rand"
2022-11-23 17:57:23 +00:00
"crypto/x509"
2015-04-16 00:08:12 +00:00
"encoding/base64"
2022-11-23 17:57:23 +00:00
"encoding/pem"
2015-04-16 00:08:12 +00:00
"fmt"
2022-11-23 17:57:23 +00:00
"io"
2016-02-03 22:25:48 +00:00
"math/rand"
2018-02-14 16:59:46 +00:00
"os"
2018-06-05 22:51:35 +00:00
"path"
2016-08-30 20:29:09 +00:00
"reflect"
2015-09-14 20:28:46 +00:00
"strconv"
"strings"
2016-02-03 22:25:48 +00:00
"sync"
2015-04-16 00:08:12 +00:00
"testing"
2016-02-03 22:25:48 +00:00
"time"
2015-04-16 00:08:12 +00:00
2022-11-23 17:57:23 +00:00
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/builtin/logical/pki"
2019-04-13 07:44:06 +00:00
logicaltest "github.com/hashicorp/vault/helper/testhelpers/logical"
2022-11-23 17:57:23 +00:00
vaulthttp "github.com/hashicorp/vault/http"
2019-04-13 07:44:06 +00:00
"github.com/hashicorp/vault/sdk/framework"
2022-01-20 15:10:15 +00:00
"github.com/hashicorp/vault/sdk/helper/consts"
2019-04-12 21:54:35 +00:00
"github.com/hashicorp/vault/sdk/helper/keysutil"
"github.com/hashicorp/vault/sdk/logical"
2022-11-23 17:57:23 +00:00
"github.com/hashicorp/vault/vault"
uuid "github.com/hashicorp/go-uuid"
2015-04-16 00:08:12 +00:00
"github.com/mitchellh/mapstructure"
2022-11-23 17:57:23 +00:00
"github.com/stretchr/testify/require"
2015-04-16 00:08:12 +00:00
)
const (
2020-10-02 02:04:36 +00:00
testPlaintext = "The quick brown fox"
2015-04-16 00:08:12 +00:00
)
2020-06-10 17:31:46 +00:00
func createBackendWithStorage ( t testing . TB ) ( * backend , logical . Storage ) {
2017-02-02 19:24:20 +00:00
config := logical . TestBackendConfig ( )
config . StorageView = & logical . InmemStorage { }
2019-06-04 22:40:56 +00:00
b , _ := Backend ( context . Background ( ) , config )
2017-02-02 19:24:20 +00:00
if b == nil {
t . Fatalf ( "failed to create backend" )
}
2018-01-19 06:44:44 +00:00
err := b . Backend . Setup ( context . Background ( ) , config )
2017-02-02 19:24:20 +00:00
if err != nil {
t . Fatal ( err )
}
return b , config . StorageView
}
2020-06-10 17:31:46 +00:00
func createBackendWithSysView ( t testing . TB ) ( * backend , logical . Storage ) {
2018-06-12 16:24:12 +00:00
sysView := logical . TestSystemView ( )
storage := & logical . InmemStorage { }
conf := & logical . BackendConfig {
StorageView : storage ,
System : sysView ,
}
2019-06-04 22:40:56 +00:00
b , _ := Backend ( context . Background ( ) , conf )
2018-06-12 16:24:12 +00:00
if b == nil {
t . Fatal ( "failed to create backend" )
}
err := b . Backend . Setup ( context . Background ( ) , conf )
if err != nil {
t . Fatal ( err )
}
return b , storage
}
2020-06-10 17:31:46 +00:00
func createBackendWithSysViewWithStorage ( t testing . TB , s logical . Storage ) * backend {
2019-06-04 22:40:56 +00:00
sysView := logical . TestSystemView ( )
conf := & logical . BackendConfig {
StorageView : s ,
System : sysView ,
}
b , _ := Backend ( context . Background ( ) , conf )
if b == nil {
t . Fatal ( "failed to create backend" )
}
err := b . Backend . Setup ( context . Background ( ) , conf )
if err != nil {
t . Fatal ( err )
}
return b
}
2020-06-10 17:31:46 +00:00
func createBackendWithForceNoCacheWithSysViewWithStorage ( t testing . TB , s logical . Storage ) * backend {
2019-06-04 22:40:56 +00:00
sysView := logical . TestSystemView ( )
sysView . CachingDisabledVal = true
conf := & logical . BackendConfig {
StorageView : s ,
System : sysView ,
}
b , _ := Backend ( context . Background ( ) , conf )
if b == nil {
t . Fatal ( "failed to create backend" )
}
err := b . Backend . Setup ( context . Background ( ) , conf )
if err != nil {
t . Fatal ( err )
}
return b
}
2017-11-03 14:45:53 +00:00
func TestTransit_RSA ( t * testing . T ) {
testTransit_RSA ( t , "rsa-2048" )
2020-02-15 22:40:50 +00:00
testTransit_RSA ( t , "rsa-3072" )
2017-11-03 14:45:53 +00:00
testTransit_RSA ( t , "rsa-4096" )
}
func testTransit_RSA ( t * testing . T , keyType string ) {
var resp * logical . Response
var err error
b , storage := createBackendWithStorage ( t )
keyReq := & logical . Request {
Path : "keys/rsa" ,
Operation : logical . UpdateOperation ,
Data : map [ string ] interface { } {
"type" : keyType ,
} ,
Storage : storage ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , keyReq )
2017-11-03 14:45:53 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
plaintext := "dGhlIHF1aWNrIGJyb3duIGZveA==" // "the quick brown fox"
encryptReq := & logical . Request {
Path : "encrypt/rsa" ,
Operation : logical . UpdateOperation ,
Storage : storage ,
Data : map [ string ] interface { } {
"plaintext" : plaintext ,
} ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , encryptReq )
2017-11-03 14:45:53 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
ciphertext1 := resp . Data [ "ciphertext" ] . ( string )
decryptReq := & logical . Request {
Path : "decrypt/rsa" ,
Operation : logical . UpdateOperation ,
Storage : storage ,
Data : map [ string ] interface { } {
"ciphertext" : ciphertext1 ,
} ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , decryptReq )
2017-11-03 14:45:53 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
decryptedPlaintext := resp . Data [ "plaintext" ]
if plaintext != decryptedPlaintext {
t . Fatalf ( "bad: plaintext; expected: %q\nactual: %q" , plaintext , decryptedPlaintext )
}
// Rotate the key
rotateReq := & logical . Request {
Path : "keys/rsa/rotate" ,
Operation : logical . UpdateOperation ,
Storage : storage ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , rotateReq )
2017-11-03 14:45:53 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
// Encrypt again
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , encryptReq )
2017-11-03 14:45:53 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
ciphertext2 := resp . Data [ "ciphertext" ] . ( string )
if ciphertext1 == ciphertext2 {
t . Fatalf ( "expected different ciphertexts" )
}
// See if the older ciphertext can still be decrypted
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , decryptReq )
2017-11-03 14:45:53 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
if resp . Data [ "plaintext" ] . ( string ) != plaintext {
t . Fatal ( "failed to decrypt old ciphertext after rotating the key" )
}
// Decrypt the new ciphertext
decryptReq . Data = map [ string ] interface { } {
"ciphertext" : ciphertext2 ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , decryptReq )
2017-11-03 14:45:53 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
if resp . Data [ "plaintext" ] . ( string ) != plaintext {
t . Fatal ( "failed to decrypt ciphertext after rotating the key" )
}
signReq := & logical . Request {
Path : "sign/rsa" ,
Operation : logical . UpdateOperation ,
Storage : storage ,
Data : map [ string ] interface { } {
"input" : plaintext ,
} ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , signReq )
2017-11-03 14:45:53 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
signature := resp . Data [ "signature" ] . ( string )
verifyReq := & logical . Request {
Path : "verify/rsa" ,
Operation : logical . UpdateOperation ,
Storage : storage ,
Data : map [ string ] interface { } {
"input" : plaintext ,
"signature" : signature ,
} ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , verifyReq )
2017-11-03 14:45:53 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
if ! resp . Data [ "valid" ] . ( bool ) {
t . Fatalf ( "failed to verify the RSA signature" )
}
signReq . Data = map [ string ] interface { } {
2018-03-15 16:17:02 +00:00
"input" : plaintext ,
"hash_algorithm" : "invalid" ,
2017-11-03 14:45:53 +00:00
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , signReq )
2019-01-23 17:31:34 +00:00
if err == nil {
2017-11-03 14:45:53 +00:00
t . Fatal ( err )
}
signReq . Data = map [ string ] interface { } {
2018-03-15 16:17:02 +00:00
"input" : plaintext ,
"hash_algorithm" : "sha2-512" ,
2017-11-03 14:45:53 +00:00
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , signReq )
2017-11-03 14:45:53 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
signature = resp . Data [ "signature" ] . ( string )
verifyReq . Data = map [ string ] interface { } {
"input" : plaintext ,
"signature" : signature ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , verifyReq )
2017-11-03 14:45:53 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
if resp . Data [ "valid" ] . ( bool ) {
t . Fatalf ( "expected validation to fail" )
}
verifyReq . Data = map [ string ] interface { } {
2018-03-15 16:17:02 +00:00
"input" : plaintext ,
"signature" : signature ,
"hash_algorithm" : "sha2-512" ,
2017-11-03 14:45:53 +00:00
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , verifyReq )
2017-11-03 14:45:53 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
if ! resp . Data [ "valid" ] . ( bool ) {
t . Fatalf ( "failed to verify the RSA signature" )
}
2022-10-27 12:26:20 +00:00
// Take a random hash and sign it using PKCSv1_5_NoOID.
hash := "P8m2iUWdc4+MiKOkiqnjNUIBa3pAUuABqqU2/KdIE8s="
signReq . Data = map [ string ] interface { } {
"input" : hash ,
"hash_algorithm" : "none" ,
"signature_algorithm" : "pkcs1v15" ,
"prehashed" : true ,
}
resp , err = b . HandleRequest ( context . Background ( ) , signReq )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
signature = resp . Data [ "signature" ] . ( string )
verifyReq . Data = map [ string ] interface { } {
"input" : hash ,
"signature" : signature ,
"hash_algorithm" : "none" ,
"signature_algorithm" : "pkcs1v15" ,
"prehashed" : true ,
}
resp , err = b . HandleRequest ( context . Background ( ) , verifyReq )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
if ! resp . Data [ "valid" ] . ( bool ) {
t . Fatalf ( "failed to verify the RSA signature" )
}
2017-11-03 14:45:53 +00:00
}
2015-04-16 00:08:12 +00:00
func TestBackend_basic ( t * testing . T ) {
decryptData := make ( map [ string ] interface { } )
logicaltest . Test ( t , logicaltest . TestCase {
2018-11-07 01:21:24 +00:00
LogicalFactory : Factory ,
2015-04-16 00:08:12 +00:00
Steps : [ ] logicaltest . TestStep {
2016-10-18 14:13:01 +00:00
testAccStepListPolicy ( t , "test" , true ) ,
2015-07-05 21:30:45 +00:00
testAccStepWritePolicy ( t , "test" , false ) ,
2016-10-18 14:13:01 +00:00
testAccStepListPolicy ( t , "test" , false ) ,
2015-07-05 21:30:45 +00:00
testAccStepReadPolicy ( t , "test" , false , false ) ,
2015-04-16 00:08:12 +00:00
testAccStepEncrypt ( t , "test" , testPlaintext , decryptData ) ,
testAccStepDecrypt ( t , "test" , testPlaintext , decryptData ) ,
2016-09-13 16:00:04 +00:00
testAccStepEncrypt ( t , "test" , "" , decryptData ) ,
testAccStepDecrypt ( t , "test" , "" , 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 {
2018-11-07 01:21:24 +00:00
LogicalFactory : Factory ,
2016-02-02 14:58:12 +00:00
Steps : [ ] logicaltest . TestStep {
testAccStepReadPolicy ( t , "test" , true , false ) ,
2016-10-18 14:13:01 +00:00
testAccStepListPolicy ( t , "test" , true ) ,
2016-02-02 14:58:12 +00:00
testAccStepEncryptUpsert ( t , "test" , testPlaintext , decryptData ) ,
2016-10-18 14:13:01 +00:00
testAccStepListPolicy ( t , "test" , false ) ,
2016-02-02 14:58:12 +00:00
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 {
2018-11-07 01:21:24 +00:00
LogicalFactory : Factory ,
2015-09-18 13:50:53 +00:00
Steps : [ ] logicaltest . TestStep {
2016-10-18 14:13:01 +00:00
testAccStepListPolicy ( t , "test" , true ) ,
2015-09-18 13:50:53 +00:00
testAccStepWritePolicy ( t , "test" , false ) ,
2016-10-18 14:13:01 +00:00
testAccStepListPolicy ( t , "test" , false ) ,
2015-09-18 13:50:53 +00:00
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 ) {
2018-02-14 16:59:46 +00:00
defer os . Setenv ( "TRANSIT_ACC_KEY_TYPE" , "" )
testBackendRotation ( t )
os . Setenv ( "TRANSIT_ACC_KEY_TYPE" , "CHACHA" )
testBackendRotation ( t )
}
func testBackendRotation ( t * testing . T ) {
2015-09-14 20:28:46 +00:00
decryptData := make ( map [ string ] interface { } )
encryptHistory := make ( map [ int ] map [ string ] interface { } )
logicaltest . Test ( t , logicaltest . TestCase {
2018-11-07 01:21:24 +00:00
LogicalFactory : Factory ,
2015-09-14 20:28:46 +00:00
Steps : [ ] logicaltest . TestStep {
2016-10-18 14:13:01 +00:00
testAccStepListPolicy ( t , "test" , true ) ,
2015-09-14 20:28:46 +00:00
testAccStepWritePolicy ( t , "test" , false ) ,
2016-10-18 14:13:01 +00:00
testAccStepListPolicy ( t , "test" , false ) ,
2015-09-14 20:28:46 +00:00
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" ) ,
2017-06-08 18:07:18 +00:00
testAccStepAdjustPolicyMinDecryption ( t , "test" , 3 ) ,
testAccStepAdjustPolicyMinEncryption ( t , "test" , 4 ) ,
testAccStepReadPolicyWithVersions ( t , "test" , false , false , 3 , 4 ) ,
2015-09-14 20:28:46 +00:00
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 ) ,
2017-06-08 18:07:18 +00:00
testAccStepAdjustPolicyMinDecryption ( t , "test" , 1 ) ,
testAccStepReadPolicyWithVersions ( t , "test" , false , false , 1 , 4 ) ,
2015-09-14 20:28:46 +00:00
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 ) ,
2016-10-18 14:13:01 +00:00
testAccStepListPolicy ( t , "test" , true ) ,
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 {
2018-11-07 01:21:24 +00:00
LogicalFactory : Factory ,
2015-07-05 21:30:45 +00:00
Steps : [ ] logicaltest . TestStep {
2016-10-18 14:13:01 +00:00
testAccStepListPolicy ( t , "test" , true ) ,
2015-07-05 21:30:45 +00:00
testAccStepWritePolicy ( t , "test" , true ) ,
2016-10-18 14:13:01 +00:00
testAccStepListPolicy ( t , "test" , false ) ,
2015-07-05 21:30:45 +00:00
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 {
2018-02-14 16:59:46 +00:00
ts := 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
}
2018-02-14 16:59:46 +00:00
if os . Getenv ( "TRANSIT_ACC_KEY_TYPE" ) == "CHACHA" {
ts . Data [ "type" ] = "chacha20-poly1305"
}
return ts
2015-04-16 00:08:12 +00:00
}
2016-10-18 14:13:01 +00:00
func testAccStepListPolicy ( t * testing . T , name string , expectNone bool ) logicaltest . TestStep {
return logicaltest . TestStep {
Operation : logical . ListOperation ,
Path : "keys" ,
Check : func ( resp * logical . Response ) error {
if resp == nil {
return fmt . Errorf ( "missing response" )
}
if expectNone {
keysRaw , ok := resp . Data [ "keys" ]
if ok || keysRaw != nil {
return fmt . Errorf ( "response data when expecting none" )
}
return nil
}
if len ( resp . Data ) == 0 {
return fmt . Errorf ( "no data returned" )
}
var d struct {
Keys [ ] string ` mapstructure:"keys" `
}
if err := mapstructure . Decode ( resp . Data , & d ) ; err != nil {
return err
}
if len ( d . Keys ) > 0 && d . Keys [ 0 ] != name {
return fmt . Errorf ( "bad name: %#v" , d )
}
if len ( d . Keys ) != 1 {
return fmt . Errorf ( "only 1 key expected, %d returned" , len ( d . Keys ) )
}
return nil
} ,
}
}
2017-06-08 18:07:18 +00:00
func testAccStepAdjustPolicyMinDecryption ( 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
}
}
2021-04-08 16:43:39 +00:00
2017-06-08 18:07:18 +00:00
func testAccStepAdjustPolicyMinEncryption ( t * testing . T , name string , minVer int ) logicaltest . TestStep {
return logicaltest . TestStep {
Operation : logical . UpdateOperation ,
Path : "keys/" + name + "/config" ,
Data : map [ string ] interface { } {
"min_encryption_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 {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "got nil response instead of error" )
2015-09-17 22:49:50 +00:00
}
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 {
2017-06-08 18:07:18 +00:00
return testAccStepReadPolicyWithVersions ( t , name , expectNone , derived , 1 , 0 )
}
func testAccStepReadPolicyWithVersions ( t * testing . T , name string , expectNone , derived bool , minDecryptionVersion int , minEncryptionVersion int ) 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 {
2016-06-20 17:17:48 +00:00
Name string ` mapstructure:"name" `
Key [ ] byte ` mapstructure:"key" `
Keys map [ string ] int64 ` mapstructure:"keys" `
2016-09-21 14:29:42 +00:00
Type string ` mapstructure:"type" `
2016-06-20 17:17:48 +00:00
Derived bool ` mapstructure:"derived" `
2016-08-30 20:29:09 +00:00
KDF string ` mapstructure:"kdf" `
2016-06-20 17:17:48 +00:00
DeletionAllowed bool ` mapstructure:"deletion_allowed" `
ConvergentEncryption bool ` mapstructure:"convergent_encryption" `
2017-06-08 18:07:18 +00:00
MinDecryptionVersion int ` mapstructure:"min_decryption_version" `
MinEncryptionVersion int ` mapstructure:"min_encryption_version" `
2015-04-16 00:08:12 +00:00
}
if err := mapstructure . Decode ( resp . Data , & d ) ; err != nil {
return err
}
if d . Name != name {
2016-09-21 14:29:42 +00:00
return fmt . Errorf ( "bad name: %#v" , d )
2015-04-16 00:08:12 +00:00
}
2018-02-14 16:59:46 +00:00
if os . Getenv ( "TRANSIT_ACC_KEY_TYPE" ) == "CHACHA" {
if d . Type != keysutil . KeyType ( keysutil . KeyType_ChaCha20_Poly1305 ) . String ( ) {
return fmt . Errorf ( "bad key type: %#v" , d )
}
} else if d . Type != keysutil . KeyType ( keysutil . KeyType_AES256_GCM96 ) . String ( ) {
2016-09-21 14:29:42 +00:00
return fmt . Errorf ( "bad key type: %#v" , d )
2015-04-16 00:08:12 +00:00
}
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 )
}
2017-06-08 18:07:18 +00:00
if d . MinDecryptionVersion != minDecryptionVersion {
return fmt . Errorf ( "bad: %#v" , d )
}
if d . MinEncryptionVersion != minEncryptionVersion {
return fmt . Errorf ( "bad: %#v" , d )
}
2022-02-18 14:35:53 +00:00
if d . DeletionAllowed {
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 )
}
2016-08-30 20:29:09 +00:00
if derived && d . KDF != "hkdf_sha256" {
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 (
2022-09-08 00:31:20 +00:00
t * testing . T , name , plaintext string , decryptData map [ string ] interface { } ,
) 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-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 (
2022-09-08 00:31:20 +00:00
t * testing . T , name , plaintext string , decryptData map [ string ] interface { } ,
) logicaltest . TestStep {
2016-07-28 15:30:46 +00:00
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" `
}
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 (
2022-09-08 00:31:20 +00:00
t * testing . T , name , plaintext , context string , decryptData map [ string ] interface { } ,
) logicaltest . TestStep {
2015-07-05 21:30:45 +00:00
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 (
2022-09-08 00:31:20 +00:00
t * testing . T , name , plaintext string , decryptData map [ string ] interface { } ,
) 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-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 (
2022-09-08 00:31:20 +00:00
t * testing . T , name string , decryptData map [ string ] interface { } , expectedVer 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-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 {
2022-08-03 18:32:45 +00:00
return fmt . Errorf ( "error pulling out version from verString %q, 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 {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "did not get expected version" )
2015-09-14 20:28:46 +00:00
}
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 { } ,
2022-09-08 00:31:20 +00:00
ver int , encryptHistory map [ int ] map [ string ] interface { } ,
) 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 : "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 { } ,
2022-09-08 00:31:20 +00:00
ver int , encryptHistory map [ int ] map [ string ] interface { } ,
) logicaltest . TestStep {
2015-09-14 20:28:46 +00:00
// 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 (
2022-09-08 00:31:20 +00:00
t * testing . T , name , plaintext string , decryptData map [ string ] interface { } ,
) 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 : "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 ,
2022-09-08 00:31:20 +00:00
dataKeyInfo map [ string ] interface { } ,
) logicaltest . TestStep {
2015-09-18 13:50:53 +00:00
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 {
2022-08-03 18:32:45 +00:00
return fmt . Errorf ( "could not base64 decode plaintext string %q" , d . Plaintext )
2015-09-18 13:50:53 +00:00
}
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 ,
2022-09-08 00:31:20 +00:00
dataKeyInfo map [ string ] interface { } ,
) logicaltest . TestStep {
2015-09-18 13:50:53 +00:00
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 ) {
2022-08-03 18:32:45 +00:00
return fmt . Errorf ( "plaintext mismatch: got %q, expected %q, decryptData was %#v" , d . Plaintext , dataKeyInfo [ "plaintext" ] . ( string ) , resp . Data )
2015-09-18 13:50:53 +00:00
}
return nil
} ,
}
}
2015-09-14 20:28:46 +00:00
func TestKeyUpgrade ( t * testing . T ) {
2016-08-30 20:29:09 +00:00
key , _ := uuid . GenerateRandomBytes ( 32 )
2016-10-26 23:52:31 +00:00
p := & keysutil . Policy {
2016-09-21 14:29:42 +00:00
Name : "test" ,
Key : key ,
2016-10-26 23:52:31 +00:00
Type : keysutil . KeyType_AES256_GCM96 ,
2015-09-14 20:28:46 +00:00
}
2016-10-26 23:52:31 +00:00
p . MigrateKeyToKeysMap ( )
2015-09-14 20:28:46 +00:00
if p . Key != nil ||
p . Keys == nil ||
len ( p . Keys ) != 1 ||
2017-12-06 23:24:00 +00:00
! reflect . DeepEqual ( p . Keys [ strconv . Itoa ( 1 ) ] . Key , key ) {
2015-09-14 20:28:46 +00:00
t . Errorf ( "bad key migration, result is %#v" , p . Keys )
}
}
2016-02-03 22:25:48 +00:00
2016-08-30 20:29:09 +00:00
func TestDerivedKeyUpgrade ( t * testing . T ) {
2018-02-14 16:59:46 +00:00
testDerivedKeyUpgrade ( t , keysutil . KeyType_AES256_GCM96 )
testDerivedKeyUpgrade ( t , keysutil . KeyType_ChaCha20_Poly1305 )
}
func testDerivedKeyUpgrade ( t * testing . T , keyType keysutil . KeyType ) {
2016-08-30 20:29:09 +00:00
storage := & logical . InmemStorage { }
key , _ := uuid . GenerateRandomBytes ( 32 )
2018-01-19 06:44:44 +00:00
keyContext , _ := uuid . GenerateRandomBytes ( 32 )
2016-08-30 20:29:09 +00:00
2016-10-26 23:52:31 +00:00
p := & keysutil . Policy {
2016-09-21 14:29:42 +00:00
Name : "test" ,
Key : key ,
2018-02-14 16:59:46 +00:00
Type : keyType ,
2016-09-21 14:29:42 +00:00
Derived : true ,
2016-08-30 20:29:09 +00:00
}
2016-10-26 23:52:31 +00:00
p . MigrateKeyToKeysMap ( )
2019-10-17 17:33:00 +00:00
p . Upgrade ( context . Background ( ) , storage , cryptoRand . Reader ) // Need to run the upgrade code to make the migration stick
2016-08-30 20:29:09 +00:00
2016-10-26 23:52:31 +00:00
if p . KDF != keysutil . Kdf_hmac_sha256_counter {
t . Fatalf ( "bad KDF value by default; counter val is %d, KDF val is %d, policy is %#v" , keysutil . Kdf_hmac_sha256_counter , p . KDF , * p )
2016-08-30 20:29:09 +00:00
}
2020-10-02 02:04:36 +00:00
derBytesOld , err := p . GetKey ( keyContext , 1 , 0 )
2016-08-30 20:29:09 +00:00
if err != nil {
t . Fatal ( err )
}
2020-10-02 02:04:36 +00:00
derBytesOld2 , err := p . GetKey ( keyContext , 1 , 0 )
2016-08-30 20:29:09 +00:00
if err != nil {
t . Fatal ( err )
}
if ! reflect . DeepEqual ( derBytesOld , derBytesOld2 ) {
t . Fatal ( "mismatch of same context alg" )
}
2016-10-26 23:52:31 +00:00
p . KDF = keysutil . Kdf_hkdf_sha256
if p . NeedsUpgrade ( ) {
2016-08-30 20:29:09 +00:00
t . Fatal ( "expected no upgrade needed" )
}
2020-10-02 02:04:36 +00:00
derBytesNew , err := p . GetKey ( keyContext , 1 , 64 )
2016-08-30 20:29:09 +00:00
if err != nil {
t . Fatal ( err )
}
2020-10-02 02:04:36 +00:00
derBytesNew2 , err := p . GetKey ( keyContext , 1 , 64 )
2016-08-30 20:29:09 +00:00
if err != nil {
t . Fatal ( err )
}
if ! reflect . DeepEqual ( derBytesNew , derBytesNew2 ) {
t . Fatal ( "mismatch of same context alg" )
}
if reflect . DeepEqual ( derBytesOld , derBytesNew ) {
t . Fatal ( "match of different context alg" )
}
}
2016-06-20 17:17:48 +00:00
func TestConvergentEncryption ( t * testing . T ) {
2018-02-14 16:59:46 +00:00
testConvergentEncryptionCommon ( t , 0 , keysutil . KeyType_AES256_GCM96 )
2019-10-03 20:11:43 +00:00
testConvergentEncryptionCommon ( t , 2 , keysutil . KeyType_AES128_GCM96 )
2018-02-14 16:59:46 +00:00
testConvergentEncryptionCommon ( t , 2 , keysutil . KeyType_AES256_GCM96 )
testConvergentEncryptionCommon ( t , 2 , keysutil . KeyType_ChaCha20_Poly1305 )
2019-10-03 20:11:43 +00:00
testConvergentEncryptionCommon ( t , 3 , keysutil . KeyType_AES128_GCM96 )
2018-06-05 22:51:35 +00:00
testConvergentEncryptionCommon ( t , 3 , keysutil . KeyType_AES256_GCM96 )
testConvergentEncryptionCommon ( t , 3 , keysutil . KeyType_ChaCha20_Poly1305 )
2016-08-26 18:11:03 +00:00
}
2018-02-14 16:59:46 +00:00
func testConvergentEncryptionCommon ( t * testing . T , ver int , keyType keysutil . KeyType ) {
2018-06-12 16:24:12 +00:00
b , storage := createBackendWithSysView ( t )
2016-06-20 17:17:48 +00:00
2016-08-07 19:16:36 +00:00
req := & logical . Request {
Storage : storage ,
Operation : logical . UpdateOperation ,
Path : "keys/testkeynonderived" ,
Data : map [ string ] interface { } {
"derived" : false ,
"convergent_encryption" : true ,
2021-12-10 17:55:50 +00:00
"type" : keyType . String ( ) ,
2016-08-07 19:16:36 +00:00
} ,
}
2018-01-08 18:31:38 +00:00
resp , err := b . HandleRequest ( context . Background ( ) , req )
2016-08-07 19:16:36 +00:00
if err != nil {
t . Fatal ( err )
}
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
if ! resp . IsError ( ) {
t . Fatalf ( "bad: expected error response, got %#v" , * resp )
}
2018-06-05 22:51:35 +00:00
req = & logical . Request {
Storage : storage ,
Operation : logical . UpdateOperation ,
Path : "keys/testkey" ,
Data : map [ string ] interface { } {
"derived" : true ,
"convergent_encryption" : true ,
2021-12-10 17:55:50 +00:00
"type" : keyType . String ( ) ,
2018-06-05 22:51:35 +00:00
} ,
}
resp , err = b . HandleRequest ( context . Background ( ) , req )
if err != nil {
t . Fatal ( err )
}
2023-05-18 18:36:10 +00:00
require . NotNil ( t , resp , "expected populated request" )
2018-06-05 22:51:35 +00:00
p , err := keysutil . LoadPolicy ( context . Background ( ) , storage , path . Join ( "policy" , "testkey" ) )
if err != nil {
t . Fatal ( err )
}
if p == nil {
t . Fatal ( "got nil policy" )
2016-08-07 19:16:36 +00:00
}
2018-06-05 22:51:35 +00:00
if ver > 2 {
p . ConvergentVersion = - 1
} else {
p . ConvergentVersion = ver
}
err = p . Persist ( context . Background ( ) , storage )
2016-08-07 19:16:36 +00:00
if err != nil {
t . Fatal ( err )
}
2018-06-05 22:51:35 +00:00
b . invalidate ( context . Background ( ) , "policy/testkey" )
if ver < 3 {
// There will be an embedded key version of 3, so specifically clear it
key := p . Keys [ strconv . Itoa ( p . LatestVersion ) ]
key . ConvergentVersion = 0
p . Keys [ strconv . Itoa ( p . LatestVersion ) ] = key
err = p . Persist ( context . Background ( ) , storage )
if err != nil {
t . Fatal ( err )
}
b . invalidate ( context . Background ( ) , "policy/testkey" )
// Verify it
p , err = keysutil . LoadPolicy ( context . Background ( ) , storage , path . Join ( p . StoragePrefix , "policy" , "testkey" ) )
if err != nil {
t . Fatal ( err )
}
if p == nil {
t . Fatal ( "got nil policy" )
}
if p . ConvergentVersion != ver {
t . Fatalf ( "bad convergent version %d" , p . ConvergentVersion )
}
key = p . Keys [ strconv . Itoa ( p . LatestVersion ) ]
if key . ConvergentVersion != 0 {
t . Fatalf ( "bad convergent key version %d" , key . ConvergentVersion )
}
}
2016-08-07 19:16:36 +00:00
2016-08-26 21:01:56 +00:00
// First, test using an invalid length of nonce -- this is only used for v1 convergent
2016-08-07 19:16:36 +00:00
req . Path = "encrypt/testkey"
2016-08-26 21:01:56 +00:00
if ver < 2 {
req . Data = map [ string ] interface { } {
"plaintext" : "emlwIHphcA==" , // "zip zap"
"nonce" : "Zm9vIGJhcg==" , // "foo bar"
"context" : "pWZ6t/im3AORd0lVYE0zBdKpX6Bl3/SvFtoVTPWbdkzjG788XmMAnOlxandSdd7S" ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , req )
2017-07-07 12:23:12 +00:00
if err == nil {
2018-06-05 22:51:35 +00:00
t . Fatalf ( "expected error, got nil, version is %d" , ver )
2017-07-07 12:23:12 +00:00
}
2016-08-26 21:01:56 +00:00
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
if ! resp . IsError ( ) {
t . Fatalf ( "expected error response, got %#v" , * resp )
}
// Ensure we fail if we do not provide a nonce
req . Data = map [ string ] interface { } {
"plaintext" : "emlwIHphcA==" , // "zip zap"
"context" : "pWZ6t/im3AORd0lVYE0zBdKpX6Bl3/SvFtoVTPWbdkzjG788XmMAnOlxandSdd7S" ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , req )
2016-08-26 21:01:56 +00:00
if err == nil && ( resp == nil || ! resp . IsError ( ) ) {
t . Fatal ( "expected error response" )
}
2016-08-07 19:53:40 +00:00
}
2016-08-07 19:16:36 +00:00
// Now test encrypting the same value twice
req . Data = map [ string ] interface { } {
"plaintext" : "emlwIHphcA==" , // "zip zap"
"nonce" : "b25ldHdvdGhyZWVl" , // "onetwothreee"
"context" : "pWZ6t/im3AORd0lVYE0zBdKpX6Bl3/SvFtoVTPWbdkzjG788XmMAnOlxandSdd7S" ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , req )
2017-07-07 12:23:12 +00:00
if err != nil {
t . Fatal ( err )
}
2016-08-07 19:16:36 +00:00
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
if resp . IsError ( ) {
t . Fatalf ( "got error response: %#v" , * resp )
}
ciphertext1 := resp . Data [ "ciphertext" ] . ( string )
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , req )
2017-07-07 12:23:12 +00:00
if err != nil {
t . Fatal ( err )
}
2016-08-07 19:16:36 +00:00
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
if resp . IsError ( ) {
t . Fatalf ( "got error response: %#v" , * resp )
}
ciphertext2 := resp . Data [ "ciphertext" ] . ( string )
if ciphertext1 != ciphertext2 {
t . Fatalf ( "expected the same ciphertext but got %s and %s" , ciphertext1 , ciphertext2 )
}
// For sanity, also check a different nonce value...
req . Data = map [ string ] interface { } {
"plaintext" : "emlwIHphcA==" , // "zip zap"
"nonce" : "dHdvdGhyZWVmb3Vy" , // "twothreefour"
"context" : "pWZ6t/im3AORd0lVYE0zBdKpX6Bl3/SvFtoVTPWbdkzjG788XmMAnOlxandSdd7S" ,
}
2016-08-26 21:01:56 +00:00
if ver < 2 {
req . Data [ "nonce" ] = "dHdvdGhyZWVmb3Vy" // "twothreefour"
} else {
req . Data [ "context" ] = "pWZ6t/im3AORd0lVYE0zBdKpX6Bl3/SvFtoVTPWbdkzjG788XmMAnOldandSdd7S"
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , req )
2017-07-07 12:23:12 +00:00
if err != nil {
t . Fatal ( err )
}
2016-08-07 19:16:36 +00:00
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
if resp . IsError ( ) {
t . Fatalf ( "got error response: %#v" , * resp )
}
ciphertext3 := resp . Data [ "ciphertext" ] . ( string )
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , req )
2017-07-07 12:23:12 +00:00
if err != nil {
t . Fatal ( err )
}
2016-08-07 19:16:36 +00:00
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
if resp . IsError ( ) {
t . Fatalf ( "got error response: %#v" , * resp )
}
ciphertext4 := resp . Data [ "ciphertext" ] . ( string )
if ciphertext3 != ciphertext4 {
t . Fatalf ( "expected the same ciphertext but got %s and %s" , ciphertext3 , ciphertext4 )
}
if ciphertext1 == ciphertext3 {
t . Fatalf ( "expected different ciphertexts" )
}
// ...and a different context value
req . Data = map [ string ] interface { } {
"plaintext" : "emlwIHphcA==" , // "zip zap"
"nonce" : "dHdvdGhyZWVmb3Vy" , // "twothreefour"
"context" : "qV4h9iQyvn+raODOer4JNAsOhkXBwdT4HZ677Ql4KLqXSU+Jk4C/fXBWbv6xkSYT" ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , req )
2017-07-07 12:23:12 +00:00
if err != nil {
t . Fatal ( err )
}
2016-08-07 19:16:36 +00:00
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
if resp . IsError ( ) {
t . Fatalf ( "got error response: %#v" , * resp )
}
ciphertext5 := resp . Data [ "ciphertext" ] . ( string )
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , req )
2017-07-07 12:23:12 +00:00
if err != nil {
t . Fatal ( err )
}
2016-08-07 19:16:36 +00:00
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
if resp . IsError ( ) {
t . Fatalf ( "got error response: %#v" , * resp )
}
ciphertext6 := resp . Data [ "ciphertext" ] . ( string )
if ciphertext5 != ciphertext6 {
t . Fatalf ( "expected the same ciphertext but got %s and %s" , ciphertext5 , ciphertext6 )
}
if ciphertext1 == ciphertext5 {
t . Fatalf ( "expected different ciphertexts" )
}
if ciphertext3 == ciphertext5 {
t . Fatalf ( "expected different ciphertexts" )
}
2016-09-13 16:00:04 +00:00
2018-06-05 22:51:35 +00:00
// If running version 2, check upgrade handling
if ver == 2 {
curr , err := keysutil . LoadPolicy ( context . Background ( ) , storage , path . Join ( p . StoragePrefix , "policy" , "testkey" ) )
if err != nil {
t . Fatal ( err )
}
if curr == nil {
t . Fatal ( "got nil policy" )
}
if curr . ConvergentVersion != 2 {
t . Fatalf ( "bad convergent version %d" , curr . ConvergentVersion )
}
key := curr . Keys [ strconv . Itoa ( curr . LatestVersion ) ]
if key . ConvergentVersion != 0 {
t . Fatalf ( "bad convergent key version %d" , key . ConvergentVersion )
}
curr . ConvergentVersion = 3
err = curr . Persist ( context . Background ( ) , storage )
if err != nil {
t . Fatal ( err )
}
b . invalidate ( context . Background ( ) , "policy/testkey" )
// Different algorithm, should be different value
resp , err = b . HandleRequest ( context . Background ( ) , req )
if err != nil {
t . Fatal ( err )
}
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
if resp . IsError ( ) {
t . Fatalf ( "got error response: %#v" , * resp )
}
ciphertext7 := resp . Data [ "ciphertext" ] . ( string )
// Now do it via key-specified version
if len ( curr . Keys ) != 1 {
t . Fatalf ( "unexpected length of keys %d" , len ( curr . Keys ) )
}
key = curr . Keys [ strconv . Itoa ( curr . LatestVersion ) ]
key . ConvergentVersion = 3
curr . Keys [ strconv . Itoa ( curr . LatestVersion ) ] = key
curr . ConvergentVersion = 2
err = curr . Persist ( context . Background ( ) , storage )
if err != nil {
t . Fatal ( err )
}
b . invalidate ( context . Background ( ) , "policy/testkey" )
resp , err = b . HandleRequest ( context . Background ( ) , req )
if err != nil {
t . Fatal ( err )
}
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 )
}
if ciphertext6 == ciphertext7 {
t . Fatalf ( "expected different ciphertexts" )
}
if ciphertext3 == ciphertext7 {
t . Fatalf ( "expected different ciphertexts" )
}
}
2016-09-13 16:00:04 +00:00
// 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" ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , req )
2017-07-07 12:23:12 +00:00
if err == nil {
t . Fatal ( "expected error, got nil" )
}
2016-09-13 16:00:04 +00:00
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" ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , req )
2017-07-07 12:23:12 +00:00
if err != nil {
t . Fatal ( err )
}
2016-09-13 16:00:04 +00:00
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
if resp . IsError ( ) {
t . Fatalf ( "got error response: %#v" , * resp )
}
ciphertext7 := resp . Data [ "ciphertext" ] . ( string )
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , req )
2017-07-07 12:23:12 +00:00
if err != nil {
t . Fatal ( err )
}
2016-09-13 16:00:04 +00:00
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 )
}
2016-08-07 19:16:36 +00:00
}
2016-02-03 22:25:48 +00:00
func TestPolicyFuzzing ( t * testing . T ) {
2016-04-21 20:32:06 +00:00
var be * backend
sysView := logical . TestSystemView ( )
2019-06-04 22:40:56 +00:00
sysView . CachingDisabledVal = true
2018-06-12 16:24:12 +00:00
conf := & logical . BackendConfig {
2016-04-21 20:32:06 +00:00
System : sysView ,
2018-06-12 16:24:12 +00:00
}
2019-06-04 22:40:56 +00:00
be , _ = Backend ( context . Background ( ) , conf )
2018-06-12 16:24:12 +00:00
be . Setup ( context . Background ( ) , conf )
2016-04-21 20:32:06 +00:00
testPolicyFuzzingCommon ( t , be )
sysView . CachingDisabledVal = true
2019-06-04 22:40:56 +00:00
be , _ = Backend ( context . Background ( ) , conf )
2018-06-12 16:24:12 +00:00
be . Setup ( context . Background ( ) , conf )
2016-04-21 20:32:06 +00:00
testPolicyFuzzingCommon ( t , be )
}
func testPolicyFuzzingCommon ( t * testing . T , be * backend ) {
2016-06-06 16:03:08 +00:00
storage := & logical . InmemStorage { }
2016-02-03 22:25:48 +00:00
wg := sync . WaitGroup { }
funcs := [ ] string { "encrypt" , "decrypt" , "rotate" , "change_min_version" }
2021-04-08 16:43:39 +00:00
// keys := []string{"test1", "test2", "test3", "test4", "test5"}
2016-02-03 22:25:48 +00:00
keys := [ ] string { "test1" , "test2" , "test3" }
// This is the goroutine loop
2016-04-21 20:32:06 +00:00
doFuzzy := func ( id int ) {
2016-02-03 22:25:48 +00:00
// Check for panics, otherwise notify we're done
defer func ( ) {
wg . Done ( )
} ( )
// Holds the latest encrypted value for each key
latestEncryptedText := map [ string ] string { }
startTime := time . Now ( )
req := & logical . Request {
Storage : storage ,
Data : map [ string ] interface { } { } ,
}
fd := & framework . FieldData { }
2016-04-21 20:32:06 +00:00
var chosenFunc , chosenKey string
2021-04-08 16:43:39 +00:00
// t.Errorf("Starting %d", id)
2016-02-03 22:25:48 +00:00
for {
// Stop after 10 seconds
if time . Now ( ) . Sub ( startTime ) > 10 * time . Second {
return
}
// Pick a function and a key
2016-04-21 21:08:44 +00:00
chosenFunc = funcs [ rand . Int ( ) % len ( funcs ) ]
chosenKey = keys [ rand . Int ( ) % len ( keys ) ]
2016-02-03 22:25:48 +00:00
fd . Raw = map [ string ] interface { } {
"name" : chosenKey ,
}
fd . Schema = be . pathKeys ( ) . Fields
// Try to write the key to make sure it exists
2018-01-08 18:31:38 +00:00
_ , err := be . pathPolicyWrite ( context . Background ( ) , req , fd )
2016-02-03 22:25:48 +00:00
if err != nil {
2018-06-12 16:24:12 +00:00
t . Errorf ( "got an error: %v" , err )
2016-02-03 22:25:48 +00:00
}
switch chosenFunc {
// Encrypt our plaintext and store the result
case "encrypt" :
2021-04-08 16:43:39 +00:00
// t.Errorf("%s, %s, %d", chosenFunc, chosenKey, id)
2016-02-03 22:25:48 +00:00
fd . Raw [ "plaintext" ] = base64 . StdEncoding . EncodeToString ( [ ] byte ( testPlaintext ) )
fd . Schema = be . pathEncrypt ( ) . Fields
2018-01-08 18:31:38 +00:00
resp , err := be . pathEncryptWrite ( context . Background ( ) , req , fd )
2016-02-03 22:25:48 +00:00
if err != nil {
2018-06-12 16:24:12 +00:00
t . Errorf ( "got an error: %v, resp is %#v" , err , * resp )
2016-02-03 22:25:48 +00:00
}
latestEncryptedText [ chosenKey ] = resp . Data [ "ciphertext" ] . ( string )
// Rotate to a new key version
case "rotate" :
2021-04-08 16:43:39 +00:00
// t.Errorf("%s, %s, %d", chosenFunc, chosenKey, id)
2016-02-03 22:25:48 +00:00
fd . Schema = be . pathRotate ( ) . Fields
2018-01-08 18:31:38 +00:00
resp , err := be . pathRotateWrite ( context . Background ( ) , req , fd )
2016-02-03 22:25:48 +00:00
if err != nil {
2018-06-12 16:24:12 +00:00
t . Errorf ( "got an error: %v, resp is %#v, chosenKey is %s" , err , * resp , chosenKey )
2016-02-03 22:25:48 +00:00
}
// Decrypt the ciphertext and compare the result
case "decrypt" :
2021-04-08 16:43:39 +00:00
// t.Errorf("%s, %s, %d", chosenFunc, chosenKey, id)
2016-02-03 22:25:48 +00:00
ct := latestEncryptedText [ chosenKey ]
if ct == "" {
continue
}
fd . Raw [ "ciphertext" ] = ct
fd . Schema = be . pathDecrypt ( ) . Fields
2018-01-08 18:31:38 +00:00
resp , err := be . pathDecryptWrite ( context . Background ( ) , req , fd )
2016-02-03 22:25:48 +00:00
if err != nil {
// This could well happen since the min version is jumping around
2016-10-26 23:52:31 +00:00
if resp . Data [ "error" ] . ( string ) == keysutil . ErrTooOld {
2016-02-03 22:25:48 +00:00
continue
}
2018-06-12 16:24:12 +00:00
t . Errorf ( "got an error: %v, resp is %#v, ciphertext was %s, chosenKey is %s, id is %d" , err , * resp , ct , chosenKey , id )
}
ptb64 , ok := resp . Data [ "plaintext" ] . ( string )
if ! ok {
t . Errorf ( "no plaintext found, response was %#v" , * resp )
return
2016-02-03 22:25:48 +00:00
}
pt , err := base64 . StdEncoding . DecodeString ( ptb64 )
if err != nil {
2018-06-12 16:24:12 +00:00
t . Errorf ( "got an error decoding base64 plaintext: %v" , err )
2016-02-03 22:25:48 +00:00
return
}
if string ( pt ) != testPlaintext {
2018-06-12 16:24:12 +00:00
t . Errorf ( "got bad plaintext back: %s" , pt )
2016-02-03 22:25:48 +00:00
}
// Change the min version, which also tests the archive functionality
case "change_min_version" :
2021-04-08 16:43:39 +00:00
// t.Errorf("%s, %s, %d", chosenFunc, chosenKey, id)
2018-01-08 18:31:38 +00:00
resp , err := be . pathPolicyRead ( context . Background ( ) , req , fd )
2016-02-03 22:25:48 +00:00
if err != nil {
2018-06-12 16:24:12 +00:00
t . Errorf ( "got an error reading policy %s: %v" , chosenKey , err )
2016-02-03 22:25:48 +00:00
}
latestVersion := resp . Data [ "latest_version" ] . ( int )
// keys start at version 1 so we want [1, latestVersion] not [0, latestVersion)
setVersion := ( rand . Int ( ) % latestVersion ) + 1
fd . Raw [ "min_decryption_version" ] = setVersion
2022-12-08 20:45:18 +00:00
fd . Schema = be . pathKeysConfig ( ) . Fields
resp , err = be . pathKeysConfigWrite ( context . Background ( ) , req , fd )
2016-02-03 22:25:48 +00:00
if err != nil {
2018-06-12 16:24:12 +00:00
t . Errorf ( "got an error setting min decryption version: %v" , err )
2016-02-03 22:25:48 +00:00
}
}
}
}
// Spawn 1000 of these workers for 10 seconds
for i := 0 ; i < 1000 ; i ++ {
wg . Add ( 1 )
2016-04-21 20:32:06 +00:00
go doFuzzy ( i )
2016-02-03 22:25:48 +00:00
}
// Wait for them all to finish
wg . Wait ( )
}
2017-11-02 21:40:52 +00:00
func TestBadInput ( t * testing . T ) {
2018-06-12 16:24:12 +00:00
b , storage := createBackendWithSysView ( t )
2017-11-02 21:40:52 +00:00
req := & logical . Request {
Storage : storage ,
Operation : logical . UpdateOperation ,
Path : "keys/test" ,
}
2018-01-08 18:31:38 +00:00
resp , err := b . HandleRequest ( context . Background ( ) , req )
2017-11-02 21:40:52 +00:00
if err != nil {
t . Fatal ( err )
}
2023-05-18 18:36:10 +00:00
require . NotNil ( t , resp , "expected populated request" )
2017-11-02 21:40:52 +00:00
req . Path = "decrypt/test"
req . Data = map [ string ] interface { } {
"ciphertext" : "vault:v1:abcd" ,
}
2018-01-08 18:31:38 +00:00
_ , err = b . HandleRequest ( context . Background ( ) , req )
2017-11-02 21:40:52 +00:00
if err == nil {
t . Fatal ( "expected error" )
}
}
2022-01-20 15:10:15 +00:00
func TestTransit_AutoRotateKeys ( t * testing . T ) {
tests := map [ string ] struct {
isDRSecondary bool
isPerfSecondary bool
isStandby bool
isLocal bool
shouldRotate bool
} {
"primary, no local mount" : {
shouldRotate : true ,
} ,
"DR secondary, no local mount" : {
isDRSecondary : true ,
shouldRotate : false ,
} ,
"perf standby, no local mount" : {
isStandby : true ,
shouldRotate : false ,
} ,
"perf secondary, no local mount" : {
isPerfSecondary : true ,
shouldRotate : false ,
} ,
"perf secondary, local mount" : {
isPerfSecondary : true ,
isLocal : true ,
shouldRotate : true ,
} ,
}
for name , test := range tests {
t . Run (
name ,
func ( t * testing . T ) {
var repState consts . ReplicationState
if test . isDRSecondary {
repState . AddState ( consts . ReplicationDRSecondary )
}
if test . isPerfSecondary {
repState . AddState ( consts . ReplicationPerformanceSecondary )
}
if test . isStandby {
repState . AddState ( consts . ReplicationPerformanceStandby )
}
sysView := logical . TestSystemView ( )
sysView . ReplicationStateVal = repState
sysView . LocalMountVal = test . isLocal
storage := & logical . InmemStorage { }
conf := & logical . BackendConfig {
StorageView : storage ,
System : sysView ,
}
b , _ := Backend ( context . Background ( ) , conf )
if b == nil {
t . Fatal ( "failed to create backend" )
}
err := b . Backend . Setup ( context . Background ( ) , conf )
if err != nil {
t . Fatal ( err )
}
// Write a key with the default auto rotate value (0/disabled)
req := & logical . Request {
Storage : storage ,
Operation : logical . UpdateOperation ,
Path : "keys/test1" ,
}
resp , err := b . HandleRequest ( context . Background ( ) , req )
if err != nil {
t . Fatal ( err )
}
2023-05-18 18:36:10 +00:00
require . NotNil ( t , resp , "expected populated request" )
2022-01-20 15:10:15 +00:00
// Write a key with an auto rotate value one day in the future
req = & logical . Request {
Storage : storage ,
Operation : logical . UpdateOperation ,
Path : "keys/test2" ,
Data : map [ string ] interface { } {
2022-02-17 20:17:59 +00:00
"auto_rotate_period" : 24 * time . Hour ,
2022-01-20 15:10:15 +00:00
} ,
}
resp , err = b . HandleRequest ( context . Background ( ) , req )
if err != nil {
t . Fatal ( err )
}
2023-05-18 18:36:10 +00:00
require . NotNil ( t , resp , "expected populated request" )
2022-01-20 15:10:15 +00:00
// Run the rotation check and ensure none of the keys have rotated
b . checkAutoRotateAfter = time . Now ( )
if err = b . autoRotateKeys ( context . Background ( ) , & logical . Request { Storage : storage } ) ; err != nil {
t . Fatal ( err )
}
req = & logical . Request {
Storage : storage ,
Operation : logical . ReadOperation ,
Path : "keys/test1" ,
}
resp , err = b . HandleRequest ( context . Background ( ) , req )
if err != nil {
t . Fatal ( err )
}
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
if resp . Data [ "latest_version" ] != 1 {
t . Fatalf ( "incorrect latest_version found, got: %d, want: %d" , resp . Data [ "latest_version" ] , 1 )
}
req . Path = "keys/test2"
resp , err = b . HandleRequest ( context . Background ( ) , req )
if err != nil {
t . Fatal ( err )
}
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
if resp . Data [ "latest_version" ] != 1 {
t . Fatalf ( "incorrect latest_version found, got: %d, want: %d" , resp . Data [ "latest_version" ] , 1 )
}
2022-02-17 20:17:59 +00:00
// Update auto rotate period on one key to be one nanosecond
2022-01-20 15:10:15 +00:00
p , _ , err := b . GetPolicy ( context . Background ( ) , keysutil . PolicyRequest {
Storage : storage ,
Name : "test2" ,
} , b . GetRandomReader ( ) )
if err != nil {
t . Fatal ( err )
}
if p == nil {
t . Fatal ( "expected non-nil policy" )
}
2022-02-17 20:17:59 +00:00
p . AutoRotatePeriod = time . Nanosecond
2022-01-20 15:10:15 +00:00
err = p . Persist ( context . Background ( ) , storage )
if err != nil {
t . Fatal ( err )
}
// Run the rotation check and validate the state of key rotations
b . checkAutoRotateAfter = time . Now ( )
if err = b . autoRotateKeys ( context . Background ( ) , & logical . Request { Storage : storage } ) ; err != nil {
t . Fatal ( err )
}
req = & logical . Request {
Storage : storage ,
Operation : logical . ReadOperation ,
Path : "keys/test1" ,
}
resp , err = b . HandleRequest ( context . Background ( ) , req )
if err != nil {
t . Fatal ( err )
}
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
if resp . Data [ "latest_version" ] != 1 {
t . Fatalf ( "incorrect latest_version found, got: %d, want: %d" , resp . Data [ "latest_version" ] , 1 )
}
req . Path = "keys/test2"
resp , err = b . HandleRequest ( context . Background ( ) , req )
if err != nil {
t . Fatal ( err )
}
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
expectedVersion := 1
if test . shouldRotate {
expectedVersion = 2
}
if resp . Data [ "latest_version" ] != expectedVersion {
t . Fatalf ( "incorrect latest_version found, got: %d, want: %d" , resp . Data [ "latest_version" ] , expectedVersion )
}
} ,
)
}
}
2022-10-24 17:41:02 +00:00
func TestTransit_AEAD ( t * testing . T ) {
testTransit_AEAD ( t , "aes128-gcm96" )
testTransit_AEAD ( t , "aes256-gcm96" )
testTransit_AEAD ( t , "chacha20-poly1305" )
}
func testTransit_AEAD ( t * testing . T , keyType string ) {
var resp * logical . Response
var err error
b , storage := createBackendWithStorage ( t )
keyReq := & logical . Request {
Path : "keys/aead" ,
Operation : logical . UpdateOperation ,
Data : map [ string ] interface { } {
"type" : keyType ,
} ,
Storage : storage ,
}
resp , err = b . HandleRequest ( context . Background ( ) , keyReq )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
plaintext := "dGhlIHF1aWNrIGJyb3duIGZveA==" // "the quick brown fox"
associated := "U3BoaW54IG9mIGJsYWNrIHF1YXJ0eiwganVkZ2UgbXkgdm93Lgo=" // "Sphinx of black quartz, judge my vow."
// Basic encrypt/decrypt should work.
encryptReq := & logical . Request {
Path : "encrypt/aead" ,
Operation : logical . UpdateOperation ,
Storage : storage ,
Data : map [ string ] interface { } {
"plaintext" : plaintext ,
} ,
}
resp , err = b . HandleRequest ( context . Background ( ) , encryptReq )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
ciphertext1 := resp . Data [ "ciphertext" ] . ( string )
decryptReq := & logical . Request {
Path : "decrypt/aead" ,
Operation : logical . UpdateOperation ,
Storage : storage ,
Data : map [ string ] interface { } {
"ciphertext" : ciphertext1 ,
} ,
}
resp , err = b . HandleRequest ( context . Background ( ) , decryptReq )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
decryptedPlaintext := resp . Data [ "plaintext" ]
if plaintext != decryptedPlaintext {
t . Fatalf ( "bad: plaintext; expected: %q\nactual: %q" , plaintext , decryptedPlaintext )
}
// Using associated as ciphertext should fail.
decryptReq . Data [ "ciphertext" ] = associated
resp , err = b . HandleRequest ( context . Background ( ) , decryptReq )
if err == nil || ( resp != nil && ! resp . IsError ( ) ) {
t . Fatalf ( "bad expected error: err: %v\nresp: %#v" , err , resp )
}
// Redoing the above with additional data should work.
encryptReq . Data [ "associated_data" ] = associated
resp , err = b . HandleRequest ( context . Background ( ) , encryptReq )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
ciphertext2 := resp . Data [ "ciphertext" ] . ( string )
decryptReq . Data [ "ciphertext" ] = ciphertext2
decryptReq . Data [ "associated_data" ] = associated
resp , err = b . HandleRequest ( context . Background ( ) , decryptReq )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: err: %v\nresp: %#v" , err , resp )
}
decryptedPlaintext = resp . Data [ "plaintext" ]
if plaintext != decryptedPlaintext {
t . Fatalf ( "bad: plaintext; expected: %q\nactual: %q" , plaintext , decryptedPlaintext )
}
// Removing the associated_data should break the decryption.
decryptReq . Data = map [ string ] interface { } {
"ciphertext" : ciphertext2 ,
}
resp , err = b . HandleRequest ( context . Background ( ) , decryptReq )
if err == nil || ( resp != nil && ! resp . IsError ( ) ) {
t . Fatalf ( "bad expected error: err: %v\nresp: %#v" , err , resp )
}
// Using a valid ciphertext with associated_data should also break the
// decryption.
decryptReq . Data [ "ciphertext" ] = ciphertext1
decryptReq . Data [ "associated_data" ] = associated
resp , err = b . HandleRequest ( context . Background ( ) , decryptReq )
if err == nil || ( resp != nil && ! resp . IsError ( ) ) {
t . Fatalf ( "bad expected error: err: %v\nresp: %#v" , err , resp )
}
}
2022-11-23 17:57:23 +00:00
// Hack: use Transit as a signer.
type transitKey struct {
public any
mount string
name string
t * testing . T
client * api . Client
}
func ( k * transitKey ) Public ( ) crypto . PublicKey {
return k . public
}
func ( k * transitKey ) Sign ( _ io . Reader , digest [ ] byte , opts crypto . SignerOpts ) ( signature [ ] byte , err error ) {
hash := opts . ( crypto . Hash )
if hash . String ( ) != "SHA-256" {
return nil , fmt . Errorf ( "unknown hash algorithm: %v" , opts )
}
resp , err := k . client . Logical ( ) . Write ( k . mount + "/sign/" + k . name , map [ string ] interface { } {
"hash_algorithm" : "sha2-256" ,
"input" : base64 . StdEncoding . EncodeToString ( digest ) ,
"prehashed" : true ,
"signature_algorithm" : "pkcs1v15" ,
} )
if err != nil {
return nil , fmt . Errorf ( "failed to sign data: %w" , err )
}
require . NotNil ( k . t , resp )
require . NotNil ( k . t , resp . Data )
require . NotNil ( k . t , resp . Data [ "signature" ] )
rawSig := resp . Data [ "signature" ] . ( string )
sigParts := strings . Split ( rawSig , ":" )
decoded , err := base64 . StdEncoding . DecodeString ( sigParts [ 2 ] )
if err != nil {
return nil , fmt . Errorf ( "failed to decode signature (%v): %w" , rawSig , err )
}
return decoded , nil
}
func TestTransitPKICSR ( t * testing . T ) {
coreConfig := & vault . CoreConfig {
LogicalBackends : map [ string ] logical . Factory {
"transit" : Factory ,
"pki" : pki . Factory ,
} ,
}
cluster := vault . NewTestCluster ( t , coreConfig , & vault . TestClusterOptions {
HandlerFunc : vaulthttp . Handler ,
} )
cluster . Start ( )
defer cluster . Cleanup ( )
cores := cluster . Cores
vault . TestWaitActive ( t , cores [ 0 ] . Core )
client := cores [ 0 ] . Client
// Mount transit, write a key.
err := client . Sys ( ) . Mount ( "transit" , & api . MountInput {
Type : "transit" ,
} )
require . NoError ( t , err )
_ , err = client . Logical ( ) . Write ( "transit/keys/leaf" , map [ string ] interface { } {
"type" : "rsa-2048" ,
} )
require . NoError ( t , err )
resp , err := client . Logical ( ) . Read ( "transit/keys/leaf" )
require . NoError ( t , err )
require . NotNil ( t , resp )
keys := resp . Data [ "keys" ] . ( map [ string ] interface { } )
require . NotNil ( t , keys )
keyData := keys [ "1" ] . ( map [ string ] interface { } )
require . NotNil ( t , keyData )
keyPublic := keyData [ "public_key" ] . ( string )
require . NotEmpty ( t , keyPublic )
pemBlock , _ := pem . Decode ( [ ] byte ( keyPublic ) )
require . NotNil ( t , pemBlock )
pubKey , err := x509 . ParsePKIXPublicKey ( pemBlock . Bytes )
require . NoError ( t , err )
require . NotNil ( t , pubKey )
// Setup a new CSR...
var reqTemplate x509 . CertificateRequest
reqTemplate . PublicKey = pubKey
reqTemplate . PublicKeyAlgorithm = x509 . RSA
reqTemplate . Subject . CommonName = "dadgarcorp.com"
var k transitKey
k . public = pubKey
k . mount = "transit"
k . name = "leaf"
k . t = t
k . client = client
req , err := x509 . CreateCertificateRequest ( cryptoRand . Reader , & reqTemplate , & k )
require . NoError ( t , err )
require . NotNil ( t , req )
reqPEM := pem . EncodeToMemory ( & pem . Block {
Type : "CERTIFICATE REQUEST" ,
Bytes : req ,
} )
t . Logf ( "csr: %v" , string ( reqPEM ) )
// Mount PKI, generate a root, sign this CSR.
err = client . Sys ( ) . Mount ( "pki" , & api . MountInput {
Type : "pki" ,
} )
require . NoError ( t , err )
resp , err = client . Logical ( ) . Write ( "pki/root/generate/internal" , map [ string ] interface { } {
"common_name" : "PKI Root X1" ,
} )
require . NoError ( t , err )
require . NotNil ( t , resp )
rootCertPEM := resp . Data [ "certificate" ] . ( string )
pemBlock , _ = pem . Decode ( [ ] byte ( rootCertPEM ) )
require . NotNil ( t , pemBlock )
rootCert , err := x509 . ParseCertificate ( pemBlock . Bytes )
require . NoError ( t , err )
resp , err = client . Logical ( ) . Write ( "pki/issuer/default/sign-verbatim" , map [ string ] interface { } {
"csr" : string ( reqPEM ) ,
"ttl" : "10m" ,
} )
require . NoError ( t , err )
require . NotNil ( t , resp )
leafCertPEM := resp . Data [ "certificate" ] . ( string )
pemBlock , _ = pem . Decode ( [ ] byte ( leafCertPEM ) )
require . NotNil ( t , pemBlock )
leafCert , err := x509 . ParseCertificate ( pemBlock . Bytes )
require . NoError ( t , err )
require . NoError ( t , leafCert . CheckSignatureFrom ( rootCert ) )
t . Logf ( "root: %v" , rootCertPEM )
t . Logf ( "leaf: %v" , leafCertPEM )
}
2023-05-11 11:56:46 +00:00
func TestTransit_ReadPublicKeyImported ( t * testing . T ) {
testTransit_ReadPublicKeyImported ( t , "rsa-2048" )
testTransit_ReadPublicKeyImported ( t , "ecdsa-p256" )
2023-05-24 15:26:35 +00:00
testTransit_ReadPublicKeyImported ( t , "ed25519" )
2023-05-11 11:56:46 +00:00
}
func testTransit_ReadPublicKeyImported ( t * testing . T , keyType string ) {
generateKeys ( t )
b , s := createBackendWithStorage ( t )
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 . Fatalf ( "failed to extract the public key: %s" , err )
}
// Import key
importReq := & logical . Request {
Storage : s ,
Operation : logical . UpdateOperation ,
Path : fmt . Sprintf ( "keys/%s/import" , keyID ) ,
Data : map [ string ] interface { } {
"public_key" : publicKeyBytes ,
"type" : keyType ,
} ,
}
importResp , err := b . HandleRequest ( context . Background ( ) , importReq )
if err != nil || ( importResp != nil && importResp . IsError ( ) ) {
t . Fatalf ( "failed to import public key. err: %s\nresp: %#v" , err , importResp )
}
// Read key
readReq := & logical . Request {
Operation : logical . ReadOperation ,
Path : "keys/" + keyID ,
Storage : s ,
}
readResp , err := b . HandleRequest ( context . Background ( ) , readReq )
if err != nil || ( readResp != nil && readResp . IsError ( ) ) {
t . Fatalf ( "failed to read key. err: %s\nresp: %#v" , err , readResp )
}
}
func TestTransit_SignWithImportedPublicKey ( t * testing . T ) {
testTransit_SignWithImportedPublicKey ( t , "rsa-2048" )
testTransit_SignWithImportedPublicKey ( t , "ecdsa-p256" )
2023-05-24 15:26:35 +00:00
testTransit_SignWithImportedPublicKey ( t , "ed25519" )
2023-05-11 11:56:46 +00:00
}
func testTransit_SignWithImportedPublicKey ( t * testing . T , keyType string ) {
generateKeys ( t )
b , s := createBackendWithStorage ( t )
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 . Fatalf ( "failed to extract the public key: %s" , err )
}
// Import key
importReq := & logical . Request {
Storage : s ,
Operation : logical . UpdateOperation ,
Path : fmt . Sprintf ( "keys/%s/import" , keyID ) ,
Data : map [ string ] interface { } {
"public_key" : publicKeyBytes ,
"type" : keyType ,
} ,
}
importResp , err := b . HandleRequest ( context . Background ( ) , importReq )
if err != nil || ( importResp != nil && importResp . IsError ( ) ) {
t . Fatalf ( "failed to import public key. err: %s\nresp: %#v" , err , importResp )
}
// Sign text
signReq := & logical . Request {
Path : "sign/" + keyID ,
Operation : logical . UpdateOperation ,
Storage : s ,
Data : map [ string ] interface { } {
"plaintext" : base64 . StdEncoding . EncodeToString ( [ ] byte ( testPlaintext ) ) ,
} ,
}
_ , err = b . HandleRequest ( context . Background ( ) , signReq )
if err == nil {
t . Fatalf ( "expected error, should have failed to sign input" )
}
}
func TestTransit_VerifyWithImportedPublicKey ( t * testing . T ) {
generateKeys ( t )
keyType := "rsa-2048"
b , s := createBackendWithStorage ( t )
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 )
}
// Retrieve public wrapping key
wrappingKey , err := b . getWrappingKey ( context . Background ( ) , s )
if err != nil || wrappingKey == nil {
t . Fatalf ( "failed to retrieve public wrapping key: %s" , err )
}
privWrappingKey := wrappingKey . Keys [ strconv . Itoa ( wrappingKey . LatestVersion ) ] . RSAKey
pubWrappingKey := & privWrappingKey . PublicKey
// generate ciphertext
importBlob := wrapTargetKeyForImport ( t , pubWrappingKey , privateKey , keyType , "SHA256" )
// Import private key
importReq := & logical . Request {
Storage : s ,
Operation : logical . UpdateOperation ,
Path : fmt . Sprintf ( "keys/%s/import" , keyID ) ,
Data : map [ string ] interface { } {
"ciphertext" : importBlob ,
"type" : keyType ,
} ,
}
importResp , err := b . HandleRequest ( context . Background ( ) , importReq )
if err != nil || ( importResp != nil && importResp . IsError ( ) ) {
t . Fatalf ( "failed to import key. err: %s\nresp: %#v" , err , importResp )
}
// Sign text
signReq := & logical . Request {
Storage : s ,
Path : "sign/" + keyID ,
Operation : logical . UpdateOperation ,
Data : map [ string ] interface { } {
"plaintext" : base64 . StdEncoding . EncodeToString ( [ ] byte ( testPlaintext ) ) ,
} ,
}
signResp , err := b . HandleRequest ( context . Background ( ) , signReq )
if err != nil || ( signResp != nil && signResp . IsError ( ) ) {
t . Fatalf ( "failed to sign plaintext. err: %s\nresp: %#v" , err , signResp )
}
// Get signature
signature := signResp . Data [ "signature" ] . ( string )
// Import new key as public key
importPubReq := & logical . Request {
Storage : s ,
Operation : logical . UpdateOperation ,
Path : fmt . Sprintf ( "keys/%s/import" , "public-key-rsa" ) ,
Data : map [ string ] interface { } {
"public_key" : publicKeyBytes ,
"type" : keyType ,
} ,
}
importPubResp , err := b . HandleRequest ( context . Background ( ) , importPubReq )
if err != nil || ( importPubResp != nil && importPubResp . IsError ( ) ) {
t . Fatalf ( "failed to import public key. err: %s\nresp: %#v" , err , importPubResp )
}
// Verify signed text
verifyReq := & logical . Request {
Path : "verify/public-key-rsa" ,
Operation : logical . UpdateOperation ,
Storage : s ,
Data : map [ string ] interface { } {
"input" : base64 . StdEncoding . EncodeToString ( [ ] byte ( testPlaintext ) ) ,
"signature" : signature ,
} ,
}
verifyResp , err := b . HandleRequest ( context . Background ( ) , verifyReq )
if err != nil || ( importResp != nil && verifyResp . IsError ( ) ) {
t . Fatalf ( "failed to verify signed data. err: %s\nresp: %#v" , err , importResp )
}
}
func TestTransit_ExportPublicKeyImported ( t * testing . T ) {
testTransit_ExportPublicKeyImported ( t , "rsa-2048" )
testTransit_ExportPublicKeyImported ( t , "ecdsa-p256" )
2023-05-24 15:26:35 +00:00
testTransit_ExportPublicKeyImported ( t , "ed25519" )
2023-05-11 11:56:46 +00:00
}
func testTransit_ExportPublicKeyImported ( t * testing . T , keyType string ) {
generateKeys ( t )
b , s := createBackendWithStorage ( t )
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 . Fatalf ( "failed to extract the public key: %s" , err )
}
2023-05-24 15:26:35 +00:00
t . Logf ( "generated key: %v" , string ( publicKeyBytes ) )
2023-05-11 11:56:46 +00:00
// Import key
importReq := & logical . Request {
Storage : s ,
Operation : logical . UpdateOperation ,
Path : fmt . Sprintf ( "keys/%s/import" , keyID ) ,
Data : map [ string ] interface { } {
"public_key" : publicKeyBytes ,
"type" : keyType ,
"exportable" : true ,
} ,
}
importResp , err := b . HandleRequest ( context . Background ( ) , importReq )
if err != nil || ( importResp != nil && importResp . IsError ( ) ) {
t . Fatalf ( "failed to import public key. err: %s\nresp: %#v" , err , importResp )
}
2023-05-24 15:26:35 +00:00
t . Logf ( "importing key: %v" , importResp )
2023-05-11 11:56:46 +00:00
// Export key
exportReq := & logical . Request {
Operation : logical . ReadOperation ,
2023-05-24 15:26:35 +00:00
Path : fmt . Sprintf ( "export/public-key/%s/latest" , keyID ) ,
2023-05-11 11:56:46 +00:00
Storage : s ,
}
exportResp , err := b . HandleRequest ( context . Background ( ) , exportReq )
if err != nil || ( exportResp != nil && exportResp . IsError ( ) ) {
t . Fatalf ( "failed to export key. err: %v\nresp: %#v" , err , exportResp )
}
2023-05-24 15:26:35 +00:00
t . Logf ( "exporting key: %v" , exportResp )
2023-05-11 11:56:46 +00:00
responseKeys , exist := exportResp . Data [ "keys" ]
if ! exist {
t . Fatal ( "expected response data to hold a 'keys' field" )
}
exportedKeyBytes := responseKeys . ( map [ string ] string ) [ "1" ]
2023-05-24 15:26:35 +00:00
if keyType != "ed25519" {
exportedKeyBlock , _ := pem . Decode ( [ ] byte ( exportedKeyBytes ) )
publicKeyBlock , _ := pem . Decode ( publicKeyBytes )
if ! reflect . DeepEqual ( publicKeyBlock . Bytes , exportedKeyBlock . Bytes ) {
t . Fatalf ( "exported key bytes should have matched with imported key for key type: %v\nexported: %v\nimported: %v" , keyType , exportedKeyBlock . Bytes , publicKeyBlock . Bytes )
}
} else {
exportedKey , err := base64 . StdEncoding . DecodeString ( exportedKeyBytes )
if err != nil {
t . Fatalf ( "error decoding exported key bytes (%v) to base64 for key type %v: %v" , exportedKeyBytes , keyType , err )
}
publicKeyBlock , _ := pem . Decode ( publicKeyBytes )
publicKeyParsed , err := x509 . ParsePKIXPublicKey ( publicKeyBlock . Bytes )
if err != nil {
t . Fatalf ( "error decoding source key bytes (%v) from PKIX marshaling for key type %v: %v" , publicKeyBlock . Bytes , keyType , err )
}
if ! reflect . DeepEqual ( [ ] byte ( publicKeyParsed . ( ed25519 . PublicKey ) ) , exportedKey ) {
t . Fatalf ( "exported key bytes should have matched with imported key for key type: %v\nexported: %v\nimported: %v" , keyType , exportedKey , publicKeyParsed )
}
2023-05-11 11:56:46 +00:00
}
}