Skip to content

Commit 0de58cd

Browse files
feat(test_vector_handlers): Hierarchy keyring test vectors (#674)
1 parent ca7e159 commit 0de58cd

11 files changed

+334
-12
lines changed

buildspec.yml

+22-1
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,28 @@ batch:
296296
buildspec: codebuild/py312/decrypt_keyrings_with_js.yml
297297
env:
298298
image: aws/codebuild/standard:7.0
299-
299+
- identifier: py312_generate_hkeyring_decrypt_vectors
300+
buildspec: codebuild/py312/generate_hkeyring_decrypt_vectors.yml
301+
env:
302+
image: aws/codebuild/standard:7.0
303+
- identifier: py312_decrypt_hkeyring_with_masterkey
304+
depend-on:
305+
- py312_generate_hkeyring_decrypt_vectors
306+
buildspec: codebuild/py312/decrypt_hkeyring_with_masterkey.yml
307+
env:
308+
image: aws/codebuild/standard:7.0
309+
- identifier: py312_decrypt_hkeyring_with_keyrings
310+
depend-on:
311+
- py312_generate_hkeyring_decrypt_vectors
312+
buildspec: codebuild/py312/decrypt_hkeyring_with_keyrings.yml
313+
env:
314+
image: aws/codebuild/standard:7.0
315+
- identifier: py312_decrypt_hkeyring_with_net
316+
depend-on:
317+
- py312_generate_hkeyring_decrypt_vectors
318+
buildspec: codebuild/py312/decrypt_hkeyring_with_net.yml
319+
env:
320+
image: aws/codebuild/standard:7.0
300321

301322
- identifier: code_coverage
302323
buildspec: codebuild/coverage/coverage.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
version: 0.2
2+
3+
env:
4+
variables:
5+
TOXENV: "py312-full_decrypt-mpl"
6+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID: >-
7+
arn:aws:kms:us-west-2:658956600833:key/b35311ef1-d8dc-4780-9f5a-55776cbb2f7f
8+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID_2: >-
9+
arn:aws:kms:eu-central-1:658956600833:key/75414c93-5285-4b57-99c9-30c1cf0a22c2
10+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_1: >-
11+
arn:aws:kms:us-west-2:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
12+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_2: >-
13+
arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
14+
15+
phases:
16+
install:
17+
runtime-versions:
18+
python: 3.12
19+
pre_build:
20+
commands:
21+
# Download previously generated vectors
22+
# This manifest has coverage for both HKeyring and required encryption context CMM
23+
- aws s3 cp s3://generated-vectors-artifacts-bucket/$CODEBUILD_RESOLVED_SOURCE_VERSION/312_hkeyring_reccmm_manifest.zip 312_hkeyring_reccmm_manifest.zip
24+
- unzip 312_hkeyring_reccmm_manifest.zip
25+
build:
26+
commands:
27+
- pip install "tox < 4.0"
28+
- cd test_vector_handlers
29+
- |
30+
tox -- \
31+
--input ../312_hkeyring_reccmm_manifest/manifest.json \
32+
--keyrings
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
version: 0.2
2+
3+
env:
4+
variables:
5+
TOXENV: "py312-full_decrypt-mpl"
6+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID: >-
7+
arn:aws:kms:us-west-2:658956600833:key/b35311ef1-d8dc-4780-9f5a-55776cbb2f7f
8+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID_2: >-
9+
arn:aws:kms:eu-central-1:658956600833:key/75414c93-5285-4b57-99c9-30c1cf0a22c2
10+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_1: >-
11+
arn:aws:kms:us-west-2:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
12+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_2: >-
13+
arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
14+
15+
phases:
16+
install:
17+
runtime-versions:
18+
python: 3.12
19+
pre_build:
20+
commands:
21+
# Download previously generated vectors
22+
# This manifest has coverage for both HKeyring and required encryption context CMM
23+
- aws s3 cp s3://generated-vectors-artifacts-bucket/$CODEBUILD_RESOLVED_SOURCE_VERSION/312_hkeyring_reccmm_manifest.zip 312_hkeyring_reccmm_manifest.zip
24+
- unzip 312_hkeyring_reccmm_manifest.zip
25+
build:
26+
commands:
27+
- pip install "tox < 4.0"
28+
- cd test_vector_handlers
29+
- |
30+
tox -- \
31+
--input ../312_hkeyring_reccmm_manifest/manifest.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
version: 0.2
2+
3+
env:
4+
variables:
5+
TOXENV: "py312-full_decrypt-mpl"
6+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID: >-
7+
arn:aws:kms:us-west-2:658956600833:key/b35311ef1-d8dc-4780-9f5a-55776cbb2f7f
8+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID_2: >-
9+
arn:aws:kms:eu-central-1:658956600833:key/75414c93-5285-4b57-99c9-30c1cf0a22c2
10+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_1: >-
11+
arn:aws:kms:us-west-2:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
12+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_2: >-
13+
arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
14+
15+
phases:
16+
install:
17+
runtime-versions:
18+
python: 3.12
19+
pre_build:
20+
commands:
21+
# Download previously generated vectors
22+
# This manifest has coverage for both HKeyring and required encryption context CMM
23+
- aws s3 cp s3://generated-vectors-artifacts-bucket/$CODEBUILD_RESOLVED_SOURCE_VERSION/312_hkeyring_reccmm_manifest.zip 312_hkeyring_reccmm_manifest.zip
24+
- unzip 312_hkeyring_reccmm_manifest.zip
25+
- export DAFNY_AWS_ESDK_TEST_VECTOR_MANIFEST_PATH="${PWD}/312_hkeyring_reccmm_manifest/manifest.json"
26+
27+
# Download dafny
28+
- 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
29+
- unzip -qq dafny.zip && rm dafny.zip
30+
- export PATH="$PWD/dafny:$PATH"
31+
32+
# Clone SDK-Dafny repo to get test vectors runner
33+
- git clone --recurse-submodules https://github.com/aws/aws-encryption-sdk-dafny.git
34+
# TODO: Change branch to published when available
35+
- cd aws-encryption-sdk-dafny
36+
- git checkout lucmcdon/hkeyring-vectors
37+
- git pull
38+
- cd AwsEncryptionSDK/
39+
- make transpile_net
40+
- cd ../mpl/TestVectorsAwsCryptographicMaterialProviders/
41+
- make transpile_net
42+
43+
# Change TestVectors to reference the published .NET ESDK
44+
- cd ../../AwsEncryptionSDK/runtimes/net/TestVectorsNative/TestVectors
45+
# - sed -i -e 's/<ProjectReference Include="\.\.\/\.\.\/ESDK\.csproj" \/>/<PackageReference Include="AWS.Cryptography.EncryptionSDK" Version="4.0.1" \/>/g' AWSEncryptionSDKTestVectorLib.csproj
46+
# - cd ../TestVectors
47+
48+
build:
49+
commands:
50+
- dotnet test --framework net6.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
version: 0.2
2+
3+
env:
4+
variables:
5+
TOXENV: "py312-full_decrypt_generate-mpl"
6+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID: >-
7+
arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f
8+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID_2: >-
9+
arn:aws:kms:eu-central-1:658956600833:key/75414c93-5285-4b57-99c9-30c1cf0a22c2
10+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_1: >-
11+
arn:aws:kms:us-west-2:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
12+
AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_MRK_KEY_ID_2: >-
13+
arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
14+
15+
phases:
16+
install:
17+
runtime-versions:
18+
python: 3.12
19+
build:
20+
commands:
21+
- pip install "tox < 4.0"
22+
- cd test_vector_handlers/test/aws-crypto-tools-test-vector-framework
23+
# Checkout WIP branch with manifest containing HKeyring and required EC CMM test cases
24+
- git checkout lucmcdon/hierarchy-test-vectors
25+
- git pull
26+
- cd ../..
27+
- |
28+
tox -- \
29+
--input test/aws-crypto-tools-test-vector-framework/features/CANONICAL-GENERATED-MANIFESTS/0007-hkeyring-reccmm-generate-manifest.json \
30+
--output 312_hkeyring_reccmm_manifest \
31+
--keyrings
32+
- zip -r 312_hkeyring_reccmm_manifest.zip 312_hkeyring_reccmm_manifest
33+
- aws s3 cp 312_hkeyring_reccmm_manifest.zip s3://generated-vectors-artifacts-bucket/$CODEBUILD_RESOLVED_SOURCE_VERSION/312_hkeyring_reccmm_manifest.zip

test_vector_handlers/src/awses_test_vectors/manifests/full_message/decrypt.py

+14-3
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ class MessageDecryptionTestScenario(object):
225225
master_key_provider_fn = attr.ib(validator=attr.validators.is_callable())
226226
result = attr.ib(validator=attr.validators.instance_of(MessageDecryptionTestResult))
227227
keyrings = attr.ib(validator=attr.validators.instance_of(bool))
228-
cmm_type = attr.ib(validator=attr.validators.instance_of(str))
228+
cmm_type = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(str)))
229229
decryption_method = attr.ib(
230230
default=None, validator=attr.validators.optional(attr.validators.instance_of(DecryptionMethod))
231231
)
@@ -292,6 +292,7 @@ def from_scenario(
292292
else:
293293
master_key_specs = [
294294
MasterKeySpec.from_scenario(spec) for spec in raw_master_key_specs
295+
if spec["type"] != "aws-kms-hierarchy"
295296
]
296297

297298
def master_key_provider_fn():
@@ -310,7 +311,8 @@ def master_key_provider_fn():
310311
encryption_context = {}
311312

312313
# MPL test vectors add CMM types to the test vectors manifests
313-
if "cmm" in scenario:
314+
if "cmm" in scenario \
315+
and scenario["cmm"] is not None:
314316
if scenario["cmm"] == "Default":
315317
# Master keys and keyrings can handle default CMM
316318
cmm_type = scenario["cmm"]
@@ -323,11 +325,17 @@ def master_key_provider_fn():
323325
else:
324326
return None
325327
else:
326-
raise ValueError("Unrecognized cmm_type: " + cmm_type)
328+
raise ValueError("Unrecognized cmm_type: " + scenario["cmm"])
327329
else:
328330
# If unspecified, set "Default" as the default
329331
cmm_type = "Default"
330332

333+
# If this scenario does not have any key providers,
334+
# do not create a scenario.
335+
# Caller logic should expect `None` to mean "no scenario".
336+
if master_key_provider_fn() is None:
337+
return None
338+
331339
return cls(
332340
ciphertext_uri=scenario["ciphertext"],
333341
ciphertext=ciphertext_reader(scenario["ciphertext"]),
@@ -358,6 +366,9 @@ def scenario_spec(self):
358366
spec["decryption-method"] = self.decryption_method.value
359367
if self.description is not None:
360368
spec["description"] = self.description
369+
spec["cmm"] = self.cmm_type
370+
spec["encryption-context"] = self.encryption_context
371+
361372
return spec
362373

363374
def _one_shot_decrypt(self):

test_vector_handlers/src/awses_test_vectors/manifests/full_message/decrypt_generation.py

+22-3
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
# We only actually need these imports when running the mypy checks
8282
pass
8383

84-
SUPPORTED_VERSIONS = (2,)
84+
SUPPORTED_VERSIONS = (2, 4, )
8585

8686

8787
class TamperingMethod:
@@ -410,6 +410,8 @@ class MessageDecryptionTestScenarioGenerator(object):
410410
decryption_master_key_provider_fn = attr.ib(validator=attr.validators.is_callable())
411411
result = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(MessageDecryptionTestResult)))
412412
keyrings = attr.ib(validator=attr.validators.instance_of(bool))
413+
cmm_type = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(str)))
414+
encryption_context = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(dict)))
413415

414416
@classmethod
415417
def from_scenario(cls, scenario, keys, plaintexts, keyrings, keys_uri):
@@ -432,6 +434,10 @@ def from_scenario(cls, scenario, keys, plaintexts, keyrings, keys_uri):
432434
keyrings,
433435
keys_uri,
434436
)
437+
438+
if encryption_scenario is None:
439+
return None
440+
435441
tampering = scenario.get("tampering")
436442
tampering_method = TamperingMethod.from_tampering_spec(tampering)
437443
decryption_method_spec = scenario.get("decryption-method")
@@ -457,6 +463,16 @@ def decryption_master_key_provider_fn():
457463
result_spec = scenario.get("result")
458464
result = MessageDecryptionTestResult.from_result_spec(result_spec, None) if result_spec else None
459465

466+
try:
467+
encryption_context = encryption_scenario_spec["encryption-context"]
468+
except KeyError:
469+
encryption_context = None
470+
471+
try:
472+
cmm_type = encryption_scenario_spec["cmm"]
473+
except KeyError:
474+
cmm_type = None
475+
460476
return cls(
461477
encryption_scenario=encryption_scenario,
462478
tampering_method=tampering_method,
@@ -465,6 +481,8 @@ def decryption_master_key_provider_fn():
465481
decryption_master_key_provider_fn=decryption_master_key_provider_fn,
466482
result=result,
467483
keyrings=keyrings,
484+
cmm_type=cmm_type,
485+
encryption_context=encryption_context,
468486
)
469487

470488
def run(self, ciphertext_writer, plaintext_uri):
@@ -494,8 +512,8 @@ def decryption_test_scenario_pair(self, ciphertext_writer, ciphertext_to_decrypt
494512
decryption_method=self.decryption_method,
495513
result=expected_result,
496514
keyrings=self.keyrings,
497-
cmm_type="Default",
498-
encryption_context={}
515+
cmm_type=self.cmm_type,
516+
encryption_context=self.encryption_context,
499517
),
500518
)
501519

@@ -533,6 +551,7 @@ def _generate_plaintexts(plaintexts_specs):
533551

534552
@classmethod
535553
def from_file(cls, input_file, keyrings):
554+
# pylint: disable=too-many-locals
536555
# type: (IO) -> MessageDecryptionGenerationManifest
537556
"""Load from a file containing a full message encrypt manifest.
538557

test_vector_handlers/src/awses_test_vectors/manifests/full_message/encrypt.py

+21
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ class MessageEncryptionTestScenario(object):
8383
master_key_specs = attr.ib(validator=iterable_validator(list, MasterKeySpec))
8484
master_key_provider_fn = attr.ib(validator=attr.validators.is_callable())
8585
keyrings = attr.ib(validator=attr.validators.instance_of(bool))
86+
cmm = attr.ib(validator=attr.validators.instance_of(str))
8687

8788
@classmethod
8889
def from_scenario(cls, scenario, keys, plaintexts, keyrings, keys_uri):
@@ -114,6 +115,25 @@ def master_key_provider_fn():
114115
return keyring_from_master_key_specs(keys_uri, master_key_specs, "encrypt")
115116
return master_key_provider_from_master_key_specs(keys, master_key_specs)
116117

118+
# MPL test vectors add CMM types to the test vectors manifests
119+
if "cmm" in scenario:
120+
if scenario["cmm"] == "Default":
121+
# Master keys and keyrings can handle default CMM
122+
cmm_type = scenario["cmm"]
123+
elif scenario["cmm"] == "RequiredEncryptionContext":
124+
# Skip RequiredEncryptionContext CMM for master keys;
125+
# RequiredEncryptionContext is unsupported for master keys.
126+
# Caller logic should expect `None` to mean "no scenario".
127+
if keyrings:
128+
cmm_type = scenario["cmm"]
129+
else:
130+
return None
131+
else:
132+
raise ValueError("Unrecognized cmm_type: " + cmm_type)
133+
else:
134+
# If unspecified, set "Default" as the default
135+
cmm_type = "Default"
136+
117137
return cls(
118138
plaintext_name=scenario["plaintext"],
119139
plaintext=plaintexts[scenario["plaintext"]],
@@ -123,6 +143,7 @@ def master_key_provider_fn():
123143
master_key_specs=master_key_specs,
124144
master_key_provider_fn=master_key_provider_fn,
125145
keyrings=keyrings,
146+
cmm=cmm_type,
126147
)
127148

128149
def run(self, materials_manager=None):

0 commit comments

Comments
 (0)