diff --git a/kmip/core/objects.py b/kmip/core/objects.py index bb75369..3a1c566 100644 --- a/kmip/core/objects.py +++ b/kmip/core/objects.py @@ -972,18 +972,9 @@ class MACSignatureKeyInformation(primitives.Struct): class KeyWrappingData(Struct): - - class MACSignature(ByteString): - - def __init__(self, value=None): - super(KeyWrappingData.MACSignature, self).__init__( - value, Tags.MAC_SIGNATURE) - - class IVCounterNonce(ByteString): - - def __init__(self, value=None): - super(KeyWrappingData.IVCounterNonce, self).__init__( - value, Tags.IV_COUNTER_NONCE) + """ + A set of key block values needed for key wrapping functionality + """ def __init__(self, wrapping_method=None, @@ -992,73 +983,301 @@ class KeyWrappingData(Struct): mac_signature=None, iv_counter_nonce=None, encoding_option=None): + """ + Construct a KeyWrappingData struct. + + Args: + wrapping_method (WrappingMethod): An enumeration value that + specifies the method to use to wrap the key value. Optional, + defaults to None. Required for encoding and decoding. + encryption_key_information (EncryptionKeyInformation): A struct + containing the unique identifier of the encryption key and + associated cryptographic parameters. Optional, defaults to + None. + mac_signature_key_information (MACSignatureKeyInformation): A + struct containing the unique identifier of the MAC/signature + key and associated cryptographic parameters. Optional, + defaults to None. + mac_signature (bytes): Bytes containing a MAC or signature of the + key value. Optional, defaults to None. + iv_counter_nonce (bytes): Bytes containing an IV/counter/nonce + value if it is required by the wrapping method. Optional, + defaults to None. + encoding_option (EncodingOption): An enumeration value that + specifies the encoding of the key value before it is wrapped. + Optional, defaults to None. + """ super(KeyWrappingData, self).__init__(Tags.KEY_WRAPPING_DATA) + + self._wrapping_method = None + self._encryption_key_information = None + self._mac_signature_key_information = None + self._mac_signature = None + self._iv_counter_nonce = None + self._encoding_option = None + self.wrapping_method = wrapping_method self.encryption_key_information = encryption_key_information self.mac_signature_key_information = mac_signature_key_information self.mac_signature = mac_signature self.iv_counter_nonce = iv_counter_nonce self.encoding_option = encoding_option - self.validate() - def read(self, istream): - super(KeyWrappingData, self).read(istream) - tstream = BytearrayStream(istream.read(self.length)) + @property + def wrapping_method(self): + if self._wrapping_method: + return self._wrapping_method.value + else: + return None - self.wrapping_method = WrappingMethod() - self.wrapping_method.read(tstream) + @wrapping_method.setter + def wrapping_method(self, value): + if value is None: + self._wrapping_method = None + elif isinstance(value, enums.WrappingMethod): + self._wrapping_method = Enumeration( + enums.WrappingMethod, + value=value, + tag=Tags.WRAPPING_METHOD + ) + else: + raise TypeError( + "Wrapping method must be a WrappingMethod enumeration." + ) - if self.is_tag_next(Tags.ENCRYPTION_KEY_INFORMATION, tstream): - self.encryption_key_information = EncryptionKeyInformation() - self.encryption_key_information.read(tstream) + @property + def encryption_key_information(self): + return self._encryption_key_information - if self.is_tag_next(Tags.MAC_SIGNATURE_KEY_INFORMATION, tstream): - self.mac_signature_key_information = MACSignatureKeyInformation() - self.mac_signature_key_information.read(tstream) + @encryption_key_information.setter + def encryption_key_information(self, value): + if value is None: + self._encryption_key_information = None + elif isinstance(value, EncryptionKeyInformation): + self._encryption_key_information = value + else: + raise TypeError( + "Encryption key information must be an " + "EncryptionKeyInformation struct." + ) - if self.is_tag_next(Tags.MAC_SIGNATURE, tstream): - self.mac_signature = KeyWrappingData.MACSignature() - self.mac_signature.read(tstream) + @property + def mac_signature_key_information(self): + return self._mac_signature_key_information - if self.is_tag_next(Tags.IV_COUNTER_NONCE, tstream): - self.iv_counter_nonce = KeyWrappingData.IVCounterNonce() - self.iv_counter_nonce.read(tstream) + @mac_signature_key_information.setter + def mac_signature_key_information(self, value): + if value is None: + self._mac_signature_key_information = None + elif isinstance(value, MACSignatureKeyInformation): + self._mac_signature_key_information = value + else: + raise TypeError( + "MAC/signature key information must be an " + "MACSignatureKeyInformation struct." + ) - if self.is_tag_next(Tags.ENCODING_OPTION, tstream): - self.encoding_option = EncodingOption() - self.encoding_option.read(tstream) + @property + def mac_signature(self): + if self._mac_signature: + return self._mac_signature.value + else: + return None - self.is_oversized(tstream) - self.validate() + @mac_signature.setter + def mac_signature(self, value): + if value is None: + self._mac_signature = None + elif isinstance(value, six.binary_type): + self._mac_signature = primitives.ByteString( + value=value, + tag=enums.Tags.MAC_SIGNATURE + ) + else: + raise TypeError("MAC/signature must be bytes.") - def write(self, ostream): - tstream = BytearrayStream() + @property + def iv_counter_nonce(self): + if self._iv_counter_nonce: + return self._iv_counter_nonce.value + else: + return None - # Write the contents of the key wrapping data - self.wrapping_method.write(tstream) + @iv_counter_nonce.setter + def iv_counter_nonce(self, value): + if value is None: + self._iv_counter_nonce = None + elif isinstance(value, six.binary_type): + self._iv_counter_nonce = primitives.ByteString( + value=value, + tag=enums.Tags.IV_COUNTER_NONCE + ) + else: + raise TypeError("IV/counter/nonce must be bytes.") - if self.encryption_key_information is not None: - self.encryption_key_information.write(tstream) - if self.mac_signature_key_information is not None: - self.mac_signature_key_information.write(tstream) - if self.mac_signature is not None: - self.mac_signature.write(tstream) - if self.iv_counter_nonce is not None: - self.iv_counter_nonce.write(tstream) - if self.encoding_option is not None: - self.encoding_option.write(tstream) + @property + def encoding_option(self): + if self._encoding_option: + return self._encoding_option.value + else: + return None - # Write the length and value of the key wrapping data - self.length = tstream.length() - super(KeyWrappingData, self).write(ostream) - ostream.write(tstream.buffer) + @encoding_option.setter + def encoding_option(self, value): + if value is None: + self._encoding_option = None + elif isinstance(value, enums.EncodingOption): + self._encoding_option = Enumeration( + enums.EncodingOption, + value=value, + tag=Tags.ENCODING_OPTION + ) + else: + raise TypeError( + "Encoding option must be an EncodingOption enumeration." + ) - def validate(self): - self.__validate() + def read(self, input_stream): + """ + Read the data encoding the KeyWrappingData struct and decode it into + its constituent parts. - def __validate(self): - # TODO (peter-hamilton) Finish implementation - pass + Args: + input_stream (stream): A data stream containing encoded object + data, supporting a read method; usually a BytearrayStream + object. + """ + super(KeyWrappingData, self).read(input_stream) + local_stream = BytearrayStream(input_stream.read(self.length)) + + if self.is_tag_next(enums.Tags.WRAPPING_METHOD, local_stream): + self._wrapping_method = primitives.Enumeration( + enum=enums.WrappingMethod, + tag=enums.Tags.WRAPPING_METHOD + ) + self._wrapping_method.read(local_stream) + else: + raise ValueError( + "Invalid struct missing the wrapping method attribute." + ) + + if self.is_tag_next( + enums.Tags.ENCRYPTION_KEY_INFORMATION, + local_stream + ): + self._encryption_key_information = EncryptionKeyInformation() + self._encryption_key_information.read(local_stream) + if self.is_tag_next( + enums.Tags.MAC_SIGNATURE_KEY_INFORMATION, + local_stream + ): + self._mac_signature_key_information = MACSignatureKeyInformation() + self._mac_signature_key_information.read(local_stream) + + if self.is_tag_next(enums.Tags.MAC_SIGNATURE, local_stream): + self._mac_signature = primitives.ByteString( + tag=enums.Tags.MAC_SIGNATURE + ) + self._mac_signature.read(local_stream) + + if self.is_tag_next(enums.Tags.IV_COUNTER_NONCE, local_stream): + self._iv_counter_nonce = primitives.ByteString( + tag=enums.Tags.IV_COUNTER_NONCE + ) + self._iv_counter_nonce.read(local_stream) + + if self.is_tag_next(enums.Tags.ENCODING_OPTION, local_stream): + self._encoding_option = primitives.Enumeration( + enum=enums.EncodingOption, + tag=enums.Tags.ENCODING_OPTION + ) + self._encoding_option.read(local_stream) + + self.is_oversized(local_stream) + + def write(self, output_stream): + """ + Write the data encoding the KeyWrappingData struct to a stream. + + Args: + output_stream (stream): A data stream in which to encode object + data, supporting a write method; usually a BytearrayStream + object. + """ + local_stream = BytearrayStream() + + if self._wrapping_method: + self._wrapping_method.write(local_stream) + else: + raise ValueError( + "Invalid struct missing the wrapping method attribute." + ) + + if self._encryption_key_information: + self._encryption_key_information.write(local_stream) + if self._mac_signature_key_information: + self._mac_signature_key_information.write(local_stream) + if self._mac_signature: + self._mac_signature.write(local_stream) + if self._iv_counter_nonce: + self._iv_counter_nonce.write(local_stream) + if self._encoding_option: + self._encoding_option.write(local_stream) + + self.length = local_stream.length() + super(KeyWrappingData, self).write(output_stream) + output_stream.write(local_stream.buffer) + + def __eq__(self, other): + if isinstance(other, KeyWrappingData): + if self.wrapping_method != other.wrapping_method: + return False + elif self.encryption_key_information != \ + other.encryption_key_information: + return False + elif self.mac_signature_key_information != \ + other.mac_signature_key_information: + return False + elif self.mac_signature != other.mac_signature: + return False + elif self.iv_counter_nonce != other.iv_counter_nonce: + return False + elif self.encoding_option != other.encoding_option: + return False + else: + return True + + def __ne__(self, other): + if isinstance(other, KeyWrappingData): + return not self == other + else: + return NotImplemented + + def __repr__(self): + args = ", ".join([ + "wrapping_method={0}".format(self.wrapping_method), + "encryption_key_information={0}".format( + repr(self.encryption_key_information) + ), + "mac_signature_key_information={0}".format( + repr(self.mac_signature_key_information) + ), + "mac_signature={0}".format(self.mac_signature), + "iv_counter_nonce={0}".format(self.iv_counter_nonce), + "encoding_option={0}".format(self.encoding_option) + ]) + return "KeyWrappingData({0})".format(args) + + def __str__(self): + return str({ + 'wrapping_method': self.wrapping_method, + 'encryption_key_information': self.encryption_key_information, + 'mac_signature_key_information': + self.mac_signature_key_information, + 'mac_signature': self.mac_signature, + 'iv_counter_nonce': self.iv_counter_nonce, + 'encoding_option': self.encoding_option + }) class KeyWrappingSpecification(primitives.Struct): diff --git a/kmip/tests/unit/core/objects/test_objects.py b/kmip/tests/unit/core/objects/test_objects.py index 416689a..84afab2 100644 --- a/kmip/tests/unit/core/objects/test_objects.py +++ b/kmip/tests/unit/core/objects/test_objects.py @@ -1206,6 +1206,950 @@ class TestMACSignatureKeyInformation(testtools.TestCase): self.assertEqual(expected, observed) +class TestKeyWrappingData(testtools.TestCase): + """ + Test suite for the KeyWrappingData struct. + """ + + def setUp(self): + super(TestKeyWrappingData, self).setUp() + + # Encoding obtained in part from the KMIP 1.1 testing document, + # Sections 14.1. The rest was built by hand. + # + # This encoding matches the following set of values: + # + # Wrapping Method - ENCRYPT + # Encryption Key Information + # Unique Identifier - 100182d5-72b8-47aa-8383-4d97d512e98a + # Cryptographic Parameters + # Block Cipher Mode - NIST_KEY_WRAP + # MAC/Signature Key Information + # Unique Identifier - 100182d5-72b8-47aa-8383-4d97d512e98a + # Cryptographic Parameters + # Block Cipher Mode - NIST_KEY_WRAP + # MAC/Signature - 0x0123456789ABCDEF + # IV/Counter/Nonce - 0x01 + # Encoding Option - NO_ENCODING + + self.full_encoding = BytearrayStream( + b'\x42\x00\x46\x01\x00\x00\x00\xE0' + b'\x42\x00\x9E\x05\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00' + b'\x42\x00\x36\x01\x00\x00\x00\x48' + b'\x42\x00\x94\x07\x00\x00\x00\x24' + b'\x31\x30\x30\x31\x38\x32\x64\x35\x2D\x37\x32\x62\x38\x2D\x34\x37' + b'\x61\x61\x2D\x38\x33\x38\x33\x2D\x34\x64\x39\x37\x64\x35\x31\x32' + b'\x65\x39\x38\x61\x00\x00\x00\x00' + b'\x42\x00\x2B\x01\x00\x00\x00\x10' + b'\x42\x00\x11\x05\x00\x00\x00\x04\x00\x00\x00\x0D\x00\x00\x00\x00' + b'\x42\x00\x4E\x01\x00\x00\x00\x48' + b'\x42\x00\x94\x07\x00\x00\x00\x24' + b'\x31\x30\x30\x31\x38\x32\x64\x35\x2D\x37\x32\x62\x38\x2D\x34\x37' + b'\x61\x61\x2D\x38\x33\x38\x33\x2D\x34\x64\x39\x37\x64\x35\x31\x32' + b'\x65\x39\x38\x61\x00\x00\x00\x00' + b'\x42\x00\x2B\x01\x00\x00\x00\x10' + b'\x42\x00\x11\x05\x00\x00\x00\x04\x00\x00\x00\x0D\x00\x00\x00\x00' + b'\x42\x00\x4D\x08\x00\x00\x00\x08\x01\x23\x45\x67\x89\xAB\xCD\xEF' + b'\x42\x00\x3D\x08\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00' + b'\x42\x00\xA3\x05\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00' + ) + + # Encoding obtained from the KMIP 1.1 testing document, Section 14.1. + # This encoding matches the following set of values: + # + # Wrapping Method - ENCRYPT + # Encryption Key Information + # Unique Identifier - 100182d5-72b8-47aa-8383-4d97d512e98a + # Cryptographic Parameters + # Block Cipher Mode - NIST_KEY_WRAP + # Encoding Option - NO_ENCODING + + self.partial_encoding = BytearrayStream( + b'\x42\x00\x46\x01\x00\x00\x00\x70' + b'\x42\x00\x9E\x05\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00' + b'\x42\x00\x36\x01\x00\x00\x00\x48' + b'\x42\x00\x94\x07\x00\x00\x00\x24' + b'\x31\x30\x30\x31\x38\x32\x64\x35\x2D\x37\x32\x62\x38\x2D\x34\x37' + b'\x61\x61\x2D\x38\x33\x38\x33\x2D\x34\x64\x39\x37\x64\x35\x31\x32' + b'\x65\x39\x38\x61\x00\x00\x00\x00' + b'\x42\x00\x2B\x01\x00\x00\x00\x10' + b'\x42\x00\x11\x05\x00\x00\x00\x04\x00\x00\x00\x0D\x00\x00\x00\x00' + b'\x42\x00\xA3\x05\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00' + ) + + self.empty_encoding = BytearrayStream( + b'\x42\x00\x46\x01\x00\x00\x00\x00' + ) + + def tearDown(self): + super(TestKeyWrappingData, self).tearDown() + + def test_init(self): + """ + Test that a KeyWrappingData struct can be constructed with no + arguments. + """ + key_wrapping_data = objects.KeyWrappingData() + + self.assertEqual(None, key_wrapping_data.wrapping_method) + self.assertEqual(None, key_wrapping_data.encryption_key_information) + self.assertEqual(None, key_wrapping_data.mac_signature_key_information) + self.assertEqual(None, key_wrapping_data.mac_signature) + self.assertEqual(None, key_wrapping_data.iv_counter_nonce) + self.assertEqual(None, key_wrapping_data.encoding_option) + + def test_init_with_args(self): + """ + Test that a KeyWrappingData struct can be constructed with valid + values. + """ + key_wrapping_data = objects.KeyWrappingData( + wrapping_method=enums.WrappingMethod.ENCRYPT, + encryption_key_information=objects.EncryptionKeyInformation( + unique_identifier="12345678-9012-3456-7890-123456789012", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CTR + ) + ), + mac_signature_key_information=objects.MACSignatureKeyInformation( + unique_identifier="00000000-1111-2222-3333-444444444444", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + mac_signature=b'\x01', + iv_counter_nonce=b'\x02', + encoding_option=enums.EncodingOption.TTLV_ENCODING + ) + + self.assertEqual( + enums.WrappingMethod.ENCRYPT, + key_wrapping_data.wrapping_method + ) + self.assertIsInstance( + key_wrapping_data.encryption_key_information, + objects.EncryptionKeyInformation + ) + e = key_wrapping_data.encryption_key_information + self.assertEqual( + "12345678-9012-3456-7890-123456789012", + e.unique_identifier + ) + self.assertIsInstance( + e.cryptographic_parameters, + attributes.CryptographicParameters + ) + self.assertEqual( + enums.BlockCipherMode.CTR, + e.cryptographic_parameters.block_cipher_mode + ) + self.assertIsInstance( + key_wrapping_data.mac_signature_key_information, + objects.MACSignatureKeyInformation + ) + m = key_wrapping_data.mac_signature_key_information + self.assertEqual( + "00000000-1111-2222-3333-444444444444", + m.unique_identifier + ) + self.assertIsInstance( + m.cryptographic_parameters, + attributes.CryptographicParameters + ) + self.assertEqual( + enums.BlockCipherMode.NIST_KEY_WRAP, + m.cryptographic_parameters.block_cipher_mode + ) + self.assertEqual(b'\x01', key_wrapping_data.mac_signature) + self.assertEqual(b'\x02', key_wrapping_data.iv_counter_nonce) + self.assertEqual( + enums.EncodingOption.TTLV_ENCODING, + key_wrapping_data.encoding_option + ) + + def test_invalid_wrapping_method(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the wrapping method of a KeyWrappingData struct. + """ + kwargs = {'wrapping_method': 'invalid'} + self.assertRaisesRegexp( + TypeError, + "Wrapping method must be a WrappingMethod enumeration.", + objects.KeyWrappingData, + **kwargs + ) + + args = (objects.KeyWrappingData(), 'wrapping_method', 0) + self.assertRaisesRegexp( + TypeError, + "Wrapping method must be a WrappingMethod enumeration.", + setattr, + *args + ) + + def test_invalid_encryption_key_information(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the encryption key information of a KeyWrappingData struct. + """ + kwargs = {'encryption_key_information': 'invalid'} + self.assertRaisesRegexp( + TypeError, + "Encryption key information must be an EncryptionKeyInformation " + "struct.", + objects.KeyWrappingData, + **kwargs + ) + + args = ( + objects.KeyWrappingData(), + 'encryption_key_information', + 'invalid' + ) + self.assertRaisesRegexp( + TypeError, + "Encryption key information must be an EncryptionKeyInformation " + "struct.", + setattr, + *args + ) + + def test_invalid_mac_signature_key_information(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the MAC/signature key information of a KeyWrappingData struct. + """ + kwargs = {'mac_signature_key_information': 'invalid'} + self.assertRaisesRegexp( + TypeError, + "MAC/signature key information must be an " + "MACSignatureKeyInformation struct.", + objects.KeyWrappingData, + **kwargs + ) + + args = ( + objects.KeyWrappingData(), + 'mac_signature_key_information', + 'invalid' + ) + self.assertRaisesRegexp( + TypeError, + "MAC/signature key information must be an " + "MACSignatureKeyInformation struct.", + setattr, + *args + ) + + def test_invalid_mac_signature(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the MAC/signature of a KeyWrappingData struct. + """ + kwargs = {'mac_signature': 0} + self.assertRaisesRegexp( + TypeError, + "MAC/signature must be bytes.", + objects.KeyWrappingData, + **kwargs + ) + + args = ( + objects.KeyWrappingData(), + 'mac_signature', + 0 + ) + self.assertRaisesRegexp( + TypeError, + "MAC/signature must be bytes.", + setattr, + *args + ) + + def test_invalid_iv_counter_nonce(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the IV/counter/nonce of a KeyWrappingData struct. + """ + kwargs = {'iv_counter_nonce': 0} + self.assertRaisesRegexp( + TypeError, + "IV/counter/nonce must be bytes.", + objects.KeyWrappingData, + **kwargs + ) + + args = ( + objects.KeyWrappingData(), + 'iv_counter_nonce', + 0 + ) + self.assertRaisesRegexp( + TypeError, + "IV/counter/nonce must be bytes.", + setattr, + *args + ) + + def test_invalid_encoding_option(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the encoding option of a KeyWrappingData struct. + """ + kwargs = {'encoding_option': 'invalid'} + self.assertRaisesRegexp( + TypeError, + "Encoding option must be an EncodingOption enumeration.", + objects.KeyWrappingData, + **kwargs + ) + + args = ( + objects.KeyWrappingData(), + 'encoding_option', + 'invalid' + ) + self.assertRaisesRegexp( + TypeError, + "Encoding option must be an EncodingOption enumeration.", + setattr, + *args + ) + + def test_read(self): + """ + Test that a KeyWrappingData struct can be read from a data stream. + """ + key_wrapping_data = objects.KeyWrappingData() + + self.assertEqual(None, key_wrapping_data.wrapping_method) + self.assertEqual(None, key_wrapping_data.encryption_key_information) + self.assertEqual(None, key_wrapping_data.mac_signature_key_information) + self.assertEqual(None, key_wrapping_data.mac_signature) + self.assertEqual(None, key_wrapping_data.iv_counter_nonce) + self.assertEqual(None, key_wrapping_data.encoding_option) + + key_wrapping_data.read(self.full_encoding) + + self.assertEqual( + enums.WrappingMethod.ENCRYPT, + key_wrapping_data.wrapping_method + ) + self.assertIsInstance( + key_wrapping_data.encryption_key_information, + objects.EncryptionKeyInformation + ) + e = key_wrapping_data.encryption_key_information + self.assertEqual( + "100182d5-72b8-47aa-8383-4d97d512e98a", + e.unique_identifier + ) + self.assertIsInstance( + e.cryptographic_parameters, + attributes.CryptographicParameters + ) + self.assertEqual( + enums.BlockCipherMode.NIST_KEY_WRAP, + e.cryptographic_parameters.block_cipher_mode + ) + self.assertIsInstance( + key_wrapping_data.mac_signature_key_information, + objects.MACSignatureKeyInformation + ) + m = key_wrapping_data.mac_signature_key_information + self.assertEqual( + "100182d5-72b8-47aa-8383-4d97d512e98a", + m.unique_identifier + ) + self.assertIsInstance( + m.cryptographic_parameters, + attributes.CryptographicParameters + ) + self.assertEqual( + enums.BlockCipherMode.NIST_KEY_WRAP, + m.cryptographic_parameters.block_cipher_mode + ) + self.assertEqual( + b'\x01\x23\x45\x67\x89\xAB\xCD\xEF', + key_wrapping_data.mac_signature + ) + self.assertEqual( + b'\x01', + key_wrapping_data.iv_counter_nonce + ) + self.assertEqual( + enums.EncodingOption.NO_ENCODING, + key_wrapping_data.encoding_option + ) + + def test_read_partial(self): + """ + Test that a KeyWrappingData struct can be read from a partial data + stream. + """ + key_wrapping_data = objects.KeyWrappingData() + + self.assertEqual(None, key_wrapping_data.wrapping_method) + self.assertEqual(None, key_wrapping_data.encryption_key_information) + self.assertEqual(None, key_wrapping_data.mac_signature_key_information) + self.assertEqual(None, key_wrapping_data.mac_signature) + self.assertEqual(None, key_wrapping_data.iv_counter_nonce) + self.assertEqual(None, key_wrapping_data.encoding_option) + + key_wrapping_data.read(self.partial_encoding) + + self.assertEqual( + enums.WrappingMethod.ENCRYPT, + key_wrapping_data.wrapping_method + ) + self.assertIsInstance( + key_wrapping_data.encryption_key_information, + objects.EncryptionKeyInformation + ) + e = key_wrapping_data.encryption_key_information + self.assertEqual( + "100182d5-72b8-47aa-8383-4d97d512e98a", + e.unique_identifier + ) + self.assertIsInstance( + e.cryptographic_parameters, + attributes.CryptographicParameters + ) + self.assertEqual( + enums.BlockCipherMode.NIST_KEY_WRAP, + e.cryptographic_parameters.block_cipher_mode + ) + self.assertIsNone(key_wrapping_data.mac_signature_key_information) + self.assertIsNone(key_wrapping_data.mac_signature) + self.assertIsNone(key_wrapping_data.iv_counter_nonce) + self.assertEqual( + enums.EncodingOption.NO_ENCODING, + key_wrapping_data.encoding_option + ) + + def test_read_invalid(self): + """ + Test that a ValueError gets raised when a required KeyWrappingData + field is missing from the struct encoding. + """ + key_wrapping_data = objects.KeyWrappingData() + args = (self.empty_encoding,) + self.assertRaisesRegexp( + ValueError, + "Invalid struct missing the wrapping method attribute.", + key_wrapping_data.read, + *args + ) + + def test_write(self): + """ + Test that a KeyWrappingData struct can be written to a data stream. + """ + key_wrapping_data = objects.KeyWrappingData( + wrapping_method=enums.WrappingMethod.ENCRYPT, + encryption_key_information=objects.EncryptionKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + mac_signature_key_information=objects.MACSignatureKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + mac_signature=b'\x01\x23\x45\x67\x89\xAB\xCD\xEF', + iv_counter_nonce=b'\x01', + encoding_option=enums.EncodingOption.NO_ENCODING + ) + stream = BytearrayStream() + key_wrapping_data.write(stream) + + self.assertEqual(len(self.full_encoding), len(stream)) + self.assertEqual(str(self.full_encoding), str(stream)) + + def test_write_partial(self): + """ + Test that a partially defined KeyWrappingData struct can be written to + a data stream. + """ + key_wrapping_data = objects.KeyWrappingData( + wrapping_method=enums.WrappingMethod.ENCRYPT, + encryption_key_information=objects.EncryptionKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + encoding_option=enums.EncodingOption.NO_ENCODING + ) + stream = BytearrayStream() + key_wrapping_data.write(stream) + + self.assertEqual(len(self.partial_encoding), len(stream)) + self.assertEqual(str(self.partial_encoding), str(stream)) + + def test_write_invalid(self): + """ + Test that a ValueError gets raised when a required KeyWrappingData + field is missing when encoding the struct. + """ + key_wrapping_data = objects.KeyWrappingData() + stream = utils.BytearrayStream() + args = (stream,) + self.assertRaisesRegexp( + ValueError, + "Invalid struct missing the wrapping method attribute.", + key_wrapping_data.write, + *args + ) + + def test_equal_on_equal(self): + """ + Test that the equality operator returns True when comparing two + KeyWrappingData structs with the same data. + """ + a = objects.KeyWrappingData() + b = objects.KeyWrappingData() + + self.assertTrue(a == b) + self.assertTrue(b == a) + + a = objects.KeyWrappingData( + wrapping_method=enums.WrappingMethod.ENCRYPT, + encryption_key_information=objects.EncryptionKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + mac_signature_key_information=objects.MACSignatureKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + mac_signature=b'\x01\x01\x01\x01\x01\x01\x01\x01', + iv_counter_nonce=b'\x01', + encoding_option=enums.EncodingOption.NO_ENCODING + ) + b = objects.KeyWrappingData( + wrapping_method=enums.WrappingMethod.ENCRYPT, + encryption_key_information=objects.EncryptionKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + mac_signature_key_information=objects.MACSignatureKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + mac_signature=b'\x01\x01\x01\x01\x01\x01\x01\x01', + iv_counter_nonce=b'\x01', + encoding_option=enums.EncodingOption.NO_ENCODING + ) + + self.assertTrue(a == b) + self.assertTrue(b == a) + + def test_equal_on_not_equal_wrapping_method(self): + """ + Test that the equality operator returns False when comparing two + KeyWrappingData structs with different wrapping methods. + """ + a = objects.KeyWrappingData( + wrapping_method=enums.WrappingMethod.ENCRYPT + ) + b = objects.KeyWrappingData( + wrapping_method=enums.WrappingMethod.MAC_SIGN + ) + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_encryption_key_information(self): + """ + Test that the equality operator returns False when comparing two + KeyWrappingData structs with different encryption key information. + """ + a = objects.KeyWrappingData( + encryption_key_information=objects.EncryptionKeyInformation( + unique_identifier="100182d5-72b8-ffff-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC + ) + ) + ) + b = objects.KeyWrappingData( + encryption_key_information=objects.EncryptionKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ) + ) + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_mac_signature_key_information(self): + """ + Test that the equality operator returns False when comparing two + KeyWrappingData structs with different MAC/signature key information. + """ + a = objects.KeyWrappingData( + mac_signature_key_information=objects.MACSignatureKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ) + ) + b = objects.KeyWrappingData( + mac_signature_key_information=objects.MACSignatureKeyInformation( + unique_identifier="100182d5-72b8-ffff-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC + ) + ) + ) + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_mac_signatures(self): + """ + Test that the equality operator returns False when comparing two + KeyWrappingData structs with different MAC/signatures. + """ + a = objects.KeyWrappingData(mac_signature=b'\x01') + b = objects.KeyWrappingData(mac_signature=b'\x10') + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_iv_counter_nonce(self): + """ + Test that the equality operator returns False when comparing two + KeyWrappingData structs with different IV/counter/nonces. + """ + a = objects.KeyWrappingData(iv_counter_nonce=b'\x01') + b = objects.KeyWrappingData(iv_counter_nonce=b'\x10') + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_encoding_option(self): + """ + Test that the equality operator returns False when comparing two + KeyWrappingData structs with different encoding options. + """ + a = objects.KeyWrappingData( + encoding_option=enums.EncodingOption.NO_ENCODING + ) + b = objects.KeyWrappingData( + encoding_option=enums.EncodingOption.TTLV_ENCODING + ) + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_type_mismatch(self): + """ + Test that the equality operator returns False when comparing two + KeyWrappingData structs with different types. + """ + a = objects.KeyWrappingData() + b = 'invalid' + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_not_equal_on_equal(self): + """ + Test that the inequality operator returns False when comparing two + KeyWrappingData structs with the same data. + """ + a = objects.KeyWrappingData() + b = objects.KeyWrappingData() + + self.assertFalse(a != b) + self.assertFalse(b != a) + + a = objects.KeyWrappingData( + wrapping_method=enums.WrappingMethod.ENCRYPT, + encryption_key_information=objects.EncryptionKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + mac_signature_key_information=objects.MACSignatureKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + mac_signature=b'\x01\x01\x01\x01\x01\x01\x01\x01', + iv_counter_nonce=b'\x01', + encoding_option=enums.EncodingOption.NO_ENCODING + ) + b = objects.KeyWrappingData( + wrapping_method=enums.WrappingMethod.ENCRYPT, + encryption_key_information=objects.EncryptionKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + mac_signature_key_information=objects.MACSignatureKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + mac_signature=b'\x01\x01\x01\x01\x01\x01\x01\x01', + iv_counter_nonce=b'\x01', + encoding_option=enums.EncodingOption.NO_ENCODING + ) + + self.assertFalse(a != b) + self.assertFalse(b != a) + + def test_not_equal_on_not_equal_wrapping_method(self): + """ + Test that the inequality operator returns True when comparing two + KeyWrappingData structs with different wrapping methods. + """ + a = objects.KeyWrappingData( + wrapping_method=enums.WrappingMethod.ENCRYPT + ) + b = objects.KeyWrappingData( + wrapping_method=enums.WrappingMethod.MAC_SIGN + ) + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_encryption_key_information(self): + """ + Test that the inequality operator returns True when comparing two + KeyWrappingData structs with different encryption key information. + """ + a = objects.KeyWrappingData( + encryption_key_information=objects.EncryptionKeyInformation( + unique_identifier="100182d5-72b8-ffff-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC + ) + ) + ) + b = objects.KeyWrappingData( + encryption_key_information=objects.EncryptionKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ) + ) + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_mac_signature_key_information(self): + """ + Test that the inequality operator returns True when comparing two + KeyWrappingData structs with different MAC/signature key information. + """ + a = objects.KeyWrappingData( + mac_signature_key_information=objects.MACSignatureKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ) + ) + b = objects.KeyWrappingData( + mac_signature_key_information=objects.MACSignatureKeyInformation( + unique_identifier="100182d5-72b8-ffff-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC + ) + ) + ) + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_mac_signatures(self): + """ + Test that the inequality operator returns True when comparing two + KeyWrappingData structs with different MAC/signatures. + """ + a = objects.KeyWrappingData(mac_signature=b'\x01') + b = objects.KeyWrappingData(mac_signature=b'\x10') + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_iv_counter_nonce(self): + """ + Test that the inequality operator returns True when comparing two + KeyWrappingData structs with different IV/counter/nonces. + """ + a = objects.KeyWrappingData(iv_counter_nonce=b'\x01') + b = objects.KeyWrappingData(iv_counter_nonce=b'\x10') + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_encoding_option(self): + """ + Test that the inequality operator returns True when comparing two + KeyWrappingData structs with different encoding options. + """ + a = objects.KeyWrappingData( + encoding_option=enums.EncodingOption.NO_ENCODING + ) + b = objects.KeyWrappingData( + encoding_option=enums.EncodingOption.TTLV_ENCODING + ) + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_type_mismatch(self): + """ + Test that the inequality operator returns True when comparing two + KeyWrappingData structs with different types. + """ + a = objects.KeyWrappingData() + b = 'invalid' + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_repr(self): + """ + Test that repr can be applied to an KeyWrappingData struct. + """ + key_wrapping_data = objects.KeyWrappingData( + wrapping_method=enums.WrappingMethod.ENCRYPT, + encryption_key_information=objects.EncryptionKeyInformation( + unique_identifier="100182d5-72b8-ffff-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + mac_signature_key_information=objects.MACSignatureKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC + ) + ), + mac_signature=b'\x01\x01\x02\x02\x03\x03\x04\x04', + iv_counter_nonce=b'\xFF', + encoding_option=enums.EncodingOption.TTLV_ENCODING + ) + + expected = ( + "KeyWrappingData(" + "wrapping_method=WrappingMethod.ENCRYPT, " + "encryption_key_information=EncryptionKeyInformation(" + "unique_identifier='100182d5-72b8-ffff-8383-4d97d512e98a', " + "cryptographic_parameters=CryptographicParameters(" + "block_cipher_mode=BlockCipherMode.NIST_KEY_WRAP, " + "padding_method=None, " + "hashing_algorithm=None, " + "key_role_type=None, " + "digital_signature_algorithm=None, " + "cryptographic_algorithm=None, " + "random_iv=None, " + "iv_length=None, " + "tag_length=None, " + "fixed_field_length=None, " + "invocation_field_length=None, " + "counter_length=None, " + "initial_counter_value=None)), " + "mac_signature_key_information=MACSignatureKeyInformation(" + "unique_identifier='100182d5-72b8-47aa-8383-4d97d512e98a', " + "cryptographic_parameters=CryptographicParameters(" + "block_cipher_mode=BlockCipherMode.CBC, " + "padding_method=None, " + "hashing_algorithm=None, " + "key_role_type=None, " + "digital_signature_algorithm=None, " + "cryptographic_algorithm=None, " + "random_iv=None, " + "iv_length=None, " + "tag_length=None, " + "fixed_field_length=None, " + "invocation_field_length=None, " + "counter_length=None, " + "initial_counter_value=None)), " + "mac_signature={0}, " + "iv_counter_nonce={1}, " + "encoding_option=EncodingOption.TTLV_ENCODING)".format( + b'\x01\x01\x02\x02\x03\x03\x04\x04', + b'\xFF' + ) + ) + observed = repr(key_wrapping_data) + + self.assertEqual(expected, observed) + + def test_str(self): + """ + Test that str can be applied to a KeyWrappingData struct. + """ + key_wrapping_data = objects.KeyWrappingData( + wrapping_method=enums.WrappingMethod.ENCRYPT, + encryption_key_information=objects.EncryptionKeyInformation( + unique_identifier="100182d5-72b8-ffff-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + mac_signature_key_information=objects.MACSignatureKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC + ) + ), + mac_signature=b'\x01\x01\x02\x02\x03\x03\x04\x04', + iv_counter_nonce=b'\xFF', + encoding_option=enums.EncodingOption.TTLV_ENCODING + ) + + expected = str({ + 'wrapping_method': enums.WrappingMethod.ENCRYPT, + 'encryption_key_information': objects.EncryptionKeyInformation( + unique_identifier="100182d5-72b8-ffff-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.NIST_KEY_WRAP + ) + ), + 'mac_signature_key_information': + objects.MACSignatureKeyInformation( + unique_identifier="100182d5-72b8-47aa-8383-4d97d512e98a", + cryptographic_parameters=attributes.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC + ) + ), + 'mac_signature': b'\x01\x01\x02\x02\x03\x03\x04\x04', + 'iv_counter_nonce': b'\xFF', + 'encoding_option': enums.EncodingOption.TTLV_ENCODING + }) + observed = str(key_wrapping_data) + + self.assertEqual(expected, observed) + + class TestKeyWrappingSpecification(testtools.TestCase): """ Test suite for the KeyWrappingSpecification struct.