diff --git a/moto/kms/models.py b/moto/kms/models.py index 6c53dad06..a1971a05c 100644 --- a/moto/kms/models.py +++ b/moto/kms/models.py @@ -22,6 +22,7 @@ from .utils import ( generate_key_id, generate_master_key, generate_private_key, + KeySpec, ) @@ -302,6 +303,8 @@ class KmsBackend(BaseBackend): - The resource is set to "*" - The Action matches `describe_key` """ + if key_spec: + self.__ensure_valid_key_spec(key_spec) key = Key( policy, key_usage, @@ -615,6 +618,16 @@ class KmsBackend(BaseBackend): ) ) + def __ensure_valid_key_spec(self, key_spec: str) -> None: + if key_spec not in KeySpec.key_specs(): + raise ValidationException( + ( + "1 validation error detected: Value '{key_spec}' at 'KeySpec' failed " + "to satisfy constraint: Member must satisfy enum value set: " + "{valid_key_specs}" + ).format(key_spec=key_spec, valid_key_specs=KeySpec.key_specs()) + ) + def sign( self, key_id: str, message: bytes, signing_algorithm: str ) -> Tuple[str, bytes, str]: diff --git a/moto/kms/utils.py b/moto/kms/utils.py index 2639f5ca4..35fec1c0f 100644 --- a/moto/kms/utils.py +++ b/moto/kms/utils.py @@ -1,5 +1,6 @@ from collections import namedtuple -from typing import Any, Dict, Tuple +from typing import Any, Dict, Tuple, List +from enum import Enum import io import os import struct @@ -48,6 +49,28 @@ RESERVED_ALIASE_TARGET_KEY_IDS = { RESERVED_ALIASES = list(RESERVED_ALIASE_TARGET_KEY_IDS.keys()) +class KeySpec(str, Enum): + # Asymmetric key specs + RSA_2048 = "RSA_2048" + RSA_3072 = "RSA_3072" + RSA_4096 = "RSA_4096" + ECC_NIST_P256 = "ECC_NIST_P256" + ECC_SECG_P256K1 = "ECC_SECG_P256K1" + ECC_NIST_P384 = "ECC_NIST_P384" + ECC_NIST_P512 = "ECC_NIST_P521" + SM2 = "SM2" # China Regions only + # Symmetric key specs + SYMMETRIC_DEFAULT = "SYMMETRIC_DEFAULT" + HMAC_224 = "HMAC_224" + HMAC_256 = "HMAC_256" + HMAC_284 = "HMAC_384" + HMAC_512 = "HMAC_512" + + @classmethod + def key_specs(self) -> List[str]: + return sorted([item.value for item in KeySpec]) + + def generate_key_id(multi_region: bool = False) -> str: key = str(mock_random.uuid4()) # https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html diff --git a/tests/test_kms/test_kms_boto3.py b/tests/test_kms/test_kms_boto3.py index dd82e9c2c..3c1e0ab8d 100644 --- a/tests/test_kms/test_kms_boto3.py +++ b/tests/test_kms/test_kms_boto3.py @@ -42,6 +42,21 @@ def test_create_key_without_description(): assert metadata["Description"] == "" +@mock_kms +def test_create_key_with_invalid_key_spec(): + conn = boto3.client("kms", region_name="us-east-1") + unsupported_key_spec = "NotSupportedKeySpec" + with pytest.raises(ClientError) as ex: + conn.create_key(Policy="my policy", KeySpec=unsupported_key_spec) + err = ex.value.response["Error"] + assert err["Code"] == "ValidationException" + assert err["Message"] == ( + "1 validation error detected: Value '{key_spec}' at 'KeySpec' failed " + "to satisfy constraint: Member must satisfy enum value set: " + "['ECC_NIST_P256', 'ECC_NIST_P384', 'ECC_NIST_P521', 'ECC_SECG_P256K1', 'HMAC_224', 'HMAC_256', 'HMAC_384', 'HMAC_512', 'RSA_2048', 'RSA_3072', 'RSA_4096', 'SM2', 'SYMMETRIC_DEFAULT']" + ).format(key_spec=unsupported_key_spec) + + @mock_kms def test_create_key(): conn = boto3.client("kms", region_name="us-east-1")