Skip to content

Commit

Permalink
Merge pull request #107 from mattsb42-aws/handlers
Browse files Browse the repository at this point in the history
Test vector handler updates
  • Loading branch information
mattsb42-aws committed Dec 3, 2018
2 parents fd07fbb + 67bf9f9 commit 5de76e5
Show file tree
Hide file tree
Showing 6 changed files with 4,323 additions and 4,420 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
MANIFEST_VERSION = Dict[str, Union[str, int]]

AWS_KMS_KEY_SPEC = Dict[str, Union[bool, str]]
MANUAL_KEY_SPEC = Dict[str, Union[bool, str, int, Iterable[str]]]
MANUAL_KEY_SPEC = Dict[str, Union[bool, str, int]]
KEY_SPEC = Union[AWS_KMS_KEY_SPEC, MANUAL_KEY_SPEC]
KEYS_MANIFEST = Dict[str, Union[MANIFEST_VERSION, Iterable[KEY_SPEC]]]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,4 @@ def run_and_write_to_dir(self, target_directory, json_indent=None):
keys_uri="file://keys.json", keys=self.keys, test_scenarios=test_scenarios
)

root_writer(
"manifest.json", json.dumps(decrypt_manifest.manifest_spec, indent=json_indent).encode(ENCODING)
)
root_writer("manifest.json", json.dumps(decrypt_manifest.manifest_spec, indent=json_indent).encode(ENCODING))
45 changes: 18 additions & 27 deletions test_vector_handlers/src/awses_test_vectors/manifests/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,7 @@

from awses_test_vectors.internal.aws_kms import arn_from_key_id
from awses_test_vectors.internal.defaults import ENCODING
from awses_test_vectors.internal.util import (
dictionary_validator,
iterable_validator,
membership_validator,
validate_manifest_type,
)
from awses_test_vectors.internal.util import dictionary_validator, membership_validator, validate_manifest_type

try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import cast, Dict, Iterable, Optional # noqa pylint: disable=unused-import
Expand All @@ -42,7 +37,7 @@
# We only actually need these imports when running the mypy checks
pass

SUPPORTED_VERSIONS = (1,)
SUPPORTED_VERSIONS = (3,)
KEY_TYPES = ("symmetric", "private", "public")
KEY_ENCODINGS = ("base64", "pem")
KEY_ALGORITHMS = ("aes", "rsa")
Expand All @@ -60,14 +55,16 @@ class KeySpec(object):

encrypt = attr.ib(validator=attr.validators.instance_of(bool))
decrypt = attr.ib(validator=attr.validators.instance_of(bool))
key_id = attr.ib(validator=attr.validators.instance_of(six.string_types))

def __init__(self, encrypt, decrypt): # noqa=D107
# type: (bool, bool) -> None
def __init__(self, encrypt, decrypt, key_id): # noqa=D107
# type: (bool, bool, 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.encrypt = encrypt
self.decrypt = decrypt
self.key_id = key_id
attr.validate(self)


Expand All @@ -84,16 +81,14 @@ class AwsKmsKeySpec(KeySpec):
# pylint: disable=too-few-public-methods

type_name = attr.ib(validator=membership_validator(("aws-kms",)))
key_id = attr.ib(validator=attr.validators.instance_of(six.string_types))

def __init__(self, encrypt, decrypt, type_name, key_id): # 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.key_id = key_id
super(AwsKmsKeySpec, self).__init__(encrypt, decrypt)
super(AwsKmsKeySpec, self).__init__(encrypt, decrypt, key_id)

@property
def manifest_spec(self):
Expand All @@ -117,35 +112,32 @@ class ManualKeySpec(KeySpec):
Allowed values described in AWS Crypto Tools Test Vector Framework feature #0002 Keys Manifest.
:param str key_id: Master key ID
:param bool encrypt: Key can be used to encrypt
:param bool decrypt: Key can be used to decrypt
:param str algorithm: Algorithm to use with key
:param str type_name: Key type
:param int bits: Key length in bits
:param str encoding: Encoding used to encode key material
:param material: Raw material encoded, then split into lines separated by ``line_separator``
:type material: list of str
:param str line_separator: Character with which to separate members of ``material``
before decoding (optional: default is empty string)
:param str material: Raw material encoded
"""

algorithm = attr.ib(validator=membership_validator(KEY_ALGORITHMS))
type_name = attr.ib(validator=membership_validator(KEY_TYPES))
bits = attr.ib(validator=attr.validators.instance_of(int))
encoding = attr.ib(validator=membership_validator(KEY_ENCODINGS))
material = attr.ib(validator=iterable_validator(list, six.string_types))
line_separator = attr.ib(default="", validator=attr.validators.instance_of(six.string_types))
material = attr.ib(validator=attr.validators.instance_of(six.string_types))

def __init__(
self,
key_id, # type: str
encrypt, # type: bool
decrypt, # type: bool
algorithm, # type: str
type_name, # type: str
bits, # type: int
encoding, # type: str
material, # type: Iterable[str]
line_separator="", # type: Optional[str]
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
Expand All @@ -156,8 +148,7 @@ def __init__(
self.bits = bits
self.encoding = encoding
self.material = material
self.line_separator = line_separator
super(ManualKeySpec, self).__init__(encrypt, decrypt)
super(ManualKeySpec, self).__init__(encrypt, decrypt, key_id)

@property
def raw_material(self):
Expand All @@ -167,7 +158,7 @@ def raw_material(self):
:return: Binary key material
:rtype: bytes
"""
raw_material = self.line_separator.join(self.material).encode(ENCODING)
raw_material = self.material.encode(ENCODING)
if self.encoding == "base64":
return base64.b64decode(raw_material)

Expand All @@ -188,8 +179,8 @@ def manifest_spec(self):
"type": self.type_name,
"bits": self.bits,
"encoding": self.encoding,
"line-separator": self.line_separator,
"material": self.material,
"key-id": self.key_id,
}


Expand All @@ -201,6 +192,7 @@ def key_from_manifest_spec(key_spec):
:return: Loaded key
:rtype: KeySpec
"""
key_id = key_spec["key-id"] # type: str
decrypt = key_spec["decrypt"] # type: bool
encrypt = key_spec["encrypt"] # type: bool
type_name = key_spec["type"] # type: str
Expand All @@ -211,16 +203,15 @@ def key_from_manifest_spec(key_spec):
algorithm = key_spec["algorithm"] # type: str
bits = key_spec["bits"] # type: int
encoding = key_spec["encoding"] # type: str
line_separator = key_spec.get("line-separator", "") # type: str
material = key_spec["material"] # type: Iterable[str]
material = key_spec["material"] # type: str
return ManualKeySpec(
key_id=key_id,
encrypt=encrypt,
decrypt=decrypt,
type_name=type_name,
algorithm=algorithm,
bits=bits,
encoding=encoding,
line_separator=line_separator,
material=material,
)

Expand All @@ -242,7 +233,7 @@ class KeysManifest(object):
@classmethod
def from_manifest_spec(cls, raw_manifest):
# type: (KEYS_MANIFEST) -> KeysManifest
""""""
"""Load from a JSON keys manifest."""
manifest_version = raw_manifest["manifest"] # type: MANIFEST_VERSION
validate_manifest_type(
type_name=cls.type_name, manifest_version=manifest_version, supported_versions=SUPPORTED_VERSIONS
Expand Down
49 changes: 17 additions & 32 deletions test_vector_handlers/src/awses_test_vectors/manifests/master_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,17 @@
"rsa/pkcs1": WrappingAlgorithm.RSA_PKCS1,
"rsa/oaep-mgf1/sha1": WrappingAlgorithm.RSA_OAEP_SHA1_MGF1,
"rsa/oaep-mgf1/sha256": WrappingAlgorithm.RSA_OAEP_SHA256_MGF1,
# \/ not yet implemented \/
# 'rsa/oaep-mgf1/sha384': WrappingAlgorithm.RSA_OAEP_SHA384_MGF1,
# 'rsa/oaep-mgf1/sha512': WrappingAlgorithm.RSA_OAEP_SHA512_MGF1,
}
_NOT_YET_IMPLEMENTED = {"rsa/oaep-mgf1/sha384", "rsa/oaep-mgf1/sha512"}
try:
_RAW_WRAPPING_KEY_ALGORITHMS.update(
{
"rsa/oaep-mgf1/sha384": WrappingAlgorithm.RSA_OAEP_SHA384_MGF1,
"rsa/oaep-mgf1/sha512": WrappingAlgorithm.RSA_OAEP_SHA512_MGF1,
}
)
_NOT_YET_IMPLEMENTED = {}
except AttributeError:
_NOT_YET_IMPLEMENTED = {"rsa/oaep-mgf1/sha384", "rsa/oaep-mgf1/sha512"}
_RAW_ENCRYPTION_KEY_TYPE = {
"symmetric": EncryptionKeyType.SYMMETRIC,
"private": EncryptionKeyType.PRIVATE,
Expand All @@ -68,18 +74,16 @@ class MasterKeySpec(object):
Described in AWS Crypto Tools Test Vector Framework features #0003 and #0004.
:param str type_name:
:param str key_name:
:param str key_id:
:param str provider_id:
:param str encryption_algorithm:
:param str padding_algorithm:
:param str padding_hash:
:param str type_name: Master key type name
:param str key_name: Name of key in keys spec
:param str provider_id: Master key provider ID
:param str encryption_algorithm: Wrapping key encryption algorithm (required for raw master keys)
:param str padding_algorithm: Wrapping key padding algorithm (required for raw master keys)
:param str padding_hash: Wrapping key padding hash (required for raw master keys)
"""

type_name = attr.ib(validator=membership_validator(KNOWN_TYPES))
key_name = attr.ib(validator=attr.validators.instance_of(six.string_types))
key_id = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(six.string_types)))
provider_id = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(six.string_types)))
encryption_algorithm = attr.ib(validator=attr.validators.optional(membership_validator(KNOWN_ALGORITHMS)))
padding_algorithm = attr.ib(validator=attr.validators.optional(membership_validator(KNOWN_PADDING)))
Expand Down Expand Up @@ -113,7 +117,6 @@ def from_scenario(cls, spec):
return cls(
type_name=spec["type"],
key_name=spec["key"],
key_id=spec.get("key-id"),
provider_id=spec.get("provider-id"),
encryption_algorithm=spec.get("encryption-algorithm"),
padding_algorithm=spec.get("padding-algorithm"),
Expand Down Expand Up @@ -166,19 +169,6 @@ def _wrapping_key(self, key_spec):
key_type = _RAW_ENCRYPTION_KEY_TYPE[key_spec.type_name]
return WrappingKey(wrapping_algorithm=algorithm, wrapping_key=material, wrapping_key_type=key_type)

def _raw_key_id(self):
# type: () -> str
"""Determine the key ID value if this is a raw master key.
:returns: Correct key ID
:rtype: str
:raises TypeError: if this is not a raw master key specification
"""
if not self.type_name == "raw":
raise TypeError("This is not a raw master key")

return self.key_id if self.key_id is not None else self.key_name

def _raw_master_key_from_spec(self, key_spec):
# type: (KeySpec) -> RawMasterKey
"""Build a raw master key using this specification.
Expand All @@ -192,8 +182,7 @@ def _raw_master_key_from_spec(self, key_spec):
raise TypeError("This is not a raw master key")

wrapping_key = self._wrapping_key(key_spec)
key_id = self._raw_key_id()
return RawMasterKey(provider_id=self.provider_id, key_id=key_id, wrapping_key=wrapping_key)
return RawMasterKey(provider_id=self.provider_id, key_id=key_spec.key_id, wrapping_key=wrapping_key)

def _kms_master_key_from_spec(self, key_spec):
# type: (KeySpec) -> KMSMasterKey
Expand All @@ -207,9 +196,6 @@ def _kms_master_key_from_spec(self, key_spec):
if not self.type_name == "aws-kms":
raise TypeError("This is not an AWS KMS master key")

if self.key_id is not None and self.key_id != key_spec.key_id:
raise ValueError("AWS KMS key IDs must match between master key spec and key spec")

return KMS_MASTER_KEY_PROVIDER.master_key(key_id=key_spec.key_id)

_MASTER_KEY_LOADERS = {"aws-kms": _kms_master_key_from_spec, "raw": _raw_master_key_from_spec}
Expand Down Expand Up @@ -237,7 +223,6 @@ def scenario_spec(self):
if self.type_name != "aws-kms":
spec.update(
{
"key-id": self.key_id,
"provider-id": self.provider_id,
"encryption-algorithm": self.encryption_algorithm,
"padding-algorithm": self.padding_algorithm,
Expand Down

0 comments on commit 5de76e5

Please sign in to comment.