From 11e2120046a13892f8cb82f5ef8fba15bc876c03 Mon Sep 17 00:00:00 2001 From: Bert Blommers Date: Wed, 22 Feb 2023 10:22:37 -0100 Subject: [PATCH] KMS: encrypt() should allow an alias as argument (#5959) --- moto/kms/models.py | 2 +- tests/test_kms/test_kms_boto3.py | 132 ---------------------- tests/test_kms/test_kms_encrypt.py | 176 +++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 133 deletions(-) create mode 100644 tests/test_kms/test_kms_encrypt.py diff --git a/moto/kms/models.py b/moto/kms/models.py index 8549da5ea..917407699 100644 --- a/moto/kms/models.py +++ b/moto/kms/models.py @@ -363,7 +363,7 @@ class KmsBackend(BaseBackend): key_id = self.get_alias_name(key_id) key_id = self.get_key_id(key_id) if key_id.startswith("alias/"): - key_id = self.get_key_id_from_alias(key_id) + key_id = self.get_key_id(self.get_key_id_from_alias(key_id)) return key_id def alias_exists(self, alias_name): diff --git a/tests/test_kms/test_kms_boto3.py b/tests/test_kms/test_kms_boto3.py index f51b75129..f82d56309 100644 --- a/tests/test_kms/test_kms_boto3.py +++ b/tests/test_kms/test_kms_boto3.py @@ -43,19 +43,6 @@ def test_create_key_without_description(): metadata.should.have.key("Description").equal("") -@mock_kms -def test_create_key_with_empty_content(): - client_kms = boto3.client("kms", region_name="ap-northeast-1") - metadata = client_kms.create_key(Policy="my policy")["KeyMetadata"] - with pytest.raises(ClientError) as exc: - client_kms.encrypt(KeyId=metadata["KeyId"], Plaintext="") - err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "1 validation error detected: Value at 'plaintext' failed to satisfy constraint: Member must have length greater than or equal to 1" - ) - - @mock_kms def test_create_key(): conn = boto3.client("kms", region_name="us-east-1") @@ -377,51 +364,6 @@ def test_generate_data_key(): response["KeyId"].should.equal(key_arn) -@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS) -@mock_kms -def test_encrypt(plaintext): - client = boto3.client("kms", region_name="us-west-2") - - key = client.create_key(Description="key") - key_id = key["KeyMetadata"]["KeyId"] - key_arn = key["KeyMetadata"]["Arn"] - - response = client.encrypt(KeyId=key_id, Plaintext=plaintext) - response["CiphertextBlob"].should_not.equal(plaintext) - - # CiphertextBlob must NOT be base64-encoded - with pytest.raises(Exception): - base64.b64decode(response["CiphertextBlob"], validate=True) - - response["KeyId"].should.equal(key_arn) - - -@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS) -@mock_kms -def test_decrypt(plaintext): - client = boto3.client("kms", region_name="us-west-2") - - key = client.create_key(Description="key") - key_id = key["KeyMetadata"]["KeyId"] - key_arn = key["KeyMetadata"]["Arn"] - - encrypt_response = client.encrypt(KeyId=key_id, Plaintext=plaintext) - - client.create_key(Description="key") - # CiphertextBlob must NOT be base64-encoded - with pytest.raises(Exception): - base64.b64decode(encrypt_response["CiphertextBlob"], validate=True) - - decrypt_response = client.decrypt(CiphertextBlob=encrypt_response["CiphertextBlob"]) - - # Plaintext must NOT be base64-encoded - with pytest.raises(Exception): - base64.b64decode(decrypt_response["Plaintext"], validate=True) - - decrypt_response["Plaintext"].should.equal(_get_encoded_value(plaintext)) - decrypt_response["KeyId"].should.equal(key_arn) - - @pytest.mark.parametrize( "key_id", [ @@ -440,17 +382,6 @@ def test_invalid_key_ids(key_id): client.generate_data_key(KeyId=key_id, NumberOfBytes=5) -@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS) -@mock_kms -def test_kms_encrypt(plaintext): - client = boto3.client("kms", region_name="us-east-1") - key = client.create_key(Description="key") - response = client.encrypt(KeyId=key["KeyMetadata"]["KeyId"], Plaintext=plaintext) - - response = client.decrypt(CiphertextBlob=response["CiphertextBlob"]) - response["Plaintext"].should.equal(_get_encoded_value(plaintext)) - - @mock_kms def test_disable_key(): client = boto3.client("kms", region_name="us-east-1") @@ -738,69 +669,6 @@ def test_generate_data_key_without_plaintext_decrypt(): assert "Plaintext" not in resp1 -@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS) -@mock_kms -def test_re_encrypt_decrypt(plaintext): - client = boto3.client("kms", region_name="us-west-2") - - key_1 = client.create_key(Description="key 1") - key_1_id = key_1["KeyMetadata"]["KeyId"] - key_1_arn = key_1["KeyMetadata"]["Arn"] - key_2 = client.create_key(Description="key 2") - key_2_id = key_2["KeyMetadata"]["KeyId"] - key_2_arn = key_2["KeyMetadata"]["Arn"] - - encrypt_response = client.encrypt( - KeyId=key_1_id, Plaintext=plaintext, EncryptionContext={"encryption": "context"} - ) - - re_encrypt_response = client.re_encrypt( - CiphertextBlob=encrypt_response["CiphertextBlob"], - SourceEncryptionContext={"encryption": "context"}, - DestinationKeyId=key_2_id, - DestinationEncryptionContext={"another": "context"}, - ) - - # CiphertextBlob must NOT be base64-encoded - with pytest.raises(Exception): - base64.b64decode(re_encrypt_response["CiphertextBlob"], validate=True) - - re_encrypt_response["SourceKeyId"].should.equal(key_1_arn) - re_encrypt_response["KeyId"].should.equal(key_2_arn) - - decrypt_response_1 = client.decrypt( - CiphertextBlob=encrypt_response["CiphertextBlob"], - EncryptionContext={"encryption": "context"}, - ) - decrypt_response_1["Plaintext"].should.equal(_get_encoded_value(plaintext)) - decrypt_response_1["KeyId"].should.equal(key_1_arn) - - decrypt_response_2 = client.decrypt( - CiphertextBlob=re_encrypt_response["CiphertextBlob"], - EncryptionContext={"another": "context"}, - ) - decrypt_response_2["Plaintext"].should.equal(_get_encoded_value(plaintext)) - decrypt_response_2["KeyId"].should.equal(key_2_arn) - - decrypt_response_1["Plaintext"].should.equal(decrypt_response_2["Plaintext"]) - - -@mock_kms -def test_re_encrypt_to_invalid_destination(): - client = boto3.client("kms", region_name="us-west-2") - - key = client.create_key(Description="key 1") - key_id = key["KeyMetadata"]["KeyId"] - - encrypt_response = client.encrypt(KeyId=key_id, Plaintext=b"some plaintext") - - with pytest.raises(client.exceptions.NotFoundException): - client.re_encrypt( - CiphertextBlob=encrypt_response["CiphertextBlob"], - DestinationKeyId="alias/DoesNotExist", - ) - - @pytest.mark.parametrize("number_of_bytes", [12, 44, 91, 1, 1024]) @mock_kms def test_generate_random(number_of_bytes): diff --git a/tests/test_kms/test_kms_encrypt.py b/tests/test_kms/test_kms_encrypt.py new file mode 100644 index 000000000..6db34dcc3 --- /dev/null +++ b/tests/test_kms/test_kms_encrypt.py @@ -0,0 +1,176 @@ +import base64 + +import boto3 +import sure # noqa # pylint: disable=unused-import +from botocore.exceptions import ClientError +import pytest + +from moto import mock_kms +from .test_kms_boto3 import PLAINTEXT_VECTORS, _get_encoded_value + + +@mock_kms +def test_create_key_with_empty_content(): + client_kms = boto3.client("kms", region_name="ap-northeast-1") + metadata = client_kms.create_key(Policy="my policy")["KeyMetadata"] + with pytest.raises(ClientError) as exc: + client_kms.encrypt(KeyId=metadata["KeyId"], Plaintext="") + err = exc.value.response["Error"] + err["Code"].should.equal("ValidationException") + err["Message"].should.equal( + "1 validation error detected: Value at 'plaintext' failed to satisfy constraint: Member must have length greater than or equal to 1" + ) + + +@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS) +@mock_kms +def test_encrypt(plaintext): + client = boto3.client("kms", region_name="us-west-2") + + key = client.create_key(Description="key") + key_id = key["KeyMetadata"]["KeyId"] + key_arn = key["KeyMetadata"]["Arn"] + + response = client.encrypt(KeyId=key_id, Plaintext=plaintext) + response["CiphertextBlob"].should_not.equal(plaintext) + + # CiphertextBlob must NOT be base64-encoded + with pytest.raises(Exception): + base64.b64decode(response["CiphertextBlob"], validate=True) + + response["KeyId"].should.equal(key_arn) + + +@mock_kms +def test_encrypt_using_alias_name(): + kms = boto3.client("kms", region_name="us-east-1") + key_details = kms.create_key() + key_alias = "alias/examplekey" + kms.create_alias(AliasName=key_alias, TargetKeyId=key_details["KeyMetadata"]["Arn"]) + + # Just ensure that they do not throw an error, i.e. verify that it's possible to call this method using the Alias + resp = kms.encrypt(KeyId=key_alias, Plaintext="hello") + kms.decrypt(CiphertextBlob=resp["CiphertextBlob"]) + + +@mock_kms +def test_encrypt_using_alias_arn(): + kms = boto3.client("kms", region_name="us-east-1") + key_details = kms.create_key() + key_alias = "alias/examplekey" + kms.create_alias(AliasName=key_alias, TargetKeyId=key_details["KeyMetadata"]["Arn"]) + + aliases = kms.list_aliases(KeyId=key_details["KeyMetadata"]["Arn"])["Aliases"] + my_alias = [a for a in aliases if a["AliasName"] == key_alias][0] + + kms.encrypt(KeyId=my_alias["AliasArn"], Plaintext="hello") + + +@mock_kms +def test_encrypt_using_key_arn(): + kms = boto3.client("kms", region_name="us-east-1") + key_details = kms.create_key() + key_alias = "alias/examplekey" + kms.create_alias(AliasName=key_alias, TargetKeyId=key_details["KeyMetadata"]["Arn"]) + + kms.encrypt(KeyId=key_details["KeyMetadata"]["Arn"], Plaintext="hello") + + +@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS) +@mock_kms +def test_decrypt(plaintext): + client = boto3.client("kms", region_name="us-west-2") + + key = client.create_key(Description="key") + key_id = key["KeyMetadata"]["KeyId"] + key_arn = key["KeyMetadata"]["Arn"] + + encrypt_response = client.encrypt(KeyId=key_id, Plaintext=plaintext) + + client.create_key(Description="key") + # CiphertextBlob must NOT be base64-encoded + with pytest.raises(Exception): + base64.b64decode(encrypt_response["CiphertextBlob"], validate=True) + + decrypt_response = client.decrypt(CiphertextBlob=encrypt_response["CiphertextBlob"]) + + # Plaintext must NOT be base64-encoded + with pytest.raises(Exception): + base64.b64decode(decrypt_response["Plaintext"], validate=True) + + decrypt_response["Plaintext"].should.equal(_get_encoded_value(plaintext)) + decrypt_response["KeyId"].should.equal(key_arn) + + +@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS) +@mock_kms +def test_kms_encrypt(plaintext): + client = boto3.client("kms", region_name="us-east-1") + key = client.create_key(Description="key") + response = client.encrypt(KeyId=key["KeyMetadata"]["KeyId"], Plaintext=plaintext) + + response = client.decrypt(CiphertextBlob=response["CiphertextBlob"]) + response["Plaintext"].should.equal(_get_encoded_value(plaintext)) + + +@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS) +@mock_kms +def test_re_encrypt_decrypt(plaintext): + client = boto3.client("kms", region_name="us-west-2") + + key_1 = client.create_key(Description="key 1") + key_1_id = key_1["KeyMetadata"]["KeyId"] + key_1_arn = key_1["KeyMetadata"]["Arn"] + key_2 = client.create_key(Description="key 2") + key_2_id = key_2["KeyMetadata"]["KeyId"] + key_2_arn = key_2["KeyMetadata"]["Arn"] + + encrypt_response = client.encrypt( + KeyId=key_1_id, Plaintext=plaintext, EncryptionContext={"encryption": "context"} + ) + + re_encrypt_response = client.re_encrypt( + CiphertextBlob=encrypt_response["CiphertextBlob"], + SourceEncryptionContext={"encryption": "context"}, + DestinationKeyId=key_2_id, + DestinationEncryptionContext={"another": "context"}, + ) + + # CiphertextBlob must NOT be base64-encoded + with pytest.raises(Exception): + base64.b64decode(re_encrypt_response["CiphertextBlob"], validate=True) + + re_encrypt_response["SourceKeyId"].should.equal(key_1_arn) + re_encrypt_response["KeyId"].should.equal(key_2_arn) + + decrypt_response_1 = client.decrypt( + CiphertextBlob=encrypt_response["CiphertextBlob"], + EncryptionContext={"encryption": "context"}, + ) + decrypt_response_1["Plaintext"].should.equal(_get_encoded_value(plaintext)) + decrypt_response_1["KeyId"].should.equal(key_1_arn) + + decrypt_response_2 = client.decrypt( + CiphertextBlob=re_encrypt_response["CiphertextBlob"], + EncryptionContext={"another": "context"}, + ) + decrypt_response_2["Plaintext"].should.equal(_get_encoded_value(plaintext)) + decrypt_response_2["KeyId"].should.equal(key_2_arn) + + decrypt_response_1["Plaintext"].should.equal(decrypt_response_2["Plaintext"]) + + +@mock_kms +def test_re_encrypt_to_invalid_destination(): + client = boto3.client("kms", region_name="us-west-2") + + key = client.create_key(Description="key 1") + key_id = key["KeyMetadata"]["KeyId"] + + encrypt_response = client.encrypt(KeyId=key_id, Plaintext=b"some plaintext") + + with pytest.raises(client.exceptions.NotFoundException): + client.re_encrypt( + CiphertextBlob=encrypt_response["CiphertextBlob"], + DestinationKeyId="alias/DoesNotExist", + )