diff --git a/kmip/core/messages/payloads/create_key_pair.py b/kmip/core/messages/payloads/create_key_pair.py index 7521eb6..ec3489d 100644 --- a/kmip/core/messages/payloads/create_key_pair.py +++ b/kmip/core/messages/payloads/create_key_pair.py @@ -154,41 +154,82 @@ class CreateKeyPairRequestPayload(primitives.Struct): ) local_buffer = utils.BytearrayStream(input_buffer.read(self.length)) - if self.is_tag_next( - enums.Tags.COMMON_TEMPLATE_ATTRIBUTE, - local_buffer - ): - self._common_template_attribute = objects.TemplateAttribute( - tag=enums.Tags.COMMON_TEMPLATE_ATTRIBUTE - ) - self._common_template_attribute.read( - local_buffer, - kmip_version=kmip_version - ) + if kmip_version < enums.KMIPVersion.KMIP_2_0: + if self.is_tag_next( + enums.Tags.COMMON_TEMPLATE_ATTRIBUTE, + local_buffer + ): + self._common_template_attribute = objects.TemplateAttribute( + tag=enums.Tags.COMMON_TEMPLATE_ATTRIBUTE + ) + self._common_template_attribute.read( + local_buffer, + kmip_version=kmip_version + ) + else: + if self.is_tag_next(enums.Tags.COMMON_ATTRIBUTES, local_buffer): + attributes = objects.Attributes( + tag=enums.Tags.COMMON_ATTRIBUTES + ) + attributes.read(local_buffer, kmip_version=kmip_version) + self._common_template_attribute = \ + objects.convert_attributes_to_template_attribute( + attributes + ) - if self.is_tag_next( - enums.Tags.PRIVATE_KEY_TEMPLATE_ATTRIBUTE, - local_buffer - ): - self._private_key_template_attribute = objects.TemplateAttribute( - tag=enums.Tags.PRIVATE_KEY_TEMPLATE_ATTRIBUTE - ) - self._private_key_template_attribute.read( - local_buffer, - kmip_version=kmip_version - ) + if kmip_version < enums.KMIPVersion.KMIP_2_0: + if self.is_tag_next( + enums.Tags.PRIVATE_KEY_TEMPLATE_ATTRIBUTE, + local_buffer + ): + self._private_key_template_attribute = \ + objects.TemplateAttribute( + tag=enums.Tags.PRIVATE_KEY_TEMPLATE_ATTRIBUTE + ) + self._private_key_template_attribute.read( + local_buffer, + kmip_version=kmip_version + ) + else: + if self.is_tag_next( + enums.Tags.PRIVATE_KEY_ATTRIBUTES, + local_buffer + ): + attributes = objects.Attributes( + tag=enums.Tags.PRIVATE_KEY_ATTRIBUTES + ) + attributes.read(local_buffer, kmip_version=kmip_version) + self._private_key_template_attribute = \ + objects.convert_attributes_to_template_attribute( + attributes + ) - if self.is_tag_next( - enums.Tags.PUBLIC_KEY_TEMPLATE_ATTRIBUTE, - local_buffer - ): - self._public_key_template_attribute = objects.TemplateAttribute( - tag=enums.Tags.PUBLIC_KEY_TEMPLATE_ATTRIBUTE - ) - self._public_key_template_attribute.read( - local_buffer, - kmip_version=kmip_version - ) + if kmip_version < enums.KMIPVersion.KMIP_2_0: + if self.is_tag_next( + enums.Tags.PUBLIC_KEY_TEMPLATE_ATTRIBUTE, + local_buffer + ): + self._public_key_template_attribute = \ + objects.TemplateAttribute( + tag=enums.Tags.PUBLIC_KEY_TEMPLATE_ATTRIBUTE + ) + self._public_key_template_attribute.read( + local_buffer, + kmip_version=kmip_version + ) + else: + if self.is_tag_next( + enums.Tags.PUBLIC_KEY_ATTRIBUTES, + local_buffer + ): + attributes = objects.Attributes( + tag=enums.Tags.PUBLIC_KEY_ATTRIBUTES + ) + attributes.read(local_buffer, kmip_version=kmip_version) + self._public_key_template_attribute = \ + objects.convert_attributes_to_template_attribute( + attributes + ) self.is_oversized(local_buffer) @@ -205,23 +246,44 @@ class CreateKeyPairRequestPayload(primitives.Struct): """ local_buffer = utils.BytearrayStream() - if self._common_template_attribute is not None: - self._common_template_attribute.write( - local_buffer, - kmip_version=kmip_version - ) + if kmip_version < enums.KMIPVersion.KMIP_2_0: + if self._common_template_attribute is not None: + self._common_template_attribute.write( + local_buffer, + kmip_version=kmip_version + ) + else: + if self._common_template_attribute is not None: + attributes = objects.convert_template_attribute_to_attributes( + self._common_template_attribute + ) + attributes.write(local_buffer, kmip_version=kmip_version) - if self._private_key_template_attribute is not None: - self._private_key_template_attribute.write( - local_buffer, - kmip_version=kmip_version - ) + if kmip_version < enums.KMIPVersion.KMIP_2_0: + if self._private_key_template_attribute is not None: + self._private_key_template_attribute.write( + local_buffer, + kmip_version=kmip_version + ) + else: + if self._private_key_template_attribute is not None: + attributes = objects.convert_template_attribute_to_attributes( + self._private_key_template_attribute + ) + attributes.write(local_buffer, kmip_version=kmip_version) - if self._public_key_template_attribute is not None: - self._public_key_template_attribute.write( - local_buffer, - kmip_version=kmip_version - ) + if kmip_version < enums.KMIPVersion.KMIP_2_0: + if self._public_key_template_attribute is not None: + self._public_key_template_attribute.write( + local_buffer, + kmip_version=kmip_version + ) + else: + if self._public_key_template_attribute is not None: + attributes = objects.convert_template_attribute_to_attributes( + self._public_key_template_attribute + ) + attributes.write(local_buffer, kmip_version=kmip_version) self.length = local_buffer.length() super(CreateKeyPairRequestPayload, self).write( @@ -301,6 +363,26 @@ class CreateKeyPairResponsePayload(primitives.Struct): public_key_unique_identifier=None, private_key_template_attribute=None, public_key_template_attribute=None): + """ + Construct a CreateKeyPair response payload structure. + + Args: + private_key_unique_identifier (string): A string specifying the + ID of the new private key. Optional, defaults to None. Required + for read/write. + public_key_unique_identifier (string): A string specifying the + ID of the new public key. Optional, defaults to None. Required + for read/write. + private_key_template_attribute (TemplateAttribute): A + TemplateAttribute structure with the + PrivateKeyTemplateAttribute tag containing the set of + attributes that were set on the new private key. Optional, + defaults to None. + public_key_template_attribute (TemplateAttribute): A + TemplateAttribute structure with the PublicKeyTemplateAttribute + tag containing the set of attributes that were set on the new + public key. Optional, defaults to None. + """ super(CreateKeyPairResponsePayload, self).__init__( enums.Tags.RESPONSE_PAYLOAD ) @@ -456,29 +538,32 @@ class CreateKeyPairResponsePayload(primitives.Struct): "public key unique identifier." ) - if self.is_tag_next( - enums.Tags.PRIVATE_KEY_TEMPLATE_ATTRIBUTE, - local_buffer - ): - self._private_key_template_attribute = objects.TemplateAttribute( - tag=enums.Tags.PRIVATE_KEY_TEMPLATE_ATTRIBUTE - ) - self._private_key_template_attribute.read( - local_buffer, - kmip_version=kmip_version - ) + if kmip_version < enums.KMIPVersion.KMIP_2_0: + if self.is_tag_next( + enums.Tags.PRIVATE_KEY_TEMPLATE_ATTRIBUTE, + local_buffer + ): + self._private_key_template_attribute = \ + objects.TemplateAttribute( + tag=enums.Tags.PRIVATE_KEY_TEMPLATE_ATTRIBUTE + ) + self._private_key_template_attribute.read( + local_buffer, + kmip_version=kmip_version + ) - if self.is_tag_next( - enums.Tags.PUBLIC_KEY_TEMPLATE_ATTRIBUTE, - local_buffer - ): - self._public_key_template_attribute = objects.TemplateAttribute( - tag=enums.Tags.PUBLIC_KEY_TEMPLATE_ATTRIBUTE - ) - self._public_key_template_attribute.read( - local_buffer, - kmip_version=kmip_version - ) + if self.is_tag_next( + enums.Tags.PUBLIC_KEY_TEMPLATE_ATTRIBUTE, + local_buffer + ): + self._public_key_template_attribute = \ + objects.TemplateAttribute( + tag=enums.Tags.PUBLIC_KEY_TEMPLATE_ATTRIBUTE + ) + self._public_key_template_attribute.read( + local_buffer, + kmip_version=kmip_version + ) self.is_oversized(local_buffer) diff --git a/kmip/tests/unit/core/messages/payloads/test_create_key_pair.py b/kmip/tests/unit/core/messages/payloads/test_create_key_pair.py index 0b13b79..2eeaff6 100644 --- a/kmip/tests/unit/core/messages/payloads/test_create_key_pair.py +++ b/kmip/tests/unit/core/messages/payloads/test_create_key_pair.py @@ -100,6 +100,43 @@ class TestCreateKeyPairRequestPayload(testtools.TestCase): b'\x42\x00\x0B\x02\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00' ) + # Encoding obtained from the KMIP 1.1 testing document, Section 8.1.0. + # Manually converted to the KMIP 2.0 format. + # + # This encoding matches the following set of values: + # Request Payload + # Common Attributes + # Cryptographic Algorithm - RSA + # Cryptographic Length - 1024 + # Private Key Attributes + # Name + # Name Value - PrivateKey1 + # Name Type - Uninterpreted Text String + # Cryptographic Usage Mask - Sign + # Public Key Attributes + # Name + # Name Value - PublicKey1 + # Name Type - Uninterpreted Text String + # Cryptographic Usage Mask - Verify + self.full_encoding_with_attributes = utils.BytearrayStream( + b'\x42\x00\x79\x01\x00\x00\x00\xB8' + b'\x42\x01\x26\x01\x00\x00\x00\x20' + b'\x42\x00\x28\x05\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00' + b'\x42\x00\x2A\x02\x00\x00\x00\x04\x00\x00\x04\x00\x00\x00\x00\x00' + b'\x42\x01\x27\x01\x00\x00\x00\x40' + b'\x42\x00\x53\x01\x00\x00\x00\x28' + b'\x42\x00\x55\x07\x00\x00\x00\x0B' + b'\x50\x72\x69\x76\x61\x74\x65\x4B\x65\x79\x31\x00\x00\x00\x00\x00' + b'\x42\x00\x54\x05\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00' + b'\x42\x00\x2C\x02\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00' + b'\x42\x01\x28\x01\x00\x00\x00\x40' + b'\x42\x00\x53\x01\x00\x00\x00\x28' + b'\x42\x00\x55\x07\x00\x00\x00\x0A' + b'\x50\x75\x62\x6C\x69\x63\x4B\x65\x79\x31\x00\x00\x00\x00\x00\x00' + b'\x42\x00\x54\x05\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00' + b'\x42\x00\x2C\x02\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00' + ) + # Encoding obtained from the KMIP 1.1 testing document, Section 8.1.0. # # This encoding matches the following set of values: @@ -510,6 +547,106 @@ class TestCreateKeyPairRequestPayload(testtools.TestCase): payload.public_key_template_attribute ) + def test_read_kmip_2_0(self): + """ + Test that a CreateKeyPair request payload can be read from a data + stream encoded with the KMIP 2.0 format. + """ + payload = payloads.CreateKeyPairRequestPayload() + + self.assertIsNone(payload.common_template_attribute) + self.assertIsNone(payload.private_key_template_attribute) + self.assertIsNone(payload.public_key_template_attribute) + + payload.read( + self.full_encoding_with_attributes, + kmip_version=enums.KMIPVersion.KMIP_2_0 + ) + + self.assertEqual( + objects.TemplateAttribute( + attributes=[ + objects.Attribute( + attribute_name=objects.Attribute.AttributeName( + 'Cryptographic Algorithm' + ), + attribute_value=primitives.Enumeration( + enums.CryptographicAlgorithm, + value=enums.CryptographicAlgorithm.RSA, + tag=enums.Tags.CRYPTOGRAPHIC_ALGORITHM + ) + ), + objects.Attribute( + attribute_name=objects.Attribute.AttributeName( + 'Cryptographic Length' + ), + attribute_value=primitives.Integer( + value=1024, + tag=enums.Tags.CRYPTOGRAPHIC_LENGTH + ) + ) + ], + tag=enums.Tags.COMMON_TEMPLATE_ATTRIBUTE + ), + payload.common_template_attribute + ) + self.assertEqual( + objects.TemplateAttribute( + attributes=[ + objects.Attribute( + attribute_name=objects.Attribute.AttributeName("Name"), + attribute_value=attributes.Name( + name_value=attributes.Name.NameValue( + "PrivateKey1" + ), + name_type=attributes.Name.NameType( + enums.NameType.UNINTERPRETED_TEXT_STRING + ) + ) + ), + objects.Attribute( + attribute_name=objects.Attribute.AttributeName( + "Cryptographic Usage Mask" + ), + attribute_value=primitives.Integer( + value=enums.CryptographicUsageMask.SIGN.value, + tag=enums.Tags.CRYPTOGRAPHIC_USAGE_MASK + ) + ) + ], + tag=enums.Tags.PRIVATE_KEY_TEMPLATE_ATTRIBUTE + ), + payload.private_key_template_attribute + ) + self.assertEqual( + objects.TemplateAttribute( + attributes=[ + objects.Attribute( + attribute_name=objects.Attribute.AttributeName("Name"), + attribute_value=attributes.Name( + name_value=attributes.Name.NameValue( + "PublicKey1" + ), + name_type=attributes.Name.NameType( + enums.NameType.UNINTERPRETED_TEXT_STRING + ) + ) + ), + objects.Attribute( + attribute_name=objects.Attribute.AttributeName( + "Cryptographic Usage Mask" + ), + attribute_value=primitives.Integer( + value=enums.CryptographicUsageMask.VERIFY.value, + tag=enums.Tags.CRYPTOGRAPHIC_USAGE_MASK + ) + ) + ], + tag=enums.Tags.PUBLIC_KEY_TEMPLATE_ATTRIBUTE + ), + payload.public_key_template_attribute + ) + def test_read_missing_common_template_attribute(self): """ Test that a CreateKeyPair request payload can be read from a data @@ -826,6 +963,94 @@ class TestCreateKeyPairRequestPayload(testtools.TestCase): self.assertEqual(len(self.full_encoding), len(stream)) self.assertEqual(str(self.full_encoding), str(stream)) + def test_write_kmip_2_0(self): + """ + Test that a CreateKeyPair request payload can be written to a data + stream encoded with the KMIP 2.0 format. + """ + payload = payloads.CreateKeyPairRequestPayload( + common_template_attribute=objects.TemplateAttribute( + attributes=[ + objects.Attribute( + attribute_name=objects.Attribute.AttributeName( + 'Cryptographic Algorithm' + ), + attribute_value=primitives.Enumeration( + enums.CryptographicAlgorithm, + value=enums.CryptographicAlgorithm.RSA, + tag=enums.Tags.CRYPTOGRAPHIC_ALGORITHM + ) + ), + objects.Attribute( + attribute_name=objects.Attribute.AttributeName( + 'Cryptographic Length' + ), + attribute_value=primitives.Integer( + value=1024, + tag=enums.Tags.CRYPTOGRAPHIC_LENGTH + ) + ) + ], + tag=enums.Tags.COMMON_TEMPLATE_ATTRIBUTE + ), + private_key_template_attribute=objects.TemplateAttribute( + attributes=[ + objects.Attribute( + attribute_name=objects.Attribute.AttributeName("Name"), + attribute_value=attributes.Name( + name_value=attributes.Name.NameValue( + "PrivateKey1" + ), + name_type=attributes.Name.NameType( + enums.NameType.UNINTERPRETED_TEXT_STRING + ) + ) + ), + objects.Attribute( + attribute_name=objects.Attribute.AttributeName( + "Cryptographic Usage Mask" + ), + attribute_value=primitives.Integer( + value=enums.CryptographicUsageMask.SIGN.value, + tag=enums.Tags.CRYPTOGRAPHIC_USAGE_MASK + ) + ) + ], + tag=enums.Tags.PRIVATE_KEY_TEMPLATE_ATTRIBUTE + ), + public_key_template_attribute=objects.TemplateAttribute( + attributes=[ + objects.Attribute( + attribute_name=objects.Attribute.AttributeName("Name"), + attribute_value=attributes.Name( + name_value=attributes.Name.NameValue( + "PublicKey1" + ), + name_type=attributes.Name.NameType( + enums.NameType.UNINTERPRETED_TEXT_STRING + ) + ) + ), + objects.Attribute( + attribute_name=objects.Attribute.AttributeName( + "Cryptographic Usage Mask" + ), + attribute_value=primitives.Integer( + value=enums.CryptographicUsageMask.VERIFY.value, + tag=enums.Tags.CRYPTOGRAPHIC_USAGE_MASK + ) + ) + ], + tag=enums.Tags.PUBLIC_KEY_TEMPLATE_ATTRIBUTE + ) + ) + + stream = utils.BytearrayStream() + payload.write(stream, kmip_version=enums.KMIPVersion.KMIP_2_0) + + self.assertEqual(len(self.full_encoding_with_attributes), len(stream)) + self.assertEqual(str(self.full_encoding_with_attributes), str(stream)) + def test_write_missing_common_template_attribute(self): """ Test that a CreateKeyPair request payload can be written to a data