mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-30 18:17:55 +00:00
Add support for a dedicated HMAC type in Transit. (#16668)
* Get import correct * limits, docs * changelog * unit tests * And fix import for hmac unit test * typo * Update website/content/api-docs/secret/transit.mdx Co-authored-by: Matt Schultz <975680+schultz-is@users.noreply.github.com> * Update builtin/logical/transit/path_keys.go Co-authored-by: Matt Schultz <975680+schultz-is@users.noreply.github.com> * Validate key sizes a bit more carefully * Update sdk/helper/keysutil/policy.go Co-authored-by: Matt Schultz <975680+schultz-is@users.noreply.github.com> Co-authored-by: Matt Schultz <975680+schultz-is@users.noreply.github.com>
This commit is contained in:
@@ -14,11 +14,25 @@ import (
|
|||||||
func TestTransit_HMAC(t *testing.T) {
|
func TestTransit_HMAC(t *testing.T) {
|
||||||
b, storage := createBackendWithSysView(t)
|
b, storage := createBackendWithSysView(t)
|
||||||
|
|
||||||
// First create a key
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
typ string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "foo",
|
||||||
|
typ: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dedicated",
|
||||||
|
typ: "hmac",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
req := &logical.Request{
|
req := &logical.Request{
|
||||||
Storage: storage,
|
Storage: storage,
|
||||||
Operation: logical.UpdateOperation,
|
Operation: logical.UpdateOperation,
|
||||||
Path: "keys/foo",
|
Path: "keys/" + c.name,
|
||||||
}
|
}
|
||||||
_, err := b.HandleRequest(context.Background(), req)
|
_, err := b.HandleRequest(context.Background(), req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -28,7 +42,7 @@ func TestTransit_HMAC(t *testing.T) {
|
|||||||
// Now, change the key value to something we control
|
// Now, change the key value to something we control
|
||||||
p, _, err := b.GetPolicy(context.Background(), keysutil.PolicyRequest{
|
p, _, err := b.GetPolicy(context.Background(), keysutil.PolicyRequest{
|
||||||
Storage: storage,
|
Storage: storage,
|
||||||
Name: "foo",
|
Name: c.name,
|
||||||
}, b.GetRandomReader())
|
}, b.GetRandomReader())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -37,12 +51,13 @@ func TestTransit_HMAC(t *testing.T) {
|
|||||||
latestVersion := strconv.Itoa(p.LatestVersion)
|
latestVersion := strconv.Itoa(p.LatestVersion)
|
||||||
keyEntry := p.Keys[latestVersion]
|
keyEntry := p.Keys[latestVersion]
|
||||||
keyEntry.HMACKey = []byte("01234567890123456789012345678901")
|
keyEntry.HMACKey = []byte("01234567890123456789012345678901")
|
||||||
|
keyEntry.Key = []byte("01234567890123456789012345678901")
|
||||||
p.Keys[latestVersion] = keyEntry
|
p.Keys[latestVersion] = keyEntry
|
||||||
if err = p.Persist(context.Background(), storage); err != nil {
|
if err = p.Persist(context.Background(), storage); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Path = "hmac/foo"
|
req.Path = "hmac/" + c.name
|
||||||
req.Data = map[string]interface{}{
|
req.Data = map[string]interface{}{
|
||||||
"input": "dGhlIHF1aWNrIGJyb3duIGZveA==",
|
"input": "dGhlIHF1aWNrIGJyb3duIGZveA==",
|
||||||
}
|
}
|
||||||
@@ -96,11 +111,11 @@ func TestTransit_HMAC(t *testing.T) {
|
|||||||
doRequest(req, false, "vault:v1:UcBvm5VskkukzZHlPgm3p5P/Yr/PV6xpuOGZISya3A4=")
|
doRequest(req, false, "vault:v1:UcBvm5VskkukzZHlPgm3p5P/Yr/PV6xpuOGZISya3A4=")
|
||||||
|
|
||||||
// Test algorithm selection in the path
|
// Test algorithm selection in the path
|
||||||
req.Path = "hmac/foo/sha2-224"
|
req.Path = "hmac/" + c.name + "/sha2-224"
|
||||||
doRequest(req, false, "vault:v1:3p+ZWVquYDvu2dSTCa65Y3fgoMfIAc6fNaBbtg==")
|
doRequest(req, false, "vault:v1:3p+ZWVquYDvu2dSTCa65Y3fgoMfIAc6fNaBbtg==")
|
||||||
|
|
||||||
// Reset and test algorithm selection in the data
|
// Reset and test algorithm selection in the data
|
||||||
req.Path = "hmac/foo"
|
req.Path = "hmac/" + c.name
|
||||||
req.Data["algorithm"] = "sha2-224"
|
req.Data["algorithm"] = "sha2-224"
|
||||||
doRequest(req, false, "vault:v1:3p+ZWVquYDvu2dSTCa65Y3fgoMfIAc6fNaBbtg==")
|
doRequest(req, false, "vault:v1:3p+ZWVquYDvu2dSTCa65Y3fgoMfIAc6fNaBbtg==")
|
||||||
|
|
||||||
@@ -115,7 +130,7 @@ func TestTransit_HMAC(t *testing.T) {
|
|||||||
doRequest(req, false, "vault:v1:PSXLXvkvKF4CpU65e2bK1tGBZQpcpCEM32fq2iUoiTyQQCfBcGJJItQ+60tMwWXAPQrC290AzTrNJucGrr4GFA==")
|
doRequest(req, false, "vault:v1:PSXLXvkvKF4CpU65e2bK1tGBZQpcpCEM32fq2iUoiTyQQCfBcGJJItQ+60tMwWXAPQrC290AzTrNJucGrr4GFA==")
|
||||||
|
|
||||||
// Test SHA3
|
// Test SHA3
|
||||||
req.Path = "hmac/foo"
|
req.Path = "hmac/" + c.name
|
||||||
req.Data["algorithm"] = "sha3-224"
|
req.Data["algorithm"] = "sha3-224"
|
||||||
doRequest(req, false, "vault:v1:TGipmKH8LR/BkMolYpDYy0BJCIhTtGPDhV2VkQ==")
|
doRequest(req, false, "vault:v1:TGipmKH8LR/BkMolYpDYy0BJCIhTtGPDhV2VkQ==")
|
||||||
|
|
||||||
@@ -156,7 +171,7 @@ func TestTransit_HMAC(t *testing.T) {
|
|||||||
doRequest(req, false, "vault:v2:Dt+mO/B93kuWUbGMMobwUNX5Wodr6dL3JH4DMfpQ0kw=")
|
doRequest(req, false, "vault:v2:Dt+mO/B93kuWUbGMMobwUNX5Wodr6dL3JH4DMfpQ0kw=")
|
||||||
|
|
||||||
// Verify a previous version
|
// Verify a previous version
|
||||||
req.Path = "verify/foo"
|
req.Path = "verify/" + c.name
|
||||||
|
|
||||||
req.Data["hmac"] = "vault:v1:UcBvm5VskkukzZHlPgm3p5P/Yr/PV6xpuOGZISya3A4="
|
req.Data["hmac"] = "vault:v1:UcBvm5VskkukzZHlPgm3p5P/Yr/PV6xpuOGZISya3A4="
|
||||||
resp, err := b.HandleRequest(context.Background(), req)
|
resp, err := b.HandleRequest(context.Background(), req)
|
||||||
@@ -197,6 +212,7 @@ func TestTransit_HMAC(t *testing.T) {
|
|||||||
if err != logical.ErrInvalidRequest {
|
if err != logical.ErrInvalidRequest {
|
||||||
t.Fatalf("expected invalid request error, got %v", err)
|
t.Fatalf("expected invalid request error, got %v", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTransit_batchHMAC(t *testing.T) {
|
func TestTransit_batchHMAC(t *testing.T) {
|
||||||
|
|||||||
@@ -177,6 +177,8 @@ func (b *backend) pathImportWrite(ctx context.Context, req *logical.Request, d *
|
|||||||
polReq.KeyType = keysutil.KeyType_RSA3072
|
polReq.KeyType = keysutil.KeyType_RSA3072
|
||||||
case "rsa-4096":
|
case "rsa-4096":
|
||||||
polReq.KeyType = keysutil.KeyType_RSA4096
|
polReq.KeyType = keysutil.KeyType_RSA4096
|
||||||
|
case "hmac":
|
||||||
|
polReq.KeyType = keysutil.KeyType_HMAC
|
||||||
default:
|
default:
|
||||||
return logical.ErrorResponse(fmt.Sprintf("unknown key type: %v", keyType)), logical.ErrInvalidRequest
|
return logical.ErrorResponse(fmt.Sprintf("unknown key type: %v", keyType)), logical.ErrInvalidRequest
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ var keyTypes = []string{
|
|||||||
"rsa-2048",
|
"rsa-2048",
|
||||||
"rsa-3072",
|
"rsa-3072",
|
||||||
"rsa-4096",
|
"rsa-4096",
|
||||||
|
"hmac",
|
||||||
}
|
}
|
||||||
|
|
||||||
var hashFns = []string{
|
var hashFns = []string{
|
||||||
@@ -543,7 +544,7 @@ func wrapTargetKeyForImport(t *testing.T, wrappingKey *rsa.PublicKey, targetKey
|
|||||||
var ok bool
|
var ok bool
|
||||||
var err error
|
var err error
|
||||||
switch targetKeyType {
|
switch targetKeyType {
|
||||||
case "aes128-gcm96", "aes256-gcm96", "chacha20-poly1305":
|
case "aes128-gcm96", "aes256-gcm96", "chacha20-poly1305", "hmac":
|
||||||
preppedTargetKey, ok = targetKey.([]byte)
|
preppedTargetKey, ok = targetKey.([]byte)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatal("failed to wrap target key for import: symmetric key not provided in byte format")
|
t.Fatal("failed to wrap target key for import: symmetric key not provided in byte format")
|
||||||
@@ -600,7 +601,7 @@ func generateKey(keyType string) (interface{}, error) {
|
|||||||
switch keyType {
|
switch keyType {
|
||||||
case "aes128-gcm96":
|
case "aes128-gcm96":
|
||||||
return uuid.GenerateRandomBytes(16)
|
return uuid.GenerateRandomBytes(16)
|
||||||
case "aes256-gcm96":
|
case "aes256-gcm96", "hmac":
|
||||||
return uuid.GenerateRandomBytes(32)
|
return uuid.GenerateRandomBytes(32)
|
||||||
case "chacha20-poly1305":
|
case "chacha20-poly1305":
|
||||||
return uuid.GenerateRandomBytes(32)
|
return uuid.GenerateRandomBytes(32)
|
||||||
|
|||||||
@@ -103,6 +103,11 @@ being automatically rotated. A value of 0
|
|||||||
(default) disables automatic rotation for the
|
(default) disables automatic rotation for the
|
||||||
key.`,
|
key.`,
|
||||||
},
|
},
|
||||||
|
"key_size": {
|
||||||
|
Type: framework.TypeInt,
|
||||||
|
Default: 0,
|
||||||
|
Description: fmt.Sprintf("The key size in bytes for the algorithm. Only applies to HMAC and must be no fewer than %d bytes and no more than %d", keysutil.HmacMinKeySize, keysutil.HmacMaxKeySize),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||||
@@ -130,6 +135,7 @@ func (b *backend) pathPolicyWrite(ctx context.Context, req *logical.Request, d *
|
|||||||
derived := d.Get("derived").(bool)
|
derived := d.Get("derived").(bool)
|
||||||
convergent := d.Get("convergent_encryption").(bool)
|
convergent := d.Get("convergent_encryption").(bool)
|
||||||
keyType := d.Get("type").(string)
|
keyType := d.Get("type").(string)
|
||||||
|
keySize := d.Get("key_size").(int)
|
||||||
exportable := d.Get("exportable").(bool)
|
exportable := d.Get("exportable").(bool)
|
||||||
allowPlaintextBackup := d.Get("allow_plaintext_backup").(bool)
|
allowPlaintextBackup := d.Get("allow_plaintext_backup").(bool)
|
||||||
autoRotatePeriod := time.Second * time.Duration(d.Get("auto_rotate_period").(int))
|
autoRotatePeriod := time.Second * time.Duration(d.Get("auto_rotate_period").(int))
|
||||||
@@ -152,6 +158,7 @@ func (b *backend) pathPolicyWrite(ctx context.Context, req *logical.Request, d *
|
|||||||
AllowPlaintextBackup: allowPlaintextBackup,
|
AllowPlaintextBackup: allowPlaintextBackup,
|
||||||
AutoRotatePeriod: autoRotatePeriod,
|
AutoRotatePeriod: autoRotatePeriod,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch keyType {
|
switch keyType {
|
||||||
case "aes128-gcm96":
|
case "aes128-gcm96":
|
||||||
polReq.KeyType = keysutil.KeyType_AES128_GCM96
|
polReq.KeyType = keysutil.KeyType_AES128_GCM96
|
||||||
@@ -173,9 +180,20 @@ func (b *backend) pathPolicyWrite(ctx context.Context, req *logical.Request, d *
|
|||||||
polReq.KeyType = keysutil.KeyType_RSA3072
|
polReq.KeyType = keysutil.KeyType_RSA3072
|
||||||
case "rsa-4096":
|
case "rsa-4096":
|
||||||
polReq.KeyType = keysutil.KeyType_RSA4096
|
polReq.KeyType = keysutil.KeyType_RSA4096
|
||||||
|
case "hmac":
|
||||||
|
polReq.KeyType = keysutil.KeyType_HMAC
|
||||||
default:
|
default:
|
||||||
return logical.ErrorResponse(fmt.Sprintf("unknown key type %v", keyType)), logical.ErrInvalidRequest
|
return logical.ErrorResponse(fmt.Sprintf("unknown key type %v", keyType)), logical.ErrInvalidRequest
|
||||||
}
|
}
|
||||||
|
if keySize != 0 {
|
||||||
|
if polReq.KeyType != keysutil.KeyType_HMAC {
|
||||||
|
return logical.ErrorResponse(fmt.Sprintf("key_size is not valid for algorithm %v", polReq.KeyType)), logical.ErrInvalidRequest
|
||||||
|
}
|
||||||
|
if keySize < keysutil.HmacMinKeySize || keySize > keysutil.HmacMaxKeySize {
|
||||||
|
return logical.ErrorResponse(fmt.Sprintf("invalid key_size %d", keySize)), logical.ErrInvalidRequest
|
||||||
|
}
|
||||||
|
polReq.KeySize = keySize
|
||||||
|
}
|
||||||
|
|
||||||
p, upserted, err := b.GetPolicy(ctx, polReq, b.GetRandomReader())
|
p, upserted, err := b.GetPolicy(ctx, polReq, b.GetRandomReader())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -242,6 +260,9 @@ func (b *backend) pathPolicyRead(ctx context.Context, req *logical.Request, d *f
|
|||||||
"imported_key": p.Imported,
|
"imported_key": p.Imported,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if p.KeySize != 0 {
|
||||||
|
resp.Data["key_size"] = p.KeySize
|
||||||
|
}
|
||||||
|
|
||||||
if p.Imported {
|
if p.Imported {
|
||||||
resp.Data["imported_key_allow_rotation"] = p.AllowImportedKeyRotation
|
resp.Data["imported_key_allow_rotation"] = p.AllowImportedKeyRotation
|
||||||
|
|||||||
3
changelog/16668.txt
Normal file
3
changelog/16668.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
```release-note:improvement
|
||||||
|
secrets/transit: Add a dedicated HMAC key type, which can be used with key import.
|
||||||
|
```
|
||||||
@@ -36,6 +36,9 @@ type PolicyRequest struct {
|
|||||||
// The key type
|
// The key type
|
||||||
KeyType KeyType
|
KeyType KeyType
|
||||||
|
|
||||||
|
// The key size for variable key size algorithms
|
||||||
|
KeySize int
|
||||||
|
|
||||||
// Whether it should be derived
|
// Whether it should be derived
|
||||||
Derived bool
|
Derived bool
|
||||||
|
|
||||||
@@ -373,6 +376,11 @@ func (lm *LockManager) GetPolicy(ctx context.Context, req PolicyRequest, rand io
|
|||||||
cleanup()
|
cleanup()
|
||||||
return nil, false, fmt.Errorf("key derivation and convergent encryption not supported for keys of type %v", req.KeyType)
|
return nil, false, fmt.Errorf("key derivation and convergent encryption not supported for keys of type %v", req.KeyType)
|
||||||
}
|
}
|
||||||
|
case KeyType_HMAC:
|
||||||
|
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:
|
default:
|
||||||
cleanup()
|
cleanup()
|
||||||
@@ -387,6 +395,7 @@ func (lm *LockManager) GetPolicy(ctx context.Context, req PolicyRequest, rand io
|
|||||||
Exportable: req.Exportable,
|
Exportable: req.Exportable,
|
||||||
AllowPlaintextBackup: req.AllowPlaintextBackup,
|
AllowPlaintextBackup: req.AllowPlaintextBackup,
|
||||||
AutoRotatePeriod: req.AutoRotatePeriod,
|
AutoRotatePeriod: req.AutoRotatePeriod,
|
||||||
|
KeySize: req.KeySize,
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Derived {
|
if req.Derived {
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ import (
|
|||||||
const (
|
const (
|
||||||
Kdf_hmac_sha256_counter = iota // built-in helper
|
Kdf_hmac_sha256_counter = iota // built-in helper
|
||||||
Kdf_hkdf_sha256 // golang.org/x/crypto/hkdf
|
Kdf_hkdf_sha256 // golang.org/x/crypto/hkdf
|
||||||
|
|
||||||
|
HmacMinKeySize = 256 / 8
|
||||||
|
HmacMaxKeySize = 4096 / 8
|
||||||
)
|
)
|
||||||
|
|
||||||
// Or this one...we need the default of zero to be the original AES256-GCM96
|
// Or this one...we need the default of zero to be the original AES256-GCM96
|
||||||
@@ -59,6 +62,7 @@ const (
|
|||||||
KeyType_ECDSA_P521
|
KeyType_ECDSA_P521
|
||||||
KeyType_AES128_GCM96
|
KeyType_AES128_GCM96
|
||||||
KeyType_RSA3072
|
KeyType_RSA3072
|
||||||
|
KeyType_HMAC
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -160,6 +164,8 @@ func (kt KeyType) String() string {
|
|||||||
return "rsa-3072"
|
return "rsa-3072"
|
||||||
case KeyType_RSA4096:
|
case KeyType_RSA4096:
|
||||||
return "rsa-4096"
|
return "rsa-4096"
|
||||||
|
case KeyType_HMAC:
|
||||||
|
return "hmac"
|
||||||
}
|
}
|
||||||
|
|
||||||
return "[unknown]"
|
return "[unknown]"
|
||||||
@@ -320,6 +326,7 @@ type Policy struct {
|
|||||||
|
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Key []byte `json:"key,omitempty"` // DEPRECATED
|
Key []byte `json:"key,omitempty"` // DEPRECATED
|
||||||
|
KeySize int `json:"key_size,omitempty"` // For algorithms with variable key sizes
|
||||||
Keys keyEntryMap `json:"keys"`
|
Keys keyEntryMap `json:"keys"`
|
||||||
|
|
||||||
// Derived keys MUST provide a context and the master underlying key is
|
// Derived keys MUST provide a context and the master underlying key is
|
||||||
@@ -1025,10 +1032,13 @@ func (p *Policy) HMACKey(version int) ([]byte, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.Type == KeyType_HMAC {
|
||||||
|
return keyEntry.Key, nil
|
||||||
|
}
|
||||||
if keyEntry.HMACKey == nil {
|
if keyEntry.HMACKey == nil {
|
||||||
return nil, fmt.Errorf("no HMAC key exists for that key version")
|
return nil, fmt.Errorf("no HMAC key exists for that key version")
|
||||||
}
|
}
|
||||||
|
|
||||||
return keyEntry.HMACKey, nil
|
return keyEntry.HMACKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1386,19 +1396,25 @@ func (p *Policy) Import(ctx context.Context, storage logical.Storage, key []byte
|
|||||||
DeprecatedCreationTime: now.Unix(),
|
DeprecatedCreationTime: now.Unix(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.Type != KeyType_HMAC {
|
||||||
hmacKey, err := uuid.GenerateRandomBytesWithReader(32, randReader)
|
hmacKey, err := uuid.GenerateRandomBytesWithReader(32, randReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
entry.HMACKey = hmacKey
|
entry.HMACKey = hmacKey
|
||||||
|
}
|
||||||
|
|
||||||
if (p.Type == KeyType_AES128_GCM96 && len(key) != 16) ||
|
if (p.Type == KeyType_AES128_GCM96 && len(key) != 16) ||
|
||||||
((p.Type == KeyType_AES256_GCM96 || p.Type == KeyType_ChaCha20_Poly1305) && len(key) != 32) {
|
((p.Type == KeyType_AES256_GCM96 || p.Type == KeyType_ChaCha20_Poly1305) && len(key) != 32) ||
|
||||||
|
(p.Type == KeyType_HMAC && (len(key) < HmacMinKeySize || len(key) > HmacMaxKeySize)) {
|
||||||
return fmt.Errorf("invalid key size %d bytes for key type %s", len(key), p.Type)
|
return fmt.Errorf("invalid key size %d bytes for key type %s", len(key), p.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Type == KeyType_AES128_GCM96 || p.Type == KeyType_AES256_GCM96 || p.Type == KeyType_ChaCha20_Poly1305 {
|
if p.Type == KeyType_AES128_GCM96 || p.Type == KeyType_AES256_GCM96 || p.Type == KeyType_ChaCha20_Poly1305 || p.Type == KeyType_HMAC {
|
||||||
entry.Key = key
|
entry.Key = key
|
||||||
|
if p.Type == KeyType_HMAC {
|
||||||
|
p.KeySize = len(key)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
parsedPrivateKey, err := x509.ParsePKCS8PrivateKey(key)
|
parsedPrivateKey, err := x509.ParsePKCS8PrivateKey(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1549,11 +1565,16 @@ func (p *Policy) RotateInMemory(randReader io.Reader) (retErr error) {
|
|||||||
entry.HMACKey = hmacKey
|
entry.HMACKey = hmacKey
|
||||||
|
|
||||||
switch p.Type {
|
switch p.Type {
|
||||||
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
|
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_HMAC:
|
||||||
// Default to 256 bit key
|
// Default to 256 bit key
|
||||||
numBytes := 32
|
numBytes := 32
|
||||||
if p.Type == KeyType_AES128_GCM96 {
|
if p.Type == KeyType_AES128_GCM96 {
|
||||||
numBytes = 16
|
numBytes = 16
|
||||||
|
} else if p.Type == KeyType_HMAC {
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
newKey, err := uuid.GenerateRandomBytesWithReader(numBytes, randReader)
|
newKey, err := uuid.GenerateRandomBytesWithReader(numBytes, randReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -63,10 +63,19 @@ values set here cannot be changed after key creation.
|
|||||||
- `rsa-2048` - RSA with bit size of 2048 (asymmetric)
|
- `rsa-2048` - RSA with bit size of 2048 (asymmetric)
|
||||||
- `rsa-3072` - RSA with bit size of 3072 (asymmetric)
|
- `rsa-3072` - RSA with bit size of 3072 (asymmetric)
|
||||||
- `rsa-4096` - RSA with bit size of 4096 (asymmetric)
|
- `rsa-4096` - RSA with bit size of 4096 (asymmetric)
|
||||||
|
- `hmac` - HMAC (HMAC generation, verification)
|
||||||
|
|
||||||
~> **Note**: In FIPS 140-2 mode, the following algorithms are not certified
|
~> **Note**: In FIPS 140-2 mode, the following algorithms are not certified
|
||||||
and thus should not be used: `chacha20-poly1305` and `ed25519`.
|
and thus should not be used: `chacha20-poly1305` and `ed25519`.
|
||||||
|
|
||||||
|
~> **Note**: All key types support HMAC through the use of a second randomly
|
||||||
|
generated key created key creation time or rotation. The HMAC key type only
|
||||||
|
supports HMAC, and behaves identically to other algorithms with
|
||||||
|
respect to the HMAC operations but supports key import. By default,
|
||||||
|
the HMAC key type uses a 256-bit key.
|
||||||
|
- `key_size` `(int: "0", optional)` - The key size in bytes for algorithms
|
||||||
|
that allow variable key sizes. Currently only applicable to HMAC, where
|
||||||
|
it must be between 16 and 512 bytes.
|
||||||
- `auto_rotate_period` `(duration: "0", optional)` – The period at which
|
- `auto_rotate_period` `(duration: "0", optional)` – The period at which
|
||||||
this key should be rotated automatically. Setting this to "0" (the default)
|
this key should be rotated automatically. Setting this to "0" (the default)
|
||||||
will disable automatic key rotation. This value cannot be shorter than one
|
will disable automatic key rotation. This value cannot be shorter than one
|
||||||
@@ -431,6 +440,9 @@ ciphertext to be encrypted with the latest version of the key, use the `rewrap`
|
|||||||
endpoint. This is only supported with keys that support encryption and
|
endpoint. This is only supported with keys that support encryption and
|
||||||
decryption operations.
|
decryption operations.
|
||||||
|
|
||||||
|
For algorithms with a configurable key size, the rotated key will use the same
|
||||||
|
key size as the previous version.
|
||||||
|
|
||||||
~> **Note**: For imported keys, rotation is only supported if the
|
~> **Note**: For imported keys, rotation is only supported if the
|
||||||
`allow_rotation` field was set to `true` on import. Once an imported key is
|
`allow_rotation` field was set to `true` on import. Once an imported key is
|
||||||
rotated within Vault, it will not support further import operations.
|
rotated within Vault, it will not support further import operations.
|
||||||
|
|||||||
@@ -85,10 +85,17 @@ types also generate separate HMAC keys):
|
|||||||
signature verification
|
signature verification
|
||||||
- `rsa-4096`: 4096-bit RSA key; supports encryption, decryption, signing, and
|
- `rsa-4096`: 4096-bit RSA key; supports encryption, decryption, signing, and
|
||||||
signature verification
|
signature verification
|
||||||
|
- `hmac`: HMAC; supporting HMAC generation and verification.
|
||||||
|
|
||||||
~> **Note**: In FIPS 140-2 mode, the following algorithms are not certified
|
~> **Note**: In FIPS 140-2 mode, the following algorithms are not certified
|
||||||
and thus should not be used: `chacha20-poly1305` and `ed25519`.
|
and thus should not be used: `chacha20-poly1305` and `ed25519`.
|
||||||
|
|
||||||
|
~> **Note**: All key types support HMAC operations through the use of a second randomly
|
||||||
|
generated key created key creation time or rotation. The HMAC key type only
|
||||||
|
supports HMAC, and behaves identically to other algorithms with
|
||||||
|
respect to the HMAC operations but supports key import. By default,
|
||||||
|
the HMAC key type uses a 256-bit key.
|
||||||
|
|
||||||
## Convergent Encryption
|
## Convergent Encryption
|
||||||
|
|
||||||
Convergent encryption is a mode where the same set of plaintext+context always
|
Convergent encryption is a mode where the same set of plaintext+context always
|
||||||
|
|||||||
Reference in New Issue
Block a user