diff --git a/kmip/pie/factory.py b/kmip/pie/factory.py index efb87fa..36401c6 100644 --- a/kmip/pie/factory.py +++ b/kmip/pie/factory.py @@ -85,9 +85,17 @@ class ObjectFactory: length = key.key_block.cryptographic_length.value value = key.key_block.key_value.key_material.value format_type = key.key_block.key_format_type.value + key_wrapping_data = key.key_block.key_wrapping_data if cls is pobjects.SymmetricKey: - key = cls(algorithm, length, value) + key = cls( + algorithm, + length, + value, + key_wrapping_data=self._build_key_wrapping_data( + key_wrapping_data + ) + ) if key.key_format_type != format_type: raise TypeError( "core key format type not compatible with Pie " @@ -96,7 +104,15 @@ class ObjectFactory: else: return key else: - return cls(algorithm, length, value, format_type) + return cls( + algorithm, + length, + value, + format_type, + key_wrapping_data=self._build_key_wrapping_data( + key_wrapping_data + ) + ) def _build_pie_secret_data(self, secret): secret_data_type = secret.secret_data_type.value @@ -117,6 +133,11 @@ class ObjectFactory: key_material = cobjects.KeyMaterial(value) key_value = cobjects.KeyValue(key_material) + key_wrapping_data = None + if key.key_wrapping_data: + key_wrapping_data = cobjects.KeyWrappingData( + **key.key_wrapping_data + ) key_block = cobjects.KeyBlock( key_format_type=misc.KeyFormatType(format_type), key_compression_type=None, @@ -124,7 +145,8 @@ class ObjectFactory: cryptographic_algorithm=attributes.CryptographicAlgorithm( algorithm), cryptographic_length=attributes.CryptographicLength(length), - key_wrapping_data=None) + key_wrapping_data=key_wrapping_data + ) return cls(key_block) @@ -155,3 +177,54 @@ class ObjectFactory: opaque_data_type = secrets.OpaqueObject.OpaqueDataType(opaque_type) opaque_data_value = secrets.OpaqueObject.OpaqueDataValue(value) return secrets.OpaqueObject(opaque_data_type, opaque_data_value) + + def _build_cryptographic_parameters(self, value): + cryptographic_parameters = { + 'block_cipher_mode': value.block_cipher_mode, + 'padding_method': value.padding_method, + 'hashing_algorithm': value.hashing_algorithm, + 'key_role_type': value.key_role_type, + 'digital_signature_algorithm': value.digital_signature_algorithm, + 'cryptographic_algorithm': value.cryptographic_algorithm, + 'random_iv': value.random_iv, + 'iv_length': value.iv_length, + 'tag_length': value.tag_length, + 'fixed_field_length': value.fixed_field_length, + 'invocation_field_length': value.invocation_field_length, + 'counter_length': value.counter_length, + 'initial_counter_value': value.initial_counter_value + } + return cryptographic_parameters + + def _build_key_wrapping_data(self, value): + if value is None: + return None + encryption_key_info = value.encryption_key_information + encryption_key_information = {} + if encryption_key_info: + encryption_key_information = { + 'unique_identifier': encryption_key_info.unique_identifier, + 'cryptographic_parameters': + self._build_cryptographic_parameters( + encryption_key_info.cryptographic_parameters + ) + } + mac_signature_key_info = value.mac_signature_key_information + mac_signature_key_information = {} + if mac_signature_key_info: + mac_signature_key_information = { + 'unique_identifier': mac_signature_key_info.unique_identifier, + 'cryptographic_parameters': + self._build_cryptographic_parameters( + mac_signature_key_info.cryptographic_parameters + ) + } + key_wrapping_data = { + 'wrapping_method': value.wrapping_method, + 'encryption_key_information': encryption_key_information, + 'mac_signature_key_information': mac_signature_key_information, + 'mac_signature': value.mac_signature, + 'iv_counter_nonce': value.iv_counter_nonce, + 'encoding_option': value.encoding_option + } + return key_wrapping_data diff --git a/kmip/pie/objects.py b/kmip/pie/objects.py index 6c4f547..f12baa8 100644 --- a/kmip/pie/objects.py +++ b/kmip/pie/objects.py @@ -15,6 +15,7 @@ from abc import abstractmethod from sqlalchemy import Column, event, ForeignKey, Integer, String, VARBINARY +from sqlalchemy import Boolean from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.orm import relationship @@ -212,6 +213,8 @@ class Key(CryptographicObject): cryptographic_length: An int defining the length of the key in bits. key_format_type: A KeyFormatType enumeration defining the format of the key value. + key_wrapping_data: A dictionary containing key wrapping data + settings, describing how the key value has been wrapped. """ __tablename__ = 'keys' @@ -224,6 +227,167 @@ class Key(CryptographicObject): key_format_type = Column( 'key_format_type', sql.EnumType(enums.KeyFormatType)) + # Key wrapping data fields + _kdw_wrapping_method = Column( + '_kdw_wrapping_method', + sql.EnumType(enums.WrappingMethod), + default=None + ) + _kdw_eki_unique_identifier = Column( + '_kdw_eki_unique_identifier', + String, + default=None + ) + _kdw_eki_cp_block_cipher_mode = Column( + '_kdw_eki_cp_block_cipher_mode', + sql.EnumType(enums.BlockCipherMode), + default=None + ) + _kdw_eki_cp_padding_method = Column( + '_kdw_eki_cp_padding_method', + sql.EnumType(enums.PaddingMethod), + default=None + ) + _kdw_eki_cp_hashing_algorithm = Column( + '_kdw_eki_cp_hashing_algorithm', + sql.EnumType(enums.HashingAlgorithm), + default=None + ) + _kdw_eki_cp_key_role_type = Column( + '_kdw_eki_cp_key_role_type', + sql.EnumType(enums.KeyRoleType), + default=None + ) + _kdw_eki_cp_digital_signature_algorithm = Column( + '_kdw_eki_cp_digital_signature_algorithm', + sql.EnumType(enums.DigitalSignatureAlgorithm), + default=None + ) + _kdw_eki_cp_cryptographic_algorithm = Column( + '_kdw_eki_cp_cryptographic_algorithm', + sql.EnumType(enums.CryptographicAlgorithm), + default=None + ) + _kdw_eki_cp_random_iv = Column( + '_kdw_eki_cp_random_iv', + Boolean, + default=None + ) + _kdw_eki_cp_iv_length = Column( + '_kdw_eki_cp_iv_length', + Integer, + default=None + ) + _kdw_eki_cp_tag_length = Column( + '_kdw_eki_cp_tag_length', + Integer, + default=None + ) + _kdw_eki_cp_fixed_field_length = Column( + '_kdw_eki_cp_fixed_field_length', + Integer, + default=None + ) + _kdw_eki_cp_invocation_field_length = Column( + '_kdw_eki_cp_invocation_field_length', + Integer + ) + _kdw_eki_cp_counter_length = Column( + '_kdw_eki_cp_counter_length', + Integer, + default=None + ) + _kdw_eki_cp_initial_counter_value = Column( + '_kdw_eki_cp_initial_counter_value', + Integer, + default=None + ) + _kdw_mski_unique_identifier = Column( + '_kdw_mski_unique_identifier', + String, + default=None + ) + _kdw_mski_cp_block_cipher_mode = Column( + '_kdw_mski_cp_block_cipher_mode', + sql.EnumType(enums.BlockCipherMode), + default=None + ) + _kdw_mski_cp_padding_method = Column( + '_kdw_mski_cp_padding_method', + sql.EnumType(enums.PaddingMethod), + default=None + ) + _kdw_mski_cp_hashing_algorithm = Column( + '_kdw_mski_cp_hashing_algorithm', + sql.EnumType(enums.HashingAlgorithm), + default=None + ) + _kdw_mski_cp_key_role_type = Column( + '_kdw_mski_cp_key_role_type', + sql.EnumType(enums.KeyRoleType), + default=None + ) + _kdw_mski_cp_digital_signature_algorithm = Column( + '_kdw_mski_cp_digital_signature_algorithm', + sql.EnumType(enums.DigitalSignatureAlgorithm), + default=None + ) + _kdw_mski_cp_cryptographic_algorithm = Column( + '_kdw_mski_cp_cryptographic_algorithm', + sql.EnumType(enums.CryptographicAlgorithm), + default=None + ) + _kdw_mski_cp_random_iv = Column( + '_kdw_mski_cp_random_iv', + Boolean, + default=None + ) + _kdw_mski_cp_iv_length = Column( + '_kdw_mski_cp_iv_length', + Integer, + default=None + ) + _kdw_mski_cp_tag_length = Column( + '_kdw_mski_cp_tag_length', + Integer, + default=None + ) + _kdw_mski_cp_fixed_field_length = Column( + '_kdw_mski_cp_fixed_field_length', + Integer, + default=None + ) + _kdw_mski_cp_invocation_field_length = Column( + '_kdw_mski_cp_invocation_field_length', + Integer, + default=None + ) + _kdw_mski_cp_counter_length = Column( + '_kdw_mski_cp_counter_length', + Integer, + default=None + ) + _kdw_mski_cp_initial_counter_value = Column( + '_kdw_mski_cp_initial_counter_value', + Integer, + default=None + ) + _kdw_mac_signature = Column( + '_kdw_mac_signature', + VARBINARY(1024), + default=None + ) + _kdw_iv_counter_nonce = Column( + '_kdw_iv_counter_nonce', + VARBINARY(1024), + default=None + ) + _kdw_encoding_option = Column( + '_kdw_encoding_option', + sql.EnumType(enums.EncodingOption), + default=None + ) + __mapper_args__ = { 'polymorphic_identity': 'Key' } @@ -232,15 +396,21 @@ class Key(CryptographicObject): } @abstractmethod - def __init__(self): + def __init__(self, key_wrapping_data=None): """ Create a Key object. + + Args: + key_wrapping_data(dict): A dictionary containing key wrapping data + settings, describing how the key value has been wrapped. + Optional, defaults to None. """ super(Key, self).__init__() self.cryptographic_algorithm = None self.cryptographic_length = None self.key_format_type = None + self.key_wrapping_data = key_wrapping_data # All remaining attributes are not considered part of the public API # and are subject to change. @@ -250,6 +420,145 @@ class Key(CryptographicObject): # unsupported by kmip.core self._usage_limits = None + @property + def key_wrapping_data(self): + """ + Retrieve all of the relevant key wrapping data fields and return them + as a dictionary. + """ + key_wrapping_data = {} + encryption_key_info = { + 'unique_identifier': self._kdw_eki_unique_identifier, + 'cryptographic_parameters': { + 'block_cipher_mode': self._kdw_eki_cp_block_cipher_mode, + 'padding_method': self._kdw_eki_cp_padding_method, + 'hashing_algorithm': self._kdw_eki_cp_hashing_algorithm, + 'key_role_type': self._kdw_eki_cp_key_role_type, + 'digital_signature_algorithm': + self._kdw_eki_cp_digital_signature_algorithm, + 'cryptographic_algorithm': + self._kdw_eki_cp_cryptographic_algorithm, + 'random_iv': self._kdw_eki_cp_random_iv, + 'iv_length': self._kdw_eki_cp_iv_length, + 'tag_length': self._kdw_eki_cp_tag_length, + 'fixed_field_length': self._kdw_eki_cp_fixed_field_length, + 'invocation_field_length': + self._kdw_eki_cp_invocation_field_length, + 'counter_length': self._kdw_eki_cp_counter_length, + 'initial_counter_value': + self._kdw_eki_cp_initial_counter_value + } + } + if not any(encryption_key_info['cryptographic_parameters'].values()): + encryption_key_info['cryptographic_parameters'] = {} + if not any(encryption_key_info.values()): + encryption_key_info = {} + + mac_sign_key_info = { + 'unique_identifier': self._kdw_mski_unique_identifier, + 'cryptographic_parameters': { + 'block_cipher_mode': self._kdw_mski_cp_block_cipher_mode, + 'padding_method': self._kdw_mski_cp_padding_method, + 'hashing_algorithm': self._kdw_mski_cp_hashing_algorithm, + 'key_role_type': self._kdw_mski_cp_key_role_type, + 'digital_signature_algorithm': + self._kdw_mski_cp_digital_signature_algorithm, + 'cryptographic_algorithm': + self._kdw_mski_cp_cryptographic_algorithm, + 'random_iv': self._kdw_mski_cp_random_iv, + 'iv_length': self._kdw_mski_cp_iv_length, + 'tag_length': self._kdw_mski_cp_tag_length, + 'fixed_field_length': self._kdw_mski_cp_fixed_field_length, + 'invocation_field_length': + self._kdw_mski_cp_invocation_field_length, + 'counter_length': self._kdw_mski_cp_counter_length, + 'initial_counter_value': + self._kdw_mski_cp_initial_counter_value + } + } + if not any(mac_sign_key_info['cryptographic_parameters'].values()): + mac_sign_key_info['cryptographic_parameters'] = {} + if not any(mac_sign_key_info.values()): + mac_sign_key_info = {} + + key_wrapping_data['wrapping_method'] = self._kdw_wrapping_method + key_wrapping_data['encryption_key_information'] = encryption_key_info + key_wrapping_data['mac_signature_key_information'] = mac_sign_key_info + key_wrapping_data['mac_signature'] = self._kdw_mac_signature + key_wrapping_data['iv_counter_nonce'] = self._kdw_iv_counter_nonce + key_wrapping_data['encoding_option'] = self._kdw_encoding_option + if not any(key_wrapping_data.values()): + key_wrapping_data = {} + + return key_wrapping_data + + @key_wrapping_data.setter + def key_wrapping_data(self, value): + """ + Set the key wrapping data attributes using a dictionary. + """ + if value is None: + value = {} + elif not isinstance(value, dict): + raise TypeError("Key wrapping data must be a dictionary.") + + self._kdw_wrapping_method = value.get('wrapping_method') + + eki = value.get('encryption_key_information') + if eki is None: + eki = {} + self._kdw_eki_unique_identifier = eki.get('unique_identifier') + eki_cp = eki.get('cryptographic_parameters') + if eki_cp is None: + eki_cp = {} + self._kdw_eki_cp_block_cipher_mode = eki_cp.get('block_cipher_mode') + self._kdw_eki_cp_padding_method = eki_cp.get('padding_method') + self._kdw_eki_cp_hashing_algorithm = eki_cp.get('hashing_algorithm') + self._kdw_eki_cp_key_role_type = eki_cp.get('key_role_type') + self._kdw_eki_cp_digital_signature_algorithm = \ + eki_cp.get('digital_signature_algorithm') + self._kdw_eki_cp_cryptographic_algorithm = \ + eki_cp.get('cryptographic_algorithm') + self._kdw_eki_cp_random_iv = eki_cp.get('random_iv') + self._kdw_eki_cp_iv_length = eki_cp.get('iv_length') + self._kdw_eki_cp_tag_length = eki_cp.get('tag_length') + self._kdw_eki_cp_fixed_field_length = eki_cp.get('fixed_field_length') + self._kdw_eki_cp_invocation_field_length = \ + eki_cp.get('invocation_field_length') + self._kdw_eki_cp_counter_length = eki_cp.get('counter_length') + self._kdw_eki_cp_initial_counter_value = \ + eki_cp.get('initial_counter_value') + + mski = value.get('mac_signature_key_information') + if mski is None: + mski = {} + self._kdw_mski_unique_identifier = mski.get('unique_identifier') + mski_cp = mski.get('cryptographic_parameters') + if mski_cp is None: + mski_cp = {} + self._kdw_mski_cp_block_cipher_mode = mski_cp.get('block_cipher_mode') + self._kdw_mski_cp_padding_method = mski_cp.get('padding_method') + self._kdw_mski_cp_hashing_algorithm = mski_cp.get('hashing_algorithm') + self._kdw_mski_cp_key_role_type = mski_cp.get('key_role_type') + self._kdw_mski_cp_digital_signature_algorithm = \ + mski_cp.get('digital_signature_algorithm') + self._kdw_mski_cp_cryptographic_algorithm = \ + mski_cp.get('cryptographic_algorithm') + self._kdw_mski_cp_random_iv = mski_cp.get('random_iv') + self._kdw_mski_cp_iv_length = mski_cp.get('iv_length') + self._kdw_mski_cp_tag_length = mski_cp.get('tag_length') + self._kdw_mski_cp_fixed_field_length = \ + mski_cp.get('fixed_field_length') + self._kdw_mski_cp_invocation_field_length = \ + mski_cp.get('invocation_field_length') + self._kdw_mski_cp_counter_length = mski_cp.get('counter_length') + self._kdw_mski_cp_initial_counter_value = \ + mski_cp.get('initial_counter_value') + + self._kdw_mac_signature = value.get('mac_signature') + self._kdw_iv_counter_nonce = value.get('iv_counter_nonce') + self._kdw_encoding_option = value.get('encoding_option') + class SymmetricKey(Key): """ @@ -267,6 +576,8 @@ class SymmetricKey(Key): cryptographic_usage_masks: The list of usage mask flags for SymmetricKey application. names: The string names of the SymmetricKey. + key_wrapping_data: A dictionary containing key wrapping data + settings, describing how the key value has been wrapped. """ __tablename__ = 'symmetric_keys' @@ -282,7 +593,7 @@ class SymmetricKey(Key): } def __init__(self, algorithm, length, value, masks=None, - name='Symmetric Key'): + name='Symmetric Key', key_wrapping_data=None): """ Create a SymmetricKey. @@ -295,8 +606,13 @@ class SymmetricKey(Key): how the key will be used. Optional, defaults to None. name(string): The string name of the key. Optional, defaults to 'Symmetric Key'. + key_wrapping_data(dict): A dictionary containing key wrapping data + settings, describing how the key value has been wrapped. + Optional, defaults to None. """ - super(SymmetricKey, self).__init__() + super(SymmetricKey, self).__init__( + key_wrapping_data=key_wrapping_data + ) self._object_type = enums.ObjectType.SYMMETRIC_KEY self.key_format_type = enums.KeyFormatType.RAW @@ -353,17 +669,29 @@ class SymmetricKey(Key): raise TypeError("key name {0} must be a string".format( position)) - if (len(self.value) * 8) != self.cryptographic_length: - msg = "key length ({0}) not equal to key value length ({1})" - msg = msg.format(self.cryptographic_length, len(self.value) * 8) - raise ValueError(msg) + if not self.key_wrapping_data: + if (len(self.value) * 8) != self.cryptographic_length: + msg = "key length ({0}) not equal to key value length ({1})" + msg = msg.format( + self.cryptographic_length, + len(self.value) * 8 + ) + raise ValueError(msg) def __repr__(self): algorithm = "algorithm={0}".format(self.cryptographic_algorithm) length = "length={0}".format(self.cryptographic_length) value = "value={0}".format(binascii.hexlify(self.value)) + key_wrapping_data = "key_wrapping_data={0}".format( + self.key_wrapping_data + ) - return "SymmetricKey({0}, {1}, {2})".format(algorithm, length, value) + return "SymmetricKey({0}, {1}, {2}, {3})".format( + algorithm, + length, + value, + key_wrapping_data + ) def __str__(self): return str(binascii.hexlify(self.value)) @@ -376,6 +704,8 @@ class SymmetricKey(Key): return False elif self.cryptographic_length != other.cryptographic_length: return False + elif self.key_wrapping_data != other.key_wrapping_data: + return False else: return True else: @@ -408,6 +738,8 @@ class PublicKey(Key): cryptographic_usage_masks: The list of usage mask flags for PublicKey application. names: The list of string names of the PublicKey. + key_wrapping_data(dict): A dictionary containing key wrapping data + settings, describing how the key value has been wrapped. """ __tablename__ = 'public_keys' @@ -424,7 +756,7 @@ class PublicKey(Key): def __init__(self, algorithm, length, value, format_type=enums.KeyFormatType.X_509, masks=None, - name='Public Key'): + name='Public Key', key_wrapping_data=None): """ Create a PublicKey. @@ -439,8 +771,13 @@ class PublicKey(Key): defining how the key will be used. Optional, defaults to None. name(string): The string name of the key. Optional, defaults to 'Public Key'. + key_wrapping_data(dict): A dictionary containing key wrapping data + settings, describing how the key value has been wrapped. + Optional, defaults to None. """ - super(PublicKey, self).__init__() + super(PublicKey, self).__init__( + key_wrapping_data=key_wrapping_data + ) self._object_type = enums.ObjectType.PUBLIC_KEY self._valid_formats = [ @@ -512,9 +849,12 @@ class PublicKey(Key): length = "length={0}".format(self.cryptographic_length) value = "value={0}".format(binascii.hexlify(self.value)) format_type = "format_type={0}".format(self.key_format_type) + key_wrapping_data = "key_wrapping_data={0}".format( + self.key_wrapping_data + ) - return "PublicKey({0}, {1}, {2}, {3})".format( - algorithm, length, value, format_type) + return "PublicKey({0}, {1}, {2}, {3}, {4})".format( + algorithm, length, value, format_type, key_wrapping_data) def __str__(self): return str(binascii.hexlify(self.value)) @@ -529,6 +869,8 @@ class PublicKey(Key): return False elif self.cryptographic_length != other.cryptographic_length: return False + elif self.key_wrapping_data != other.key_wrapping_data: + return False else: return True else: @@ -562,6 +904,8 @@ class PrivateKey(Key): application. Optional, defaults to None. names: The list of string names of the PrivateKey. Optional, defaults to 'Private Key'. + key_wrapping_data(dict): A dictionary containing key wrapping data + settings, describing how the key value has been wrapped. """ __tablename__ = 'private_keys' @@ -577,7 +921,7 @@ class PrivateKey(Key): } def __init__(self, algorithm, length, value, format_type, masks=None, - name='Private Key'): + name='Private Key', key_wrapping_data=None): """ Create a PrivateKey. @@ -591,8 +935,13 @@ class PrivateKey(Key): masks(list): A list of CryptographicUsageMask enumerations defining how the key will be used. name(string): The string name of the key. + key_wrapping_data(dict): A dictionary containing key wrapping data + settings, describing how the key value has been wrapped. + Optional, defaults to None. """ - super(PrivateKey, self).__init__() + super(PrivateKey, self).__init__( + key_wrapping_data=key_wrapping_data + ) self._object_type = enums.ObjectType.PRIVATE_KEY self._valid_formats = [ @@ -664,9 +1013,12 @@ class PrivateKey(Key): length = "length={0}".format(self.cryptographic_length) value = "value={0}".format(binascii.hexlify(self.value)) format_type = "format_type={0}".format(self.key_format_type) + key_wrapping_data = "key_wrapping_data={0}".format( + self.key_wrapping_data + ) - return "PrivateKey({0}, {1}, {2}, {3})".format( - algorithm, length, value, format_type) + return "PrivateKey({0}, {1}, {2}, {3}, {4})".format( + algorithm, length, value, format_type, key_wrapping_data) def __str__(self): return str(binascii.hexlify(self.value)) @@ -681,6 +1033,8 @@ class PrivateKey(Key): return False elif self.cryptographic_length != other.cryptographic_length: return False + elif self.key_wrapping_data != other.key_wrapping_data: + return False else: return True else: diff --git a/kmip/pie/sqltypes.py b/kmip/pie/sqltypes.py index e5d1413..6b27616 100644 --- a/kmip/pie/sqltypes.py +++ b/kmip/pie/sqltypes.py @@ -107,7 +107,10 @@ class EnumType(types.TypeDecorator): value(Enum): An Enum instance whose integer value is to be stored. dialect(string): SQL dialect """ - return value.value + if value: + return value.value + else: + return -1 def process_result_value(self, value, dialect): """ @@ -120,6 +123,8 @@ class EnumType(types.TypeDecorator): to create the Enum dialect(string): SQL dialect """ + if value == -1: + return None return self._cls(value) diff --git a/kmip/tests/unit/pie/objects/test_key.py b/kmip/tests/unit/pie/objects/test_key.py index d315940..e9d3d19 100644 --- a/kmip/tests/unit/pie/objects/test_key.py +++ b/kmip/tests/unit/pie/objects/test_key.py @@ -94,3 +94,17 @@ class TestKey(TestCase): """ dummy = DummyKey() self.assertFalse(dummy != dummy) + + def test_key_wrapping_data_invalid(self): + """ + Test that the right error is raised when setting the key wrapping + data with an invalid value. + """ + dummy = DummyKey() + args = (dummy, 'key_wrapping_data', 'invalid') + self.assertRaisesRegexp( + TypeError, + "Key wrapping data must be a dictionary.", + setattr, + *args + ) diff --git a/kmip/tests/unit/pie/objects/test_private_key.py b/kmip/tests/unit/pie/objects/test_private_key.py index 63848d0..c58daf8 100644 --- a/kmip/tests/unit/pie/objects/test_private_key.py +++ b/kmip/tests/unit/pie/objects/test_private_key.py @@ -300,9 +300,13 @@ class TestPrivateKey(testtools.TestCase): key = PrivateKey( enums.CryptographicAlgorithm.RSA, 1024, self.bytes_1024, enums.KeyFormatType.PKCS_8) - args = "algorithm={0}, length={1}, value={2}, format_type={3}".format( - enums.CryptographicAlgorithm.RSA, 1024, - binascii.hexlify(self.bytes_1024), enums.KeyFormatType.PKCS_8) + args = "{0}, {1}, {2}, {3}, {4}".format( + "algorithm={0}".format(enums.CryptographicAlgorithm.RSA), + "length={0}".format(1024), + "value={0}".format(binascii.hexlify(self.bytes_1024)), + "format_type={0}".format(enums.KeyFormatType.PKCS_8), + "key_wrapping_data={0}".format({}) + ) expected = "PrivateKey({0})".format(args) observed = repr(key) self.assertEqual(expected, observed) @@ -388,6 +392,31 @@ class TestPrivateKey(testtools.TestCase): self.assertFalse(a == b) self.assertFalse(b == a) + def test_equal_on_not_equal_key_wrapping_data(self): + """ + Test that the equality operator returns False when comparing two + PrivateKey objects with different key wrapping data. + """ + a = PrivateKey( + enums.CryptographicAlgorithm.RSA, + 1024, + self.bytes_1024, + enums.KeyFormatType.PKCS_8, + key_wrapping_data={} + ) + b = PrivateKey( + enums.CryptographicAlgorithm.RSA, + 1024, + self.bytes_1024, + enums.KeyFormatType.PKCS_8, + key_wrapping_data={ + 'wrapping_method': enums.WrappingMethod.ENCRYPT + } + ) + + self.assertFalse(a == b) + self.assertFalse(b == a) + def test_equal_on_type_mismatch(self): """ Test that the equality operator returns False when comparing a @@ -470,6 +499,31 @@ class TestPrivateKey(testtools.TestCase): self.assertTrue(a != b) self.assertTrue(b != a) + def test_not_equal_on_not_equal_key_wrapping_data(self): + """ + Test that the inequality operator returns True when comparing two + PrivateKey objects with different key wrapping data. + """ + a = PrivateKey( + enums.CryptographicAlgorithm.RSA, + 1024, + self.bytes_1024, + enums.KeyFormatType.PKCS_8, + key_wrapping_data={} + ) + b = PrivateKey( + enums.CryptographicAlgorithm.RSA, + 1024, + self.bytes_1024, + enums.KeyFormatType.PKCS_8, + key_wrapping_data={ + 'wrapping_method': enums.WrappingMethod.ENCRYPT + } + ) + + self.assertTrue(a != b) + self.assertTrue(b != a) + def test_not_equal_on_type_mismatch(self): """ Test that the equality operator returns True when comparing a diff --git a/kmip/tests/unit/pie/objects/test_public_key.py b/kmip/tests/unit/pie/objects/test_public_key.py index d269ea6..f057191 100644 --- a/kmip/tests/unit/pie/objects/test_public_key.py +++ b/kmip/tests/unit/pie/objects/test_public_key.py @@ -198,9 +198,13 @@ class TestPublicKey(testtools.TestCase): key = PublicKey( enums.CryptographicAlgorithm.RSA, 1024, self.bytes_1024, enums.KeyFormatType.X_509) - args = "algorithm={0}, length={1}, value={2}, format_type={3}".format( - enums.CryptographicAlgorithm.RSA, 1024, - binascii.hexlify(self.bytes_1024), enums.KeyFormatType.X_509) + args = "{0}, {1}, {2}, {3}, {4}".format( + "algorithm={0}".format(enums.CryptographicAlgorithm.RSA), + "length={0}".format(1024), + "value={0}".format(binascii.hexlify(self.bytes_1024)), + "format_type={0}".format(enums.KeyFormatType.X_509), + "key_wrapping_data={0}".format({}) + ) expected = "PublicKey({0})".format(args) observed = repr(key) self.assertEqual(expected, observed) @@ -286,6 +290,31 @@ class TestPublicKey(testtools.TestCase): self.assertFalse(a == b) self.assertFalse(b == a) + def test_equal_on_not_equal_key_wrapping_data(self): + """ + Test that the equality operator returns False when comparing two + PublicKey objects with different key wrapping data. + """ + a = PublicKey( + enums.CryptographicAlgorithm.RSA, + 1024, + self.bytes_1024, + enums.KeyFormatType.X_509, + key_wrapping_data={} + ) + b = PublicKey( + enums.CryptographicAlgorithm.RSA, + 1024, + self.bytes_1024, + enums.KeyFormatType.X_509, + key_wrapping_data={ + 'wrapping_method': enums.WrappingMethod.ENCRYPT + } + ) + + self.assertFalse(a == b) + self.assertFalse(b == a) + def test_equal_on_type_mismatch(self): """ Test that the equality operator returns False when comparing a @@ -368,6 +397,31 @@ class TestPublicKey(testtools.TestCase): self.assertTrue(a != b) self.assertTrue(b != a) + def test_not_equal_on_not_equal_key_wrapping_data(self): + """ + Test that the inequality operator returns True when comparing two + PublicKey objects with different key wrapping data. + """ + a = PublicKey( + enums.CryptographicAlgorithm.RSA, + 1024, + self.bytes_1024, + enums.KeyFormatType.X_509, + key_wrapping_data={} + ) + b = PublicKey( + enums.CryptographicAlgorithm.RSA, + 1024, + self.bytes_1024, + enums.KeyFormatType.X_509, + key_wrapping_data={ + 'wrapping_method': enums.WrappingMethod.ENCRYPT + } + ) + + self.assertTrue(a != b) + self.assertTrue(b != a) + def test_not_equal_on_type_mismatch(self): """ Test that the equality operator returns True when comparing a diff --git a/kmip/tests/unit/pie/objects/test_symmetric_key.py b/kmip/tests/unit/pie/objects/test_symmetric_key.py index 441996c..ccc4cdf 100644 --- a/kmip/tests/unit/pie/objects/test_symmetric_key.py +++ b/kmip/tests/unit/pie/objects/test_symmetric_key.py @@ -179,11 +179,17 @@ class TestSymmetricKey(testtools.TestCase): Test that repr can be applied to a SymmetricKey. """ key = SymmetricKey( - enums.CryptographicAlgorithm.AES, 128, self.bytes_128a) + enums.CryptographicAlgorithm.AES, + 128, + self.bytes_128a + ) - args = "algorithm={0}, length={1}, value={2}".format( - enums.CryptographicAlgorithm.AES, 128, - binascii.hexlify(self.bytes_128a)) + args = "{0}, {1}, {2}, {3}".format( + "algorithm={0}".format(enums.CryptographicAlgorithm.AES), + "length={0}".format(128), + "value={0}".format(binascii.hexlify(self.bytes_128a)), + "key_wrapping_data={0}".format({}) + ) expected = "SymmetricKey({0})".format(args) observed = repr(key) @@ -253,6 +259,29 @@ class TestSymmetricKey(testtools.TestCase): self.assertFalse(a == b) self.assertFalse(b == a) + def test_equal_on_not_equal_key_wrapping_data(self): + """ + Test that the equality operator returns False when comparing two + SymmetricKey objects with different key wrapping data. + """ + a = SymmetricKey( + enums.CryptographicAlgorithm.AES, + 128, + self.bytes_128a, + key_wrapping_data={} + ) + b = SymmetricKey( + enums.CryptographicAlgorithm.AES, + 128, + self.bytes_128a, + key_wrapping_data={ + 'wrapping_method': enums.WrappingMethod.ENCRYPT + } + ) + + self.assertFalse(a == b) + self.assertFalse(b == a) + def test_equal_on_type_mismatch(self): """ Test that the equality operator returns False when comparing a @@ -317,6 +346,29 @@ class TestSymmetricKey(testtools.TestCase): self.assertTrue(a != b) self.assertTrue(b != a) + def test_not_equal_on_not_equal_key_wrapping_data(self): + """ + Test that the inequality operator returns True when comparing two + SymmetricKey objects with different key wrapping data. + """ + a = SymmetricKey( + enums.CryptographicAlgorithm.AES, + 128, + self.bytes_128a, + key_wrapping_data={} + ) + b = SymmetricKey( + enums.CryptographicAlgorithm.AES, + 128, + self.bytes_128a, + key_wrapping_data={ + 'wrapping_method': enums.WrappingMethod.ENCRYPT + } + ) + + self.assertTrue(a != b) + self.assertTrue(b != a) + def test_not_equal_on_type_mismatch(self): """ Test that the equality operator returns True when comparing a diff --git a/kmip/tests/unit/pie/test_factory.py b/kmip/tests/unit/pie/test_factory.py index 3939289..04008c5 100644 --- a/kmip/tests/unit/pie/test_factory.py +++ b/kmip/tests/unit/pie/test_factory.py @@ -562,3 +562,103 @@ class TestObjectFactory(testtools.TestCase): self.assertEqual(key.cryptographic_length, length) self.assertEqual(key.key_format_type, format_type) self.assertEqual(key.value, value) + + def test_build_cryptographic_parameters(self): + cryptographic_parameters = cobjects.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC, + padding_method=enums.PaddingMethod.ANSI_X923, + hashing_algorithm=enums.HashingAlgorithm.SHA_256, + key_role_type=enums.KeyRoleType.KEK, + digital_signature_algorithm=enums.DigitalSignatureAlgorithm. + DSA_WITH_SHA1, + cryptographic_algorithm=enums.CryptographicAlgorithm.AES, + random_iv=True, + iv_length=32, + tag_length=33, + fixed_field_length=34, + invocation_field_length=35, + counter_length=36, + initial_counter_value=0 + ) + + result = self.factory._build_cryptographic_parameters( + cryptographic_parameters + ) + self.assertIsInstance(result, dict) + self.assertEqual( + enums.BlockCipherMode.CBC, + result.get('block_cipher_mode') + ) + self.assertEqual( + enums.PaddingMethod.ANSI_X923, + result.get('padding_method') + ) + self.assertEqual( + enums.HashingAlgorithm.SHA_256, + result.get('hashing_algorithm') + ) + self.assertEqual( + enums.KeyRoleType.KEK, + result.get('key_role_type') + ) + self.assertEqual( + enums.DigitalSignatureAlgorithm.DSA_WITH_SHA1, + result.get('digital_signature_algorithm') + ) + self.assertEqual( + enums.CryptographicAlgorithm.AES, + result.get('cryptographic_algorithm') + ) + self.assertEqual(True, result.get('random_iv')) + self.assertEqual(32, result.get('iv_length')) + self.assertEqual(33, result.get('tag_length')) + self.assertEqual(34, result.get('fixed_field_length')) + self.assertEqual(35, result.get('invocation_field_length')) + self.assertEqual(36, result.get('counter_length')) + self.assertEqual(0, result.get('initial_counter_value')) + + def test_build_key_wrapping_data(self): + key_wrapping_data = cobjects.KeyWrappingData( + wrapping_method=enums.WrappingMethod.ENCRYPT, + encryption_key_information=cobjects.EncryptionKeyInformation( + unique_identifier='1', + cryptographic_parameters=cobjects.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CBC + ) + ), + mac_signature_key_information=cobjects.MACSignatureKeyInformation( + unique_identifier='2', + cryptographic_parameters=cobjects.CryptographicParameters( + block_cipher_mode=enums.BlockCipherMode.CCM + ) + ), + mac_signature=b'\x01', + iv_counter_nonce=b'\x02', + encoding_option=enums.EncodingOption.NO_ENCODING + ) + + result = self.factory._build_key_wrapping_data( + key_wrapping_data + ) + self.assertIsInstance(result, dict) + self.assertEqual( + enums.WrappingMethod.ENCRYPT, + result.get('wrapping_method') + ) + self.assertIsInstance(result.get('encryption_key_information'), dict) + eki = result.get('encryption_key_information') + self.assertEqual('1', eki.get('unique_identifier')) + self.assertIsInstance(eki.get('cryptographic_parameters'), dict) + self.assertIsInstance( + result.get('mac_signature_key_information'), + dict + ) + mski = result.get('mac_signature_key_information') + self.assertEqual('2', mski.get('unique_identifier')) + self.assertIsInstance(mski.get('cryptographic_parameters'), dict) + self.assertEqual(b'\x01', result.get('mac_signature')) + self.assertEqual(b'\x02', result.get('iv_counter_nonce')) + self.assertEqual( + enums.EncodingOption.NO_ENCODING, + result.get('encoding_option') + )