diff --git a/buildspec.yml b/buildspec.yml
index 583fae56f..4665ac89e 100644
--- a/buildspec.yml
+++ b/buildspec.yml
@@ -296,7 +296,28 @@ batch:
buildspec: codebuild/py312/decrypt_keyrings_with_js.yml
env:
image: aws/codebuild/standard:7.0
-
+ - identifier: py312_generate_hkeyring_decrypt_vectors
+ buildspec: codebuild/py312/generate_hkeyring_decrypt_vectors.yml
+ env:
+ image: aws/codebuild/standard:7.0
+ - identifier: py312_decrypt_hkeyring_with_masterkey
+ depend-on:
+ - py312_generate_hkeyring_decrypt_vectors
+ buildspec: codebuild/py312/decrypt_hkeyring_with_masterkey.yml
+ env:
+ image: aws/codebuild/standard:7.0
+ - identifier: py312_decrypt_hkeyring_with_keyrings
+ depend-on:
+ - py312_generate_hkeyring_decrypt_vectors
+ buildspec: codebuild/py312/decrypt_hkeyring_with_keyrings.yml
+ env:
+ image: aws/codebuild/standard:7.0
+ - identifier: py312_decrypt_hkeyring_with_net
+ depend-on:
+ - py312_generate_hkeyring_decrypt_vectors
+ buildspec: codebuild/py312/decrypt_hkeyring_with_net.yml
+ env:
+ image: aws/codebuild/standard:7.0
- identifier: code_coverage
buildspec: codebuild/coverage/coverage.yml
diff --git a/codebuild/py312/decrypt_hkeyring_with_keyrings.yml b/codebuild/py312/decrypt_hkeyring_with_keyrings.yml
new file mode 100644
index 000000000..5bcd26738
--- /dev/null
+++ b/codebuild/py312/decrypt_hkeyring_with_keyrings.yml
@@ -0,0 +1,32 @@
+version: 0.2
+
+env:
+ variables:
+ TOXENV: "py312-full_decrypt-mpl"
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID: >-
+ arn:aws:kms:us-west-2:658956600833:key/b35311ef1-d8dc-4780-9f5a-55776cbb2f7f
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID_2: >-
+ arn:aws:kms:eu-central-1:658956600833:key/75414c93-5285-4b57-99c9-30c1cf0a22c2
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_1: >-
+ arn:aws:kms:us-west-2:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_2: >-
+ arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
+
+phases:
+ install:
+ runtime-versions:
+ python: 3.12
+ pre_build:
+ commands:
+ # Download previously generated vectors
+ # This manifest has coverage for both HKeyring and required encryption context CMM
+ - aws s3 cp s3://generated-vectors-artifacts-bucket/$CODEBUILD_RESOLVED_SOURCE_VERSION/312_hkeyring_reccmm_manifest.zip 312_hkeyring_reccmm_manifest.zip
+ - unzip 312_hkeyring_reccmm_manifest.zip
+ build:
+ commands:
+ - pip install "tox < 4.0"
+ - cd test_vector_handlers
+ - |
+ tox -- \
+ --input ../312_hkeyring_reccmm_manifest/manifest.json \
+ --keyrings
\ No newline at end of file
diff --git a/codebuild/py312/decrypt_hkeyring_with_masterkey.yml b/codebuild/py312/decrypt_hkeyring_with_masterkey.yml
new file mode 100644
index 000000000..be67235d7
--- /dev/null
+++ b/codebuild/py312/decrypt_hkeyring_with_masterkey.yml
@@ -0,0 +1,31 @@
+version: 0.2
+
+env:
+ variables:
+ TOXENV: "py312-full_decrypt-mpl"
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID: >-
+ arn:aws:kms:us-west-2:658956600833:key/b35311ef1-d8dc-4780-9f5a-55776cbb2f7f
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID_2: >-
+ arn:aws:kms:eu-central-1:658956600833:key/75414c93-5285-4b57-99c9-30c1cf0a22c2
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_1: >-
+ arn:aws:kms:us-west-2:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_2: >-
+ arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
+
+phases:
+ install:
+ runtime-versions:
+ python: 3.12
+ pre_build:
+ commands:
+ # Download previously generated vectors
+ # This manifest has coverage for both HKeyring and required encryption context CMM
+ - aws s3 cp s3://generated-vectors-artifacts-bucket/$CODEBUILD_RESOLVED_SOURCE_VERSION/312_hkeyring_reccmm_manifest.zip 312_hkeyring_reccmm_manifest.zip
+ - unzip 312_hkeyring_reccmm_manifest.zip
+ build:
+ commands:
+ - pip install "tox < 4.0"
+ - cd test_vector_handlers
+ - |
+ tox -- \
+ --input ../312_hkeyring_reccmm_manifest/manifest.json
diff --git a/codebuild/py312/decrypt_hkeyring_with_net.yml b/codebuild/py312/decrypt_hkeyring_with_net.yml
new file mode 100644
index 000000000..6a3b321eb
--- /dev/null
+++ b/codebuild/py312/decrypt_hkeyring_with_net.yml
@@ -0,0 +1,50 @@
+version: 0.2
+
+env:
+ variables:
+ TOXENV: "py312-full_decrypt-mpl"
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID: >-
+ arn:aws:kms:us-west-2:658956600833:key/b35311ef1-d8dc-4780-9f5a-55776cbb2f7f
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID_2: >-
+ arn:aws:kms:eu-central-1:658956600833:key/75414c93-5285-4b57-99c9-30c1cf0a22c2
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_1: >-
+ arn:aws:kms:us-west-2:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_2: >-
+ arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
+
+phases:
+ install:
+ runtime-versions:
+ python: 3.12
+ pre_build:
+ commands:
+ # Download previously generated vectors
+ # This manifest has coverage for both HKeyring and required encryption context CMM
+ - aws s3 cp s3://generated-vectors-artifacts-bucket/$CODEBUILD_RESOLVED_SOURCE_VERSION/312_hkeyring_reccmm_manifest.zip 312_hkeyring_reccmm_manifest.zip
+ - unzip 312_hkeyring_reccmm_manifest.zip
+ - export DAFNY_AWS_ESDK_TEST_VECTOR_MANIFEST_PATH="${PWD}/312_hkeyring_reccmm_manifest/manifest.json"
+
+ # Download dafny
+ - curl https://github.com/dafny-lang/dafny/releases/download/v4.7.0/dafny-4.7.0-x64-ubuntu-20.04.zip -L -o dafny.zip
+ - unzip -qq dafny.zip && rm dafny.zip
+ - export PATH="$PWD/dafny:$PATH"
+
+ # Clone SDK-Dafny repo to get test vectors runner
+ - git clone --recurse-submodules https://github.com/aws/aws-encryption-sdk-dafny.git
+ # TODO: Change branch to published when available
+ - cd aws-encryption-sdk-dafny
+ - git checkout lucmcdon/hkeyring-vectors
+ - git pull
+ - cd AwsEncryptionSDK/
+ - make transpile_net
+ - cd ../mpl/TestVectorsAwsCryptographicMaterialProviders/
+ - make transpile_net
+
+ # Change TestVectors to reference the published .NET ESDK
+ - cd ../../AwsEncryptionSDK/runtimes/net/TestVectorsNative/TestVectors
+ # - sed -i -e 's///g' AWSEncryptionSDKTestVectorLib.csproj
+ # - cd ../TestVectors
+
+ build:
+ commands:
+ - dotnet test --framework net6.0
\ No newline at end of file
diff --git a/codebuild/py312/generate_hkeyring_decrypt_vectors.yml b/codebuild/py312/generate_hkeyring_decrypt_vectors.yml
new file mode 100644
index 000000000..b0a755360
--- /dev/null
+++ b/codebuild/py312/generate_hkeyring_decrypt_vectors.yml
@@ -0,0 +1,33 @@
+version: 0.2
+
+env:
+ variables:
+ TOXENV: "py312-full_decrypt_generate-mpl"
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID: >-
+ arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID_2: >-
+ arn:aws:kms:eu-central-1:658956600833:key/75414c93-5285-4b57-99c9-30c1cf0a22c2
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_1: >-
+ arn:aws:kms:us-west-2:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
+ AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_2: >-
+ arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
+
+phases:
+ install:
+ runtime-versions:
+ python: 3.12
+ build:
+ commands:
+ - pip install "tox < 4.0"
+ - cd test_vector_handlers/test/aws-crypto-tools-test-vector-framework
+ # Checkout WIP branch with manifest containing HKeyring and required EC CMM test cases
+ - git checkout lucmcdon/hierarchy-test-vectors
+ - git pull
+ - cd ../..
+ - |
+ tox -- \
+ --input test/aws-crypto-tools-test-vector-framework/features/CANONICAL-GENERATED-MANIFESTS/0007-hkeyring-reccmm-generate-manifest.json \
+ --output 312_hkeyring_reccmm_manifest \
+ --keyrings
+ - zip -r 312_hkeyring_reccmm_manifest.zip 312_hkeyring_reccmm_manifest
+ - aws s3 cp 312_hkeyring_reccmm_manifest.zip s3://generated-vectors-artifacts-bucket/$CODEBUILD_RESOLVED_SOURCE_VERSION/312_hkeyring_reccmm_manifest.zip
diff --git a/test_vector_handlers/src/awses_test_vectors/manifests/full_message/decrypt.py b/test_vector_handlers/src/awses_test_vectors/manifests/full_message/decrypt.py
index c2a233ca6..79df4f2cf 100644
--- a/test_vector_handlers/src/awses_test_vectors/manifests/full_message/decrypt.py
+++ b/test_vector_handlers/src/awses_test_vectors/manifests/full_message/decrypt.py
@@ -225,7 +225,7 @@ class MessageDecryptionTestScenario(object):
master_key_provider_fn = attr.ib(validator=attr.validators.is_callable())
result = attr.ib(validator=attr.validators.instance_of(MessageDecryptionTestResult))
keyrings = attr.ib(validator=attr.validators.instance_of(bool))
- cmm_type = attr.ib(validator=attr.validators.instance_of(str))
+ cmm_type = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(str)))
decryption_method = attr.ib(
default=None, validator=attr.validators.optional(attr.validators.instance_of(DecryptionMethod))
)
@@ -292,6 +292,7 @@ def from_scenario(
else:
master_key_specs = [
MasterKeySpec.from_scenario(spec) for spec in raw_master_key_specs
+ if spec["type"] != "aws-kms-hierarchy"
]
def master_key_provider_fn():
@@ -310,7 +311,8 @@ def master_key_provider_fn():
encryption_context = {}
# MPL test vectors add CMM types to the test vectors manifests
- if "cmm" in scenario:
+ if "cmm" in scenario \
+ and scenario["cmm"] is not None:
if scenario["cmm"] == "Default":
# Master keys and keyrings can handle default CMM
cmm_type = scenario["cmm"]
@@ -323,11 +325,17 @@ def master_key_provider_fn():
else:
return None
else:
- raise ValueError("Unrecognized cmm_type: " + cmm_type)
+ raise ValueError("Unrecognized cmm_type: " + scenario["cmm"])
else:
# If unspecified, set "Default" as the default
cmm_type = "Default"
+ # If this scenario does not have any key providers,
+ # do not create a scenario.
+ # Caller logic should expect `None` to mean "no scenario".
+ if master_key_provider_fn() is None:
+ return None
+
return cls(
ciphertext_uri=scenario["ciphertext"],
ciphertext=ciphertext_reader(scenario["ciphertext"]),
@@ -358,6 +366,9 @@ def scenario_spec(self):
spec["decryption-method"] = self.decryption_method.value
if self.description is not None:
spec["description"] = self.description
+ spec["cmm"] = self.cmm_type
+ spec["encryption-context"] = self.encryption_context
+
return spec
def _one_shot_decrypt(self):
diff --git a/test_vector_handlers/src/awses_test_vectors/manifests/full_message/decrypt_generation.py b/test_vector_handlers/src/awses_test_vectors/manifests/full_message/decrypt_generation.py
index 93510d891..63f8b8ff3 100644
--- a/test_vector_handlers/src/awses_test_vectors/manifests/full_message/decrypt_generation.py
+++ b/test_vector_handlers/src/awses_test_vectors/manifests/full_message/decrypt_generation.py
@@ -81,7 +81,7 @@
# We only actually need these imports when running the mypy checks
pass
-SUPPORTED_VERSIONS = (2,)
+SUPPORTED_VERSIONS = (2, 4, )
class TamperingMethod:
@@ -410,6 +410,8 @@ class MessageDecryptionTestScenarioGenerator(object):
decryption_master_key_provider_fn = attr.ib(validator=attr.validators.is_callable())
result = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(MessageDecryptionTestResult)))
keyrings = attr.ib(validator=attr.validators.instance_of(bool))
+ cmm_type = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(str)))
+ encryption_context = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(dict)))
@classmethod
def from_scenario(cls, scenario, keys, plaintexts, keyrings, keys_uri):
@@ -432,6 +434,10 @@ def from_scenario(cls, scenario, keys, plaintexts, keyrings, keys_uri):
keyrings,
keys_uri,
)
+
+ if encryption_scenario is None:
+ return None
+
tampering = scenario.get("tampering")
tampering_method = TamperingMethod.from_tampering_spec(tampering)
decryption_method_spec = scenario.get("decryption-method")
@@ -457,6 +463,16 @@ def decryption_master_key_provider_fn():
result_spec = scenario.get("result")
result = MessageDecryptionTestResult.from_result_spec(result_spec, None) if result_spec else None
+ try:
+ encryption_context = encryption_scenario_spec["encryption-context"]
+ except KeyError:
+ encryption_context = None
+
+ try:
+ cmm_type = encryption_scenario_spec["cmm"]
+ except KeyError:
+ cmm_type = None
+
return cls(
encryption_scenario=encryption_scenario,
tampering_method=tampering_method,
@@ -465,6 +481,8 @@ def decryption_master_key_provider_fn():
decryption_master_key_provider_fn=decryption_master_key_provider_fn,
result=result,
keyrings=keyrings,
+ cmm_type=cmm_type,
+ encryption_context=encryption_context,
)
def run(self, ciphertext_writer, plaintext_uri):
@@ -494,8 +512,8 @@ def decryption_test_scenario_pair(self, ciphertext_writer, ciphertext_to_decrypt
decryption_method=self.decryption_method,
result=expected_result,
keyrings=self.keyrings,
- cmm_type="Default",
- encryption_context={}
+ cmm_type=self.cmm_type,
+ encryption_context=self.encryption_context,
),
)
@@ -533,6 +551,7 @@ def _generate_plaintexts(plaintexts_specs):
@classmethod
def from_file(cls, input_file, keyrings):
+ # pylint: disable=too-many-locals
# type: (IO) -> MessageDecryptionGenerationManifest
"""Load from a file containing a full message encrypt manifest.
diff --git a/test_vector_handlers/src/awses_test_vectors/manifests/full_message/encrypt.py b/test_vector_handlers/src/awses_test_vectors/manifests/full_message/encrypt.py
index 82c1740de..81581fa8e 100644
--- a/test_vector_handlers/src/awses_test_vectors/manifests/full_message/encrypt.py
+++ b/test_vector_handlers/src/awses_test_vectors/manifests/full_message/encrypt.py
@@ -83,6 +83,7 @@ class MessageEncryptionTestScenario(object):
master_key_specs = attr.ib(validator=iterable_validator(list, MasterKeySpec))
master_key_provider_fn = attr.ib(validator=attr.validators.is_callable())
keyrings = attr.ib(validator=attr.validators.instance_of(bool))
+ cmm = attr.ib(validator=attr.validators.instance_of(str))
@classmethod
def from_scenario(cls, scenario, keys, plaintexts, keyrings, keys_uri):
@@ -114,6 +115,25 @@ def master_key_provider_fn():
return keyring_from_master_key_specs(keys_uri, master_key_specs, "encrypt")
return master_key_provider_from_master_key_specs(keys, master_key_specs)
+ # MPL test vectors add CMM types to the test vectors manifests
+ if "cmm" in scenario:
+ if scenario["cmm"] == "Default":
+ # Master keys and keyrings can handle default CMM
+ cmm_type = scenario["cmm"]
+ elif scenario["cmm"] == "RequiredEncryptionContext":
+ # Skip RequiredEncryptionContext CMM for master keys;
+ # RequiredEncryptionContext is unsupported for master keys.
+ # Caller logic should expect `None` to mean "no scenario".
+ if keyrings:
+ cmm_type = scenario["cmm"]
+ else:
+ return None
+ else:
+ raise ValueError("Unrecognized cmm_type: " + cmm_type)
+ else:
+ # If unspecified, set "Default" as the default
+ cmm_type = "Default"
+
return cls(
plaintext_name=scenario["plaintext"],
plaintext=plaintexts[scenario["plaintext"]],
@@ -123,6 +143,7 @@ def master_key_provider_fn():
master_key_specs=master_key_specs,
master_key_provider_fn=master_key_provider_fn,
keyrings=keyrings,
+ cmm=cmm_type,
)
def run(self, materials_manager=None):
diff --git a/test_vector_handlers/src/awses_test_vectors/manifests/keys.py b/test_vector_handlers/src/awses_test_vectors/manifests/keys.py
index 7c55a1617..ce8bf756f 100644
--- a/test_vector_handlers/src/awses_test_vectors/manifests/keys.py
+++ b/test_vector_handlers/src/awses_test_vectors/manifests/keys.py
@@ -19,6 +19,7 @@
from awses_test_vectors.internal.mypy_types import ( # noqa pylint: disable=unused-import
AWS_KMS_KEY_SPEC,
+ AWS_KMS_HIERARCHY_KEY_SPEC,
KEY_SPEC,
KEYS_MANIFEST,
MANIFEST_VERSION,
@@ -100,6 +101,51 @@ def manifest_spec(self):
}
+@attr.s(init=False)
+class AwsKmsHierarchyKeySpec(KeySpec):
+ """AWS KMS hierarchy key specification.
+
+ :param bool encrypt: Key can be used to encrypt
+ :param bool decrypt: Key can be used to decrypt
+ :param str type_name: Master key type name (must be "static-branch-key")
+ :param str key_id: Branch key ID
+ """
+
+ # pylint: disable=too-few-public-methods
+
+ type_name = attr.ib(validator=membership_validator(("static-branch-key",)))
+
+ # noqa pylint: disable=line-too-long,too-many-arguments
+ def __init__(self, encrypt, decrypt, type_name, key_id, branch_key_version, branch_key, beacon_key): # noqa=D107
+ # type: (bool, bool, str, str) -> None
+ # Workaround pending resolution of attrs/mypy interaction.
+ # https://github.com/python/mypy/issues/2088
+ # https://github.com/python-attrs/attrs/issues/215
+ self.type_name = type_name
+ self.branch_key_version = branch_key_version
+ self.branch_key = branch_key
+ self.beacon_key = beacon_key
+ super(AwsKmsHierarchyKeySpec, self).__init__(encrypt, decrypt, key_id)
+
+ @property
+ def manifest_spec(self):
+ # type: () -> AWS_KMS_HIERARCHY_KEY_SPEC
+ """Build a key specification describing this key specification.
+
+ :return: Key specification JSON
+ :rtype: dict
+ """
+ return {
+ "encrypt": self.encrypt,
+ "decrypt": self.decrypt,
+ "type": self.type_name,
+ "key-id": self.key_id,
+ "branchKeyVersion": self.branch_key_version,
+ "branchKey": self.branch_key,
+ "beaconKey": self.beacon_key,
+ }
+
+
@attr.s(init=False)
class ManualKeySpec(KeySpec):
# pylint: disable=too-many-arguments
@@ -196,8 +242,22 @@ def key_from_manifest_spec(key_spec):
key_id = key_spec["key-id"] # type: str
return AwsKmsKeySpec(encrypt=encrypt, decrypt=decrypt, type_name=type_name, key_id=key_id)
- algorithm = key_spec["algorithm"] # type: str
+ if key_spec["type"] == "static-branch-key":
+ branch_key_version = key_spec["branchKeyVersion"] # type: str
+ branch_key = key_spec["branchKey"] # type: str
+ beacon_key = key_spec["beaconKey"] # type: str
+ return AwsKmsHierarchyKeySpec(
+ encrypt=encrypt,
+ decrypt=decrypt,
+ type_name=type_name,
+ key_id=key_id,
+ branch_key_version=branch_key_version,
+ branch_key=branch_key,
+ beacon_key=beacon_key,
+ )
+
bits = key_spec["bits"] # type: int
+ algorithm = key_spec["algorithm"]
encoding = key_spec["encoding"] # type: str
material = key_spec["material"] # type: str
return ManualKeySpec(
diff --git a/test_vector_handlers/src/awses_test_vectors/manifests/master_key.py b/test_vector_handlers/src/awses_test_vectors/manifests/master_key.py
index 49b517eae..7e64f9983 100644
--- a/test_vector_handlers/src/awses_test_vectors/manifests/master_key.py
+++ b/test_vector_handlers/src/awses_test_vectors/manifests/master_key.py
@@ -34,7 +34,7 @@
# We only actually need these imports when running the mypy checks
pass
-KNOWN_TYPES = ("aws-kms", "aws-kms-mrk-aware", "aws-kms-mrk-aware-discovery", "raw")
+KNOWN_TYPES = ("aws-kms", "aws-kms-mrk-aware", "aws-kms-mrk-aware-discovery", "raw", )
KNOWN_ALGORITHMS = ("aes", "rsa")
KNOWN_PADDING = ("pkcs1", "oaep-mgf1")
KNOWN_PADDING_HASH = ("sha1", "sha256", "sha384", "sha512")
@@ -301,7 +301,17 @@ def master_key_provider_from_master_key_specs(keys, master_key_specs):
:return: Master key provider combining all loaded master keys
:rtype: MasterKeyProvider
"""
- master_keys = [spec.master_key(keys) for spec in master_key_specs]
+ master_keys = []
+ for spec in master_key_specs:
+ try:
+ master_keys.append(spec.master_key(keys))
+ # If spec is not a valid master key
+ # (e.g. hierarchical keyring)
+ # do not make a master key
+ except KeyError:
+ pass
+ if len(master_keys) == 0:
+ return None
primary = master_keys[0]
others = master_keys[1:]
for master_key in others:
diff --git a/test_vector_handlers/src/awses_test_vectors/manifests/mpl_keyring.py b/test_vector_handlers/src/awses_test_vectors/manifests/mpl_keyring.py
index 566bd7f55..dbabeb3c7 100644
--- a/test_vector_handlers/src/awses_test_vectors/manifests/mpl_keyring.py
+++ b/test_vector_handlers/src/awses_test_vectors/manifests/mpl_keyring.py
@@ -36,10 +36,20 @@
# Ignore pylint not being able to read a module that requires the MPL
# pylint: disable=no-name-in-module
from awses_test_vectors.internal.mpl.keyvectors_provider import KeyVectorsProvider
+from awses_test_vectors.internal.util import membership_validator
from awses_test_vectors.manifests.keys import KeysManifest # noqa: disable=F401
+from .master_key import KNOWN_TYPES as MASTER_KEY_KNOWN_TYPES, MasterKeySpec
-from .master_key import MasterKeySpec
+try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
+ from typing import Iterable # noqa pylint: disable=unused-import
+
+ from awses_test_vectors.internal.mypy_types import MASTER_KEY_SPEC # noqa pylint: disable=unused-import
+except ImportError: # pragma: no cover
+ # We only actually need these imports when running the mypy checks
+ pass
+
+KEYRING_ONLY_KNOWN_TYPES = ("aws-kms-hierarchy", )
@attr.s
@@ -56,6 +66,30 @@ class KeyringSpec(MasterKeySpec): # pylint: disable=too-many-instance-attribute
:param str padding_hash: Wrapping key padding hash (required for raw master keys)
"""
+ type_name = attr.ib(validator=membership_validator(
+ set(MASTER_KEY_KNOWN_TYPES).union(set(KEYRING_ONLY_KNOWN_TYPES))
+ ))
+
+ @classmethod
+ def from_scenario(cls, spec):
+ # type: (MASTER_KEY_SPEC) -> KeyringSpec
+ """Load from a keyring specification.
+
+ :param dict spec: Master key specification JSON
+ :return: Loaded master key specification
+ :rtype: MasterKeySpec
+ """
+ return cls(
+ type_name=spec["type"],
+ key_name=spec.get("key"),
+ default_mrk_region=spec.get("default-mrk-region"),
+ discovery_filter=cls._discovery_filter_from_spec(spec.get("aws-kms-discovery-filter")),
+ provider_id=spec.get("provider-id"),
+ encryption_algorithm=spec.get("encryption-algorithm"),
+ padding_algorithm=spec.get("padding-algorithm"),
+ padding_hash=spec.get("padding-hash"),
+ )
+
def keyring(self, keys_uri, mode):
# type: (KeysManifest) -> IKeyring
"""Build a keyring using this specification.
@@ -73,8 +107,8 @@ def keyring(self, keys_uri, mode):
"key": self.key_name,
"provider-id": self.provider_id,
"encryption-algorithm": self.encryption_algorithm,
-
}
+
if self.padding_algorithm is not None and self.padding_algorithm != "":
input_kwargs["padding-algorithm"] = self.padding_algorithm
if self.padding_hash is not None: