Add AES128-GCM96 support to transit (#7555)

This commit is contained in:
Jeff Mitchell 2019-10-03 16:11:43 -04:00 committed by GitHub
parent f714060c47
commit 4252f5c9e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 79 additions and 31 deletions

View File

@ -968,8 +968,10 @@ func testDerivedKeyUpgrade(t *testing.T, keyType keysutil.KeyType) {
func TestConvergentEncryption(t *testing.T) { func TestConvergentEncryption(t *testing.T) {
testConvergentEncryptionCommon(t, 0, keysutil.KeyType_AES256_GCM96) testConvergentEncryptionCommon(t, 0, keysutil.KeyType_AES256_GCM96)
testConvergentEncryptionCommon(t, 2, keysutil.KeyType_AES128_GCM96)
testConvergentEncryptionCommon(t, 2, keysutil.KeyType_AES256_GCM96) testConvergentEncryptionCommon(t, 2, keysutil.KeyType_AES256_GCM96)
testConvergentEncryptionCommon(t, 2, keysutil.KeyType_ChaCha20_Poly1305) testConvergentEncryptionCommon(t, 2, keysutil.KeyType_ChaCha20_Poly1305)
testConvergentEncryptionCommon(t, 3, keysutil.KeyType_AES128_GCM96)
testConvergentEncryptionCommon(t, 3, keysutil.KeyType_AES256_GCM96) testConvergentEncryptionCommon(t, 3, keysutil.KeyType_AES256_GCM96)
testConvergentEncryptionCommon(t, 3, keysutil.KeyType_ChaCha20_Poly1305) testConvergentEncryptionCommon(t, 3, keysutil.KeyType_ChaCha20_Poly1305)
} }

View File

@ -9,6 +9,7 @@ import (
func TestTransit_BackupRestore(t *testing.T) { func TestTransit_BackupRestore(t *testing.T) {
// Test encryption/decryption after a restore for supported keys // Test encryption/decryption after a restore for supported keys
testBackupRestore(t, "aes128-gcm96", "encrypt-decrypt")
testBackupRestore(t, "aes256-gcm96", "encrypt-decrypt") testBackupRestore(t, "aes256-gcm96", "encrypt-decrypt")
testBackupRestore(t, "chacha20-poly1305", "encrypt-decrypt") testBackupRestore(t, "chacha20-poly1305", "encrypt-decrypt")
testBackupRestore(t, "rsa-2048", "encrypt-decrypt") testBackupRestore(t, "rsa-2048", "encrypt-decrypt")
@ -23,6 +24,7 @@ func TestTransit_BackupRestore(t *testing.T) {
testBackupRestore(t, "rsa-4096", "sign-verify") testBackupRestore(t, "rsa-4096", "sign-verify")
// Test HMAC/verification after a restore for all key types // Test HMAC/verification after a restore for all key types
testBackupRestore(t, "aes128-gcm96", "hmac-verify")
testBackupRestore(t, "aes256-gcm96", "hmac-verify") testBackupRestore(t, "aes256-gcm96", "hmac-verify")
testBackupRestore(t, "chacha20-poly1305", "hmac-verify") testBackupRestore(t, "chacha20-poly1305", "hmac-verify")
testBackupRestore(t, "ecdsa-p256", "hmac-verify") testBackupRestore(t, "ecdsa-p256", "hmac-verify")

View File

@ -32,13 +32,17 @@ func TestTransit_ConfigSettings(t *testing.T) {
req := &logical.Request{ req := &logical.Request{
Storage: storage, Storage: storage,
Operation: logical.UpdateOperation, Operation: logical.UpdateOperation,
Path: "keys/aes", Path: "keys/aes256",
Data: map[string]interface{}{ Data: map[string]interface{}{
"derived": true, "derived": true,
}, },
} }
doReq(req) doReq(req)
req.Path = "keys/aes128"
req.Data["type"] = "aes128-gcm96"
doReq(req)
req.Path = "keys/ed" req.Path = "keys/ed"
req.Data["type"] = "ed25519" req.Data["type"] = "ed25519"
doReq(req) doReq(req)
@ -59,7 +63,13 @@ func TestTransit_ConfigSettings(t *testing.T) {
delete(req.Data, "type") delete(req.Data, "type")
req.Path = "keys/aes/rotate" req.Path = "keys/aes128/rotate"
doReq(req)
doReq(req)
doReq(req)
doReq(req)
req.Path = "keys/aes256/rotate"
doReq(req) doReq(req)
doReq(req) doReq(req)
doReq(req) doReq(req)
@ -89,7 +99,7 @@ func TestTransit_ConfigSettings(t *testing.T) {
doReq(req) doReq(req)
doReq(req) doReq(req)
req.Path = "keys/aes/config" req.Path = "keys/aes256/config"
// Too high // Too high
req.Data["min_decryption_version"] = 7 req.Data["min_decryption_version"] = 7
doErrReq(req) doErrReq(req)
@ -114,6 +124,8 @@ func TestTransit_ConfigSettings(t *testing.T) {
req.Data["min_decryption_version"] = 2 req.Data["min_decryption_version"] = 2
req.Data["min_encryption_version"] = 3 req.Data["min_encryption_version"] = 3
doReq(req) doReq(req)
req.Path = "keys/aes128/config"
doReq(req)
req.Path = "keys/ed/config" req.Path = "keys/ed/config"
doReq(req) doReq(req)
req.Path = "keys/p256/config" req.Path = "keys/p256/config"
@ -131,7 +143,7 @@ func TestTransit_ConfigSettings(t *testing.T) {
} }
maxKeyVersion := 5 maxKeyVersion := 5
key := "aes" key := "aes256"
testHMAC := func(ver int, valid bool) { testHMAC := func(ver int, valid bool) {
req.Path = "hmac/" + key req.Path = "hmac/" + key
@ -193,6 +205,16 @@ func TestTransit_ConfigSettings(t *testing.T) {
testHMAC(3, true) testHMAC(3, true)
testHMAC(2, false) testHMAC(2, false)
key = "aes128"
testEncryptDecrypt(5, true)
testEncryptDecrypt(4, true)
testEncryptDecrypt(3, true)
testEncryptDecrypt(2, false)
testHMAC(5, true)
testHMAC(4, true)
testHMAC(3, true)
testHMAC(2, false)
delete(req.Data, "plaintext") delete(req.Data, "plaintext")
req.Data["input"] = "abcd" req.Data["input"] = "abcd"
key = "ed" key = "ed"

View File

@ -88,8 +88,7 @@ encryption key) this nonce value is **never reused**.
Description: ` Description: `
This parameter is required when encryption key is expected to be created. This parameter is required when encryption key is expected to be created.
When performing an upsert operation, the type of key to create. Currently, When performing an upsert operation, the type of key to create. Currently,
"aes256-gcm96" (symmetric) is the only type supported. Defaults to "aes128-gcm96" (symmetric) and "aes256-gcm96" (symmetric) are the only types supported. Defaults to "aes256-gcm96".`,
"aes256-gcm96".`,
}, },
"convergent_encryption": &framework.FieldSchema{ "convergent_encryption": &framework.FieldSchema{
@ -228,6 +227,8 @@ func (b *backend) pathEncryptWrite(ctx context.Context, req *logical.Request, d
keyType := d.Get("type").(string) keyType := d.Get("type").(string)
switch keyType { switch keyType {
case "aes128-gcm96":
polReq.KeyType = keysutil.KeyType_AES128_GCM96
case "aes256-gcm96": case "aes256-gcm96":
polReq.KeyType = keysutil.KeyType_AES256_GCM96 polReq.KeyType = keysutil.KeyType_AES256_GCM96
case "chacha20-poly1305": case "chacha20-poly1305":

View File

@ -155,7 +155,7 @@ func getExportKey(policy *keysutil.Policy, key *keysutil.KeyEntry, exportType st
case exportTypeEncryptionKey: case exportTypeEncryptionKey:
switch policy.Type { switch policy.Type {
case keysutil.KeyType_AES256_GCM96, keysutil.KeyType_ChaCha20_Poly1305: case keysutil.KeyType_AES128_GCM96, keysutil.KeyType_AES256_GCM96, keysutil.KeyType_ChaCha20_Poly1305:
return strings.TrimSpace(base64.StdEncoding.EncodeToString(key.Key)), nil return strings.TrimSpace(base64.StdEncoding.EncodeToString(key.Key)), nil
case keysutil.KeyType_RSA2048, keysutil.KeyType_RSA4096: case keysutil.KeyType_RSA2048, keysutil.KeyType_RSA4096:

View File

@ -11,12 +11,14 @@ import (
) )
func TestTransit_Export_KeyVersion_ExportsCorrectVersion(t *testing.T) { func TestTransit_Export_KeyVersion_ExportsCorrectVersion(t *testing.T) {
verifyExportsCorrectVersion(t, "encryption-key", "aes128-gcm96")
verifyExportsCorrectVersion(t, "encryption-key", "aes256-gcm96") verifyExportsCorrectVersion(t, "encryption-key", "aes256-gcm96")
verifyExportsCorrectVersion(t, "encryption-key", "chacha20-poly1305") verifyExportsCorrectVersion(t, "encryption-key", "chacha20-poly1305")
verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p256") verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p256")
verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p384") verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p384")
verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p521") verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p521")
verifyExportsCorrectVersion(t, "signing-key", "ed25519") verifyExportsCorrectVersion(t, "signing-key", "ed25519")
verifyExportsCorrectVersion(t, "hmac-key", "aes128-gcm96")
verifyExportsCorrectVersion(t, "hmac-key", "aes256-gcm96") verifyExportsCorrectVersion(t, "hmac-key", "aes256-gcm96")
verifyExportsCorrectVersion(t, "hmac-key", "chacha20-poly1305") verifyExportsCorrectVersion(t, "hmac-key", "chacha20-poly1305")
verifyExportsCorrectVersion(t, "hmac-key", "ecdsa-p256") verifyExportsCorrectVersion(t, "hmac-key", "ecdsa-p256")

View File

@ -45,7 +45,7 @@ func (b *backend) pathKeys() *framework.Path {
Type: framework.TypeString, Type: framework.TypeString,
Default: "aes256-gcm96", Default: "aes256-gcm96",
Description: ` Description: `
The type of key to create. Currently, "aes256-gcm96" (symmetric), "ecdsa-p256" The type of key to create. Currently, "aes128-gcm96" (symmetric), "aes256-gcm96" (symmetric), "ecdsa-p256"
(asymmetric), "ecdsa-p384" (asymmetric), "ecdsa-p521" (asymmetric), "ed25519" (asymmetric), "rsa-2048" (asymmetric), "rsa-4096" (asymmetric), "ecdsa-p384" (asymmetric), "ecdsa-p521" (asymmetric), "ed25519" (asymmetric), "rsa-2048" (asymmetric), "rsa-4096"
(asymmetric) are supported. Defaults to "aes256-gcm96". (asymmetric) are supported. Defaults to "aes256-gcm96".
`, `,
@ -139,6 +139,8 @@ func (b *backend) pathPolicyWrite(ctx context.Context, req *logical.Request, d *
AllowPlaintextBackup: allowPlaintextBackup, AllowPlaintextBackup: allowPlaintextBackup,
} }
switch keyType { switch keyType {
case "aes128-gcm96":
polReq.KeyType = keysutil.KeyType_AES128_GCM96
case "aes256-gcm96": case "aes256-gcm96":
polReq.KeyType = keysutil.KeyType_AES256_GCM96 polReq.KeyType = keysutil.KeyType_AES256_GCM96
case "chacha20-poly1305": case "chacha20-poly1305":
@ -260,7 +262,7 @@ func (b *backend) pathPolicyRead(ctx context.Context, req *logical.Request, d *f
} }
switch p.Type { switch p.Type {
case keysutil.KeyType_AES256_GCM96, keysutil.KeyType_ChaCha20_Poly1305: case keysutil.KeyType_AES128_GCM96, keysutil.KeyType_AES256_GCM96, keysutil.KeyType_ChaCha20_Poly1305:
retKeys := map[string]int64{} retKeys := map[string]int64{}
for k, v := range p.Keys { for k, v := range p.Keys {
retKeys[k] = v.DeprecatedCreationTime retKeys[k] = v.DeprecatedCreationTime

View File

@ -327,7 +327,7 @@ func (lm *LockManager) GetPolicy(ctx context.Context, req PolicyRequest) (retP *
// because we don't know if the parameters match. // because we don't know if the parameters match.
switch req.KeyType { switch req.KeyType {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305: case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
if req.Convergent && !req.Derived { if req.Convergent && !req.Derived {
cleanup() cleanup()
return nil, false, fmt.Errorf("convergent encryption requires derivation to be enabled") return nil, false, fmt.Errorf("convergent encryption requires derivation to be enabled")

View File

@ -57,6 +57,7 @@ const (
KeyType_ChaCha20_Poly1305 KeyType_ChaCha20_Poly1305
KeyType_ECDSA_P384 KeyType_ECDSA_P384
KeyType_ECDSA_P521 KeyType_ECDSA_P521
KeyType_AES128_GCM96
) )
const ( const (
@ -91,7 +92,7 @@ type KeyType int
func (kt KeyType) EncryptionSupported() bool { func (kt KeyType) EncryptionSupported() bool {
switch kt { switch kt {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_RSA2048, KeyType_RSA4096: case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_RSA2048, KeyType_RSA4096:
return true return true
} }
return false return false
@ -99,7 +100,7 @@ func (kt KeyType) EncryptionSupported() bool {
func (kt KeyType) DecryptionSupported() bool { func (kt KeyType) DecryptionSupported() bool {
switch kt { switch kt {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_RSA2048, KeyType_RSA4096: case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_RSA2048, KeyType_RSA4096:
return true return true
} }
return false return false
@ -123,7 +124,7 @@ func (kt KeyType) HashSignatureInput() bool {
func (kt KeyType) DerivationSupported() bool { func (kt KeyType) DerivationSupported() bool {
switch kt { switch kt {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_ED25519: case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_ED25519:
return true return true
} }
return false return false
@ -131,6 +132,8 @@ func (kt KeyType) DerivationSupported() bool {
func (kt KeyType) String() string { func (kt KeyType) String() string {
switch kt { switch kt {
case KeyType_AES128_GCM96:
return "aes128-gcm96"
case KeyType_AES256_GCM96: case KeyType_AES256_GCM96:
return "aes256-gcm96" return "aes256-gcm96"
case KeyType_ChaCha20_Poly1305: case KeyType_ChaCha20_Poly1305:
@ -729,7 +732,7 @@ func (p *Policy) DeriveKey(context []byte, ver, numBytes int) ([]byte, error) {
} }
switch p.Type { switch p.Type {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305: case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
n, err := derBytes.ReadFrom(limReader) n, err := derBytes.ReadFrom(limReader)
if err != nil { if err != nil {
return nil, errutil.InternalError{Err: fmt.Sprintf("error reading returned derived bytes: %v", err)} return nil, errutil.InternalError{Err: fmt.Sprintf("error reading returned derived bytes: %v", err)}
@ -800,40 +803,45 @@ func (p *Policy) Encrypt(ver int, context, nonce []byte, value string) (string,
var ciphertext []byte var ciphertext []byte
switch p.Type { switch p.Type {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305: case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
hmacKey := context hmacKey := context
var aead cipher.AEAD var aead cipher.AEAD
var encKey []byte var encKey []byte
var deriveHMAC bool var deriveHMAC bool
numBytes := 32 encBytes := 32
hmacBytes := 0
if p.convergentVersion(ver) > 2 { if p.convergentVersion(ver) > 2 {
deriveHMAC = true deriveHMAC = true
numBytes = 64 hmacBytes = 32
} }
key, err := p.DeriveKey(context, ver, numBytes) if p.Type == KeyType_AES128_GCM96 {
encBytes = 16
}
key, err := p.DeriveKey(context, ver, encBytes+hmacBytes)
if err != nil { if err != nil {
return "", err return "", err
} }
if len(key) < numBytes { if len(key) < encBytes+hmacBytes {
return "", errutil.InternalError{Err: "could not derive key, length too small"} return "", errutil.InternalError{Err: "could not derive key, length too small"}
} }
encKey = key[:32] encKey = key[:encBytes]
if len(encKey) != 32 { if len(encKey) != encBytes {
return "", errutil.InternalError{Err: "could not derive enc key, length not correct"} return "", errutil.InternalError{Err: "could not derive enc key, length not correct"}
} }
if deriveHMAC { if deriveHMAC {
hmacKey = key[32:] hmacKey = key[encBytes:]
if len(hmacKey) != 32 { if len(hmacKey) != hmacBytes {
return "", errutil.InternalError{Err: "could not derive hmac key, length not correct"} return "", errutil.InternalError{Err: "could not derive hmac key, length not correct"}
} }
} }
switch p.Type { switch p.Type {
case KeyType_AES256_GCM96: case KeyType_AES128_GCM96, KeyType_AES256_GCM96:
// Setup the cipher // Setup the cipher
aesCipher, err := aes.NewCipher(encKey) aesCipher, err := aes.NewCipher(encKey)
if err != nil { if err != nil {
@ -964,20 +972,25 @@ func (p *Policy) Decrypt(context, nonce []byte, value string) (string, error) {
var plain []byte var plain []byte
switch p.Type { switch p.Type {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305: case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
var aead cipher.AEAD var aead cipher.AEAD
encKey, err := p.DeriveKey(context, ver, 32) numBytes := 32
if p.Type == KeyType_AES128_GCM96 {
numBytes = 16
}
encKey, err := p.DeriveKey(context, ver, numBytes)
if err != nil { if err != nil {
return "", err return "", err
} }
if len(encKey) != 32 { if len(encKey) != numBytes {
return "", errutil.InternalError{Err: "could not derive enc key, length not correct"} return "", errutil.InternalError{Err: "could not derive enc key, length not correct"}
} }
switch p.Type { switch p.Type {
case KeyType_AES256_GCM96: case KeyType_AES128_GCM96, KeyType_AES256_GCM96:
// Setup the cipher // Setup the cipher
aesCipher, err := aes.NewCipher(encKey) aesCipher, err := aes.NewCipher(encKey)
if err != nil { if err != nil {
@ -1399,9 +1412,13 @@ func (p *Policy) Rotate(ctx context.Context, storage logical.Storage) (retErr er
entry.HMACKey = hmacKey entry.HMACKey = hmacKey
switch p.Type { switch p.Type {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305: case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
// Generate a 256bit key // Default to 256 bit key
newKey, err := uuid.GenerateRandomBytes(32) numBytes := 32
if p.Type == KeyType_AES128_GCM96 {
numBytes = 16
}
newKey, err := uuid.GenerateRandomBytes(numBytes)
if err != nil { if err != nil {
return err return err
} }