vault-24597: add key types and key creation for CMAC (#25967)

* add key types for cmac for transit key creation

* add test for key creation

* fix test logic and add cases

* fix logic for hmac

* add go doc

* fix key size and add check for HMAC key
This commit is contained in:
Rachel Culpepper 2024-04-19 09:39:59 -05:00 committed by GitHub
parent 244b4998a0
commit 9ebcbf6a0c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 135 additions and 6 deletions

View File

@ -222,6 +222,10 @@ func (b *backend) pathPolicyWrite(ctx context.Context, req *logical.Request, d *
polReq.KeyType = keysutil.KeyType_HMAC
case "managed_key":
polReq.KeyType = keysutil.KeyType_MANAGED_KEY
case "aes128-cmac":
polReq.KeyType = keysutil.KeyType_AES128_CMAC
case "aes256-cmac":
polReq.KeyType = keysutil.KeyType_AES256_CMAC
default:
return logical.ErrorResponse(fmt.Sprintf("unknown key type %v", keyType)), logical.ErrInvalidRequest
}

View File

@ -195,3 +195,113 @@ func TestTransit_CreateKeyWithAutorotation(t *testing.T) {
})
}
}
// TestTransit_CreateKey validates transit key creation functionality
func TestTransit_CreateKey(t *testing.T) {
testCases := map[string]struct {
creationParams map[string]interface{}
shouldError bool
}{
"AES-128": {
creationParams: map[string]interface{}{"type": "aes128-gcm96"},
shouldError: false,
},
"AES-256": {
creationParams: map[string]interface{}{"type": "aes256-gcm96"},
shouldError: false,
},
"CHACHA20": {
creationParams: map[string]interface{}{"type": "chacha20-poly1305"},
shouldError: false,
},
"ECDSA-P256": {
creationParams: map[string]interface{}{"type": "ecdsa-p256"},
shouldError: false,
},
"ECDSA-P384": {
creationParams: map[string]interface{}{"type": "ecdsa-p384"},
shouldError: false,
},
"ECDSA-P521": {
creationParams: map[string]interface{}{"type": "ecdsa-p521"},
shouldError: false,
},
"RSA_2048": {
creationParams: map[string]interface{}{"type": "rsa-2048"},
shouldError: false,
},
"RSA_3072": {
creationParams: map[string]interface{}{"type": "rsa-3072"},
shouldError: false,
},
"RSA_4096": {
creationParams: map[string]interface{}{"type": "rsa-4096"},
shouldError: false,
},
"HMAC": {
creationParams: map[string]interface{}{"type": "hmac", "key_size": 128},
shouldError: false,
},
"AES-128 CMAC": {
creationParams: map[string]interface{}{"type": "aes128-cmac"},
shouldError: false,
},
"AES-256 CMAC": {
creationParams: map[string]interface{}{"type": "aes256-cmac"},
shouldError: false,
},
"bad key type": {
creationParams: map[string]interface{}{"type": "fake-key-type"},
shouldError: true,
},
}
coreConfig := &vault.CoreConfig{
LogicalBackends: map[string]logical.Factory{
"transit": transit.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
err := client.Sys().Mount("transit", &api.MountInput{
Type: "transit",
})
if err != nil {
t.Fatal(err)
}
for name, tt := range testCases {
t.Run(name, func(t *testing.T) {
keyName, err := uuid.GenerateUUID()
if err != nil {
t.Fatalf("error generating key name: %s", err)
}
resp, err := client.Logical().Write(fmt.Sprintf("transit/keys/%s", keyName), tt.creationParams)
if err != nil && !tt.shouldError {
t.Fatalf("unexpected error creating key: %s", err)
}
if err == nil && tt.shouldError {
t.Fatal("expected error but got nil")
}
if err == nil {
keyType, ok := resp.Data["type"]
if !ok {
t.Fatal("missing key type in response")
}
if keyType != tt.creationParams["type"] {
t.Fatalf("incorrect key type: expected %s, got %s", tt.creationParams["type"], keyType)
}
}
})
}
}

View File

@ -397,6 +397,12 @@ func (lm *LockManager) GetPolicy(ctx context.Context, req PolicyRequest, rand io
return nil, false, fmt.Errorf("key derivation and convergent encryption not supported for keys of type %v", req.KeyType)
}
case KeyType_AES128_CMAC, KeyType_AES256_CMAC:
if req.Derived || req.Convergent {
cleanup()
return nil, false, fmt.Errorf("key derivation and convergent encryption not supported for keys of type %v", req.KeyType)
}
default:
cleanup()
return nil, false, fmt.Errorf("unsupported key type %v", req.KeyType)

View File

@ -68,6 +68,8 @@ const (
KeyType_RSA3072
KeyType_MANAGED_KEY
KeyType_HMAC
KeyType_AES128_CMAC
KeyType_AES256_CMAC
)
const (
@ -202,6 +204,10 @@ func (kt KeyType) String() string {
return "hmac"
case KeyType_MANAGED_KEY:
return "managed_key"
case KeyType_AES128_CMAC:
return "aes128-cmac"
case KeyType_AES256_CMAC:
return "aes256-cmac"
}
return "[unknown]"
@ -1611,17 +1617,20 @@ func (p *Policy) RotateInMemory(randReader io.Reader) (retErr error) {
DeprecatedCreationTime: now.Unix(),
}
if p.Type != KeyType_AES128_CMAC && p.Type != KeyType_AES256_CMAC && p.Type != KeyType_HMAC {
hmacKey, err := uuid.GenerateRandomBytesWithReader(32, randReader)
if err != nil {
return err
}
entry.HMACKey = hmacKey
}
var err error
switch p.Type {
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_HMAC:
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_HMAC, KeyType_AES128_CMAC, KeyType_AES256_CMAC:
// Default to 256 bit key
numBytes := 32
if p.Type == KeyType_AES128_GCM96 {
if p.Type == KeyType_AES128_GCM96 || p.Type == KeyType_AES128_CMAC {
numBytes = 16
} else if p.Type == KeyType_HMAC {
numBytes = p.KeySize