diff --git a/builtin/logical/pki/path_manage_keys.go b/builtin/logical/pki/path_manage_keys.go index cce0fde52b..2b062eaa0d 100644 --- a/builtin/logical/pki/path_manage_keys.go +++ b/builtin/logical/pki/path_manage_keys.go @@ -19,14 +19,22 @@ func pathGenerateKey(b *backend) *framework.Path { Description: "Optional name to be used for this key", }, keyTypeParam: { - Type: framework.TypeString, - Default: "rsa", - Description: `Type of the secret key to generate`, + Type: framework.TypeString, + Default: "rsa", + Description: `The type of key to use; defaults to RSA. "rsa" +"ec" and "ed25519" are the only valid values.`, + AllowedValues: []interface{}{"rsa", "ec", "ed25519"}, + DisplayAttrs: &framework.DisplayAttributes{ + Value: "rsa", + }, }, keyBitsParam: { - Type: framework.TypeInt, - Default: 2048, - Description: `Type of the secret key to generate`, + Type: framework.TypeInt, + Default: 0, + Description: `The number of bits to use. Allowed values are +0 (universal default); with rsa key_type: 2048 (default), 3072, or +4096; with ec key_type: 224, 256 (default), 384, or 521; ignored with +ed25519.`, }, "managed_key_name": { Type: framework.TypeString, @@ -83,6 +91,11 @@ func (b *backend) pathGenerateKeyHandler(ctx context.Context, req *logical.Reque keyType := data.Get(keyTypeParam).(string) keyBits := data.Get(keyBitsParam).(int) + keyBits, _, err := certutil.ValidateDefaultOrValueKeyTypeSignatureLength(keyType, keyBits, 0) + if err != nil { + return logical.ErrorResponse("Validation for key_type, key_bits failed: %s", err.Error()), nil + } + // Internal key generation, stored in storage keyBundle, err = certutil.CreateKeyBundle(keyType, keyBits, b.GetRandomReader()) if err != nil { diff --git a/builtin/logical/pki/path_manage_keys_test.go b/builtin/logical/pki/path_manage_keys_test.go new file mode 100644 index 0000000000..e4dfefa468 --- /dev/null +++ b/builtin/logical/pki/path_manage_keys_test.go @@ -0,0 +1,61 @@ +package pki + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" +) + +func TestPKI_PathManageKeys_GenerateKeys(t *testing.T) { + b, s := createBackendWithStorage(t) + + tests := []struct { + name string + keyType string + keyBits []int + wantLogicalErr bool + }{ + {"all-defaults", "", []int{0}, false}, + {"rsa", "rsa", []int{0, 2048, 3072, 4096}, false}, + {"ec", "ec", []int{0, 224, 256, 384, 521}, false}, + {"ed25519", "ed25519", []int{0}, false}, + {"error-rsa", "rsa", []int{-1, 343444}, true}, + {"error-ec", "ec", []int{-1, 3434324}, true}, + {"error-bad-type", "dskjfkdsfjdkf", []int{0}, true}, + } + for _, tt := range tests { + for _, keyBitParam := range tt.keyBits { + keyName := fmt.Sprintf("%s-%d", tt.name, keyBitParam) + t.Run(keyName, func(t *testing.T) { + data := make(map[string]interface{}) + if tt.keyType != "" { + data["key_type"] = tt.keyType + } + if keyBitParam != 0 { + data["key_bits"] = keyBitParam + } + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/generate/internal", + Storage: s, + Data: data, + MountPoint: "pki/", + }) + require.NoError(t, err, + "Failed generating key with values key_type:%s key_bits:%d key_name:%s", tt.keyType, keyBitParam, keyName) + require.NotNil(t, resp, + "Got nil response generating key with values key_type:%s key_bits:%d key_name:%s", tt.keyType, keyBitParam, keyName) + if tt.wantLogicalErr { + require.True(t, resp.IsError(), "expected logical error but the request passed:\n%#v", resp) + } else { + require.False(t, resp.IsError(), + "Got logical error response when not expecting one, "+ + "generating key with values key_type:%s key_bits:%d key_name:%s\n%s", tt.keyType, keyBitParam, keyName, resp.Error()) + } + }) + } + } +}