diff --git a/builtin/logical/transit/path_backup_test.go b/builtin/logical/transit/path_backup_test.go index 89c5c3db59..d8a54d70fc 100644 --- a/builtin/logical/transit/path_backup_test.go +++ b/builtin/logical/transit/path_backup_test.go @@ -36,6 +36,7 @@ func TestTransit_BackupRestore(t *testing.T) { testBackupRestore(t, "rsa-2048", "hmac-verify") testBackupRestore(t, "rsa-3072", "hmac-verify") testBackupRestore(t, "rsa-4096", "hmac-verify") + testBackupRestore(t, "hmac", "hmac-verify") } func testBackupRestore(t *testing.T, keyType, feature string) { @@ -54,6 +55,9 @@ func testBackupRestore(t *testing.T, keyType, feature string) { "exportable": true, }, } + if keyType == "hmac" { + keyReq.Data["key_size"] = 32 + } resp, err = b.HandleRequest(context.Background(), keyReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("resp: %#v\nerr: %v", resp, err) diff --git a/builtin/logical/transit/path_export.go b/builtin/logical/transit/path_export.go index 3b0d97e15e..61bb5e595c 100644 --- a/builtin/logical/transit/path_export.go +++ b/builtin/logical/transit/path_export.go @@ -151,7 +151,11 @@ func getExportKey(policy *keysutil.Policy, key *keysutil.KeyEntry, exportType st switch exportType { case exportTypeHMACKey: - return strings.TrimSpace(base64.StdEncoding.EncodeToString(key.HMACKey)), nil + src := key.HMACKey + if policy.Type == keysutil.KeyType_HMAC { + src = key.Key + } + return strings.TrimSpace(base64.StdEncoding.EncodeToString(src)), nil case exportTypeEncryptionKey: switch policy.Type { diff --git a/builtin/logical/transit/path_export_test.go b/builtin/logical/transit/path_export_test.go index 6d44894e64..b44a4e7e0f 100644 --- a/builtin/logical/transit/path_export_test.go +++ b/builtin/logical/transit/path_export_test.go @@ -25,6 +25,7 @@ func TestTransit_Export_KeyVersion_ExportsCorrectVersion(t *testing.T) { verifyExportsCorrectVersion(t, "hmac-key", "ecdsa-p384") verifyExportsCorrectVersion(t, "hmac-key", "ecdsa-p521") verifyExportsCorrectVersion(t, "hmac-key", "ed25519") + verifyExportsCorrectVersion(t, "hmac-key", "hmac") } func verifyExportsCorrectVersion(t *testing.T, exportType, keyType string) { @@ -40,6 +41,9 @@ func verifyExportsCorrectVersion(t *testing.T, exportType, keyType string) { "exportable": true, "type": keyType, } + if keyType == "hmac" { + req.Data["key_size"] = 32 + } _, err := b.HandleRequest(context.Background(), req) if err != nil { t.Fatal(err) diff --git a/changelog/20864.txt b/changelog/20864.txt new file mode 100644 index 0000000000..7193c6b81f --- /dev/null +++ b/changelog/20864.txt @@ -0,0 +1,5 @@ +```release-note:bug +secrets/transit: Fix export of HMAC-only key, correctly exporting the key used for sign operations. For consumers of the previously incorrect key, use the plaintext export to retrieve these incorrect keys and import them as new versions. +secrets/transit: Fix bug related to shorter dedicated HMAC key sizing. +sdk/helper/keysutil: New HMAC type policies will have HMACKey equal to Key and be copied over on import. +``` diff --git a/sdk/helper/keysutil/policy.go b/sdk/helper/keysutil/policy.go index 4d63f0dc8f..361e21fa21 100644 --- a/sdk/helper/keysutil/policy.go +++ b/sdk/helper/keysutil/policy.go @@ -731,6 +731,10 @@ func (p *Policy) Upgrade(ctx context.Context, storage logical.Storage, randReade entry.HMACKey = hmacKey p.Keys[strconv.Itoa(p.LatestVersion)] = entry persistNeeded = true + + if p.Type == KeyType_HMAC { + entry.HMACKey = entry.Key + } } if persistNeeded { @@ -1417,6 +1421,7 @@ func (p *Policy) Import(ctx context.Context, storage logical.Storage, key []byte entry.Key = key if p.Type == KeyType_HMAC { p.KeySize = len(key) + entry.HMACKey = key } } else { parsedPrivateKey, err := x509.ParsePKCS8PrivateKey(key) @@ -1574,7 +1579,7 @@ func (p *Policy) RotateInMemory(randReader io.Reader) (retErr error) { if p.Type == KeyType_AES128_GCM96 { numBytes = 16 } else if p.Type == KeyType_HMAC { - numBytes := p.KeySize + numBytes = p.KeySize if numBytes < HmacMinKeySize || numBytes > HmacMaxKeySize { return fmt.Errorf("invalid key size for HMAC key, must be between %d and %d bytes", HmacMinKeySize, HmacMaxKeySize) } @@ -1585,6 +1590,11 @@ func (p *Policy) RotateInMemory(randReader io.Reader) (retErr error) { } entry.Key = newKey + if p.Type == KeyType_HMAC { + // To avoid causing problems, ensure HMACKey = Key. + entry.HMACKey = newKey + } + case KeyType_ECDSA_P256, KeyType_ECDSA_P384, KeyType_ECDSA_P521: var curve elliptic.Curve switch p.Type {