From e497e1c37c31f90a652a499fef0e660cbe6a8665 Mon Sep 17 00:00:00 2001 From: Peter Hamilton Date: Thu, 30 Jul 2015 08:03:33 -0400 Subject: [PATCH] Adding secret data to the Pie object hierarchy This change adds a SecretData class to the Pie object hierarchy. A unit test suite covering the class is provided, as are updates to the Pie object factory and associated tests. --- kmip/pie/factory.py | 27 +++ kmip/pie/objects.py | 106 +++++++++ .../unit/pie/objects/test_secret_data.py | 218 ++++++++++++++++++ kmip/tests/unit/pie/test_factory.py | 174 +++++++++----- 4 files changed, 463 insertions(+), 62 deletions(-) create mode 100644 kmip/tests/unit/pie/objects/test_secret_data.py diff --git a/kmip/pie/factory.py b/kmip/pie/factory.py index 8e55f81..3f3286c 100644 --- a/kmip/pie/factory.py +++ b/kmip/pie/factory.py @@ -60,6 +60,10 @@ class ObjectFactory: return self._build_core_certificate(obj) elif isinstance(obj, secrets.Certificate): return self._build_pie_certificate(obj) + elif isinstance(obj, pobjects.SecretData): + return self._build_core_secret_data(obj) + elif isinstance(obj, secrets.SecretData): + return self._build_pie_secret_data(obj) else: raise TypeError("object type unsupported and cannot be converted") @@ -93,6 +97,12 @@ class ObjectFactory: def _build_core_certificate(self, cert): return secrets.Certificate(cert.certificate_type, cert.value) + def _build_pie_secret_data(self, secret): + secret_data_type = secret.secret_data_type.enum + value = secret.key_block.key_value.key_material.value + + return pobjects.SecretData(value, secret_data_type) + def _build_core_key(self, key, cls): algorithm = key.cryptographic_algorithm length = key.cryptographic_length @@ -111,3 +121,20 @@ class ObjectFactory: key_wrapping_data=None) return cls(key_block) + + def _build_core_secret_data(self, secret): + secret_data_type = secret.data_type + value = secret.value + + key_material = cobjects.KeyMaterial(value) + key_value = cobjects.KeyValue(key_material) + key_block = cobjects.KeyBlock( + key_format_type=misc.KeyFormatType(enums.KeyFormatType.OPAQUE), + key_compression_type=None, + key_value=key_value, + cryptographic_algorithm=None, + cryptographic_length=None, + key_wrapping_data=None) + data_type = secrets.SecretData.SecretDataType(secret_data_type) + + return secrets.SecretData(data_type, key_block) diff --git a/kmip/pie/objects.py b/kmip/pie/objects.py index aae68e7..feea349 100644 --- a/kmip/pie/objects.py +++ b/kmip/pie/objects.py @@ -753,3 +753,109 @@ class X509Certificate(Certificate): return not (self == other) else: return NotImplemented + + +class SecretData(CryptographicObject): + """ + The SecretData class of the simplified KMIP object hierarchy. + + SecretData is one of several CryptographicObjects and is one of the core + KMIP objects that are the subject of key management operations. For more + information, see Section 2.2 of the KMIP 1.1 specification. + + Attributes: + cryptographic_usage_masks: A list of usage mask enumerations + describing how the CryptographicObject will be used. + data_type: The type of the secret value. + """ + + def __init__(self, value, data_type, masks=None, name='Secret Data'): + """ + Create a SecretData object. + + Args: + value(bytes): The bytes representing secret data. + data_type(SecretDataType): An enumeration defining the type of the + secret value. + masks(list): A list of CryptographicUsageMask enumerations + defining how the key will be used. + name(string): The string name of the key. + """ + super(SecretData, self).__init__() + + self._object_type = enums.ObjectType.SECRET_DATA + + self.value = value + self.data_type = data_type + self.names = [name] + + if masks: + self.cryptographic_usage_masks = masks + else: + self.cryptographic_usage_masks = list() + + # All remaining attributes are not considered part of the public API + # and are subject to change. + + # The following attributes are placeholders for attributes that are + # unsupported by kmip.core + + self.validate() + + def validate(self): + """ + Verify that the contents of the SecretData object are valid. + + Raises: + TypeError: if the types of any SecretData attributes are invalid. + """ + if not isinstance(self.value, bytes): + raise TypeError("secret value must be bytes") + elif not isinstance(self.data_type, enums.SecretDataType): + raise TypeError("secret data type must be a SecretDataType " + "enumeration") + elif not isinstance(self.cryptographic_usage_masks, list): + raise TypeError("secret data usage masks must be a list") + + mask_count = len(self.cryptographic_usage_masks) + for i in range(mask_count): + mask = self.cryptographic_usage_masks[i] + if not isinstance(mask, enums.CryptographicUsageMask): + position = "({0} in list)".format(i) + raise TypeError( + "secret data mask {0} must be a CryptographicUsageMask " + "enumeration".format(position)) + + name_count = len(self.names) + for i in range(name_count): + name = self.names[i] + if not isinstance(name, six.string_types): + position = "({0} in list)".format(i) + raise TypeError("secret data name {0} must be a string".format( + position)) + + def __repr__(self): + value = "value={0}".format(binascii.hexlify(self.value)) + data_type = "data_type={0}".format(self.data_type) + + return "SecretData({0}, {1})".format(value, data_type) + + def __str__(self): + return str(binascii.hexlify(self.value)) + + def __eq__(self, other): + if isinstance(other, SecretData): + if self.value != other.value: + return False + elif self.data_type != other.data_type: + return False + else: + return True + else: + return NotImplemented + + def __ne__(self, other): + if isinstance(other, SecretData): + return not (self == other) + else: + return NotImplemented diff --git a/kmip/tests/unit/pie/objects/test_secret_data.py b/kmip/tests/unit/pie/objects/test_secret_data.py new file mode 100644 index 0000000..335a26c --- /dev/null +++ b/kmip/tests/unit/pie/objects/test_secret_data.py @@ -0,0 +1,218 @@ +# Copyright (c) 2015 The Johns Hopkins University/Applied Physics Laboratory +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import binascii +import testtools + +from kmip.core import enums +from kmip.pie import objects + + +class TestSecretData(testtools.TestCase): + """ + Test suite for SecretData. + """ + def setUp(self): + super(TestSecretData, self).setUp() + + # Secret data taken from Sections 3.1.5 of the KMIP 1.1 testing + # documentation. + self.bytes_a = ( + b'\x53\x65\x63\x72\x65\x74\x50\x61\x73\x73\x77\x6F\x72\x64') + self.bytes_b = ( + b'\x53\x65\x63\x72\x65\x74\x50\x61\x73\x73\x77\x6F\x72\x65') + + def tearDown(self): + super(TestSecretData, self).tearDown() + + def test_init(self): + """ + Test that a SecretData object can be instantiated. + """ + secret = objects.SecretData( + self.bytes_a, enums.SecretDataType.PASSWORD) + + self.assertEqual(secret.value, self.bytes_a) + self.assertEqual(secret.data_type, enums.SecretDataType.PASSWORD) + self.assertEqual(secret.cryptographic_usage_masks, list()) + self.assertEqual(secret.names, ['Secret Data']) + + def test_init_with_args(self): + """ + Test that a SecretData object can be instantiated with all arguments. + """ + key = objects.SecretData( + self.bytes_a, + enums.SecretDataType.PASSWORD, + masks=[enums.CryptographicUsageMask.VERIFY], + name='Test Secret Data') + + self.assertEqual(key.value, self.bytes_a) + self.assertEqual(key.data_type, enums.SecretDataType.PASSWORD) + self.assertEqual(key.cryptographic_usage_masks, + [enums.CryptographicUsageMask.VERIFY]) + self.assertEqual(key.names, ['Test Secret Data']) + + def test_get_object_type(self): + """ + Test that the object type can be retrieved from the SecretData. + """ + expected = enums.ObjectType.SECRET_DATA + key = objects.SecretData(self.bytes_a, enums.SecretDataType.PASSWORD) + observed = key.object_type + self.assertEqual(expected, observed) + + def test_validate_on_invalid_value(self): + """ + Test that a TypeError is raised when an invalid value is used to + construct a SecretData. + """ + args = (0, enums.SecretDataType.PASSWORD) + self.assertRaises(TypeError, objects.SecretData, *args) + + def test_validate_on_invalid_data_type(self): + """ + Test that a TypeError is raised when an invalid data type is used to + construct a SecretData. + """ + args = (self.bytes_a, 'invalid') + self.assertRaises(TypeError, objects.SecretData, *args) + + def test_validate_on_invalid_masks(self): + """ + Test that a TypeError is raised when an invalid masks value is used to + construct a SecretData. + """ + args = (self.bytes_a, enums.SecretDataType.PASSWORD) + kwargs = {'masks': 'invalid'} + self.assertRaises(TypeError, objects.SecretData, *args, **kwargs) + + def test_validate_on_invalid_mask(self): + """ + Test that a TypeError is raised when an invalid mask value is used to + construct a SecretData. + """ + args = (self.bytes_a, enums.SecretDataType.PASSWORD) + kwargs = {'masks': ['invalid']} + self.assertRaises(TypeError, objects.SecretData, *args, **kwargs) + + def test_validate_on_invalid_name(self): + """ + Test that a TypeError is raised when an invalid name value is used to + construct a SecretData. + """ + args = (self.bytes_a, enums.SecretDataType.PASSWORD) + kwargs = {'name': 0} + self.assertRaises(TypeError, objects.SecretData, *args, **kwargs) + + def test_repr(self): + """ + Test that repr can be applied to a SecretData. + """ + key = objects.SecretData(self.bytes_a, enums.SecretDataType.PASSWORD) + args = "value={0}, data_type={1}".format( + binascii.hexlify(self.bytes_a), enums.SecretDataType.PASSWORD) + expected = "SecretData({0})".format(args) + observed = repr(key) + self.assertEqual(expected, observed) + + def test_str(self): + """ + Test that str can be applied to a SecretData. + """ + key = objects.SecretData(self.bytes_a, enums.SecretDataType.PASSWORD) + expected = str(binascii.hexlify(self.bytes_a)) + observed = str(key) + self.assertEqual(expected, observed) + + def test_equal_on_equal(self): + """ + Test that the equality operator returns True when comparing two + SecretData objects with the same data. + """ + a = objects.SecretData(self.bytes_a, enums.SecretDataType.PASSWORD) + b = objects.SecretData(self.bytes_a, enums.SecretDataType.PASSWORD) + self.assertTrue(a == b) + self.assertTrue(b == a) + + def test_equal_on_not_equal_value(self): + """ + Test that the equality operator returns False when comparing two + SecretData objects with different data. + """ + a = objects.SecretData(self.bytes_a, enums.SecretDataType.PASSWORD) + b = objects.SecretData(self.bytes_b, enums.SecretDataType.PASSWORD) + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_not_equal_data_type(self): + """ + Test that the equality operator returns False when comparing two + SecretData objects with different data. + """ + a = objects.SecretData(self.bytes_a, enums.SecretDataType.PASSWORD) + b = objects.SecretData(self.bytes_a, enums.SecretDataType.SEED) + 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 + SecretData object to a non-SecretData object. + """ + a = objects.SecretData(self.bytes_a, enums.SecretDataType.PASSWORD) + 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 SecretData objects with the same internal data. + """ + a = objects.SecretData(self.bytes_a, enums.SecretDataType.PASSWORD) + b = objects.SecretData(self.bytes_a, enums.SecretDataType.PASSWORD) + self.assertFalse(a != b) + self.assertFalse(b != a) + + def test_not_equal_on_not_equal_value(self): + """ + Test that the equality operator returns True when comparing two + SecretData objects with different data. + """ + a = objects.SecretData(self.bytes_a, enums.SecretDataType.PASSWORD) + b = objects.SecretData(self.bytes_b, enums.SecretDataType.PASSWORD) + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_not_equal_data_type(self): + """ + Test that the equality operator returns True when comparing two + SecretData objects with different data. + """ + a = objects.SecretData(self.bytes_a, enums.SecretDataType.PASSWORD) + b = objects.SecretData(self.bytes_a, enums.SecretDataType.SEED) + 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 + SecretData object to a non-SecretData object. + """ + a = objects.SecretData(self.bytes_a, enums.SecretDataType.PASSWORD) + b = "invalid" + self.assertTrue(a != b) + self.assertTrue(b != a) diff --git a/kmip/tests/unit/pie/test_factory.py b/kmip/tests/unit/pie/test_factory.py index 2a21e29..46ea3b8 100644 --- a/kmip/tests/unit/pie/test_factory.py +++ b/kmip/tests/unit/pie/test_factory.py @@ -34,59 +34,8 @@ class TestObjectFactory(testtools.TestCase): super(TestObjectFactory, self).setUp() self.factory = factory.ObjectFactory() - # Encodings obtained from Sections 13.2, 13.4 and 14.2 of the KMIP 1.1 - # test documentation. - self.certificate_bytes = ( - b'\x30\x82\x03\x12\x30\x82\x01\xFA\xA0\x03\x02\x01\x02\x02\x01\x01' - b'\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30' - b'\x3B\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x0D' - b'\x30\x0B\x06\x03\x55\x04\x0A\x13\x04\x54\x45\x53\x54\x31\x0E\x30' - b'\x0C\x06\x03\x55\x04\x0B\x13\x05\x4F\x41\x53\x49\x53\x31\x0D\x30' - b'\x0B\x06\x03\x55\x04\x03\x13\x04\x4B\x4D\x49\x50\x30\x1E\x17\x0D' - b'\x31\x30\x31\x31\x30\x31\x32\x33\x35\x39\x35\x39\x5A\x17\x0D\x32' - b'\x30\x31\x31\x30\x31\x32\x33\x35\x39\x35\x39\x5A\x30\x3B\x31\x0B' - b'\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x0D\x30\x0B\x06' - b'\x03\x55\x04\x0A\x13\x04\x54\x45\x53\x54\x31\x0E\x30\x0C\x06\x03' - b'\x55\x04\x0B\x13\x05\x4F\x41\x53\x49\x53\x31\x0D\x30\x0B\x06\x03' - b'\x55\x04\x03\x13\x04\x4B\x4D\x49\x50\x30\x82\x01\x22\x30\x0D\x06' - b'\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F' - b'\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\xAB\x7F\x16\x1C\x00\x42' - b'\x49\x6C\xCD\x6C\x6D\x4D\xAD\xB9\x19\x97\x34\x35\x35\x77\x76\x00' - b'\x3A\xCF\x54\xB7\xAF\x1E\x44\x0A\xFB\x80\xB6\x4A\x87\x55\xF8\x00' - b'\x2C\xFE\xBA\x6B\x18\x45\x40\xA2\xD6\x60\x86\xD7\x46\x48\x34\x6D' - b'\x75\xB8\xD7\x18\x12\xB2\x05\x38\x7C\x0F\x65\x83\xBC\x4D\x7D\xC7' - b'\xEC\x11\x4F\x3B\x17\x6B\x79\x57\xC4\x22\xE7\xD0\x3F\xC6\x26\x7F' - b'\xA2\xA6\xF8\x9B\x9B\xEE\x9E\x60\xA1\xD7\xC2\xD8\x33\xE5\xA5\xF4' - b'\xBB\x0B\x14\x34\xF4\xE7\x95\xA4\x11\x00\xF8\xAA\x21\x49\x00\xDF' - b'\x8B\x65\x08\x9F\x98\x13\x5B\x1C\x67\xB7\x01\x67\x5A\xBD\xBC\x7D' - b'\x57\x21\xAA\xC9\xD1\x4A\x7F\x08\x1F\xCE\xC8\x0B\x64\xE8\xA0\xEC' - b'\xC8\x29\x53\x53\xC7\x95\x32\x8A\xBF\x70\xE1\xB4\x2E\x7B\xB8\xB7' - b'\xF4\xE8\xAC\x8C\x81\x0C\xDB\x66\xE3\xD2\x11\x26\xEB\xA8\xDA\x7D' - b'\x0C\xA3\x41\x42\xCB\x76\xF9\x1F\x01\x3D\xA8\x09\xE9\xC1\xB7\xAE' - b'\x64\xC5\x41\x30\xFB\xC2\x1D\x80\xE9\xC2\xCB\x06\xC5\xC8\xD7\xCC' - b'\xE8\x94\x6A\x9A\xC9\x9B\x1C\x28\x15\xC3\x61\x2A\x29\xA8\x2D\x73' - b'\xA1\xF9\x93\x74\xFE\x30\xE5\x49\x51\x66\x2A\x6E\xDA\x29\xC6\xFC' - b'\x41\x13\x35\xD5\xDC\x74\x26\xB0\xF6\x05\x02\x03\x01\x00\x01\xA3' - b'\x21\x30\x1F\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x04\xE5' - b'\x7B\xD2\xC4\x31\xB2\xE8\x16\xE1\x80\xA1\x98\x23\xFA\xC8\x58\x27' - b'\x3F\x6B\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05' - b'\x00\x03\x82\x01\x01\x00\xA8\x76\xAD\xBC\x6C\x8E\x0F\xF0\x17\x21' - b'\x6E\x19\x5F\xEA\x76\xBF\xF6\x1A\x56\x7C\x9A\x13\xDC\x50\xD1\x3F' - b'\xEC\x12\xA4\x27\x3C\x44\x15\x47\xCF\xAB\xCB\x5D\x61\xD9\x91\xE9' - b'\x66\x31\x9D\xF7\x2C\x0D\x41\xBA\x82\x6A\x45\x11\x2F\xF2\x60\x89' - b'\xA2\x34\x4F\x4D\x71\xCF\x7C\x92\x1B\x4B\xDF\xAE\xF1\x60\x0D\x1B' - b'\xAA\xA1\x53\x36\x05\x7E\x01\x4B\x8B\x49\x6D\x4F\xAE\x9E\x8A\x6C' - b'\x1D\xA9\xAE\xB6\xCB\xC9\x60\xCB\xF2\xFA\xE7\x7F\x58\x7E\xC4\xBB' - b'\x28\x20\x45\x33\x88\x45\xB8\x8D\xD9\xAE\xEA\x53\xE4\x82\xA3\x6E' - b'\x73\x4E\x4F\x5F\x03\xB9\xD0\xDF\xC4\xCA\xFC\x6B\xB3\x4E\xA9\x05' - b'\x3E\x52\xBD\x60\x9E\xE0\x1E\x86\xD9\xB0\x9F\xB5\x11\x20\xC1\x98' - b'\x34\xA9\x97\xB0\x9C\xE0\x8D\x79\xE8\x13\x11\x76\x2F\x97\x4B\xB1' - b'\xC8\xC0\x91\x86\xC4\xD7\x89\x33\xE0\xDB\x38\xE9\x05\x08\x48\x77' - b'\xE1\x47\xC7\x8A\xF5\x2F\xAE\x07\x19\x2F\xF1\x66\xD1\x9F\xA9\x4A' - b'\x11\xCC\x11\xB2\x7E\xD0\x50\xF7\xA2\x7F\xAE\x13\xB2\x05\xA5\x74' - b'\xC4\xEE\x00\xAA\x8B\xD6\x5D\x0D\x70\x57\xC9\x85\xC8\x39\xEF\x33' - b'\x6A\x44\x1E\xD5\x3A\x53\xC6\xB6\xB6\x96\xF1\xBD\xEB\x5F\x7E\xA8' - b'\x11\xEB\xB2\x5A\x7F\x86') + # Key encoding obtained from Sections 3.1.5, 13.2, 13.4, and 14.2 of + # the KMIP 1.1 test documentation. self.symmetric_bytes = ( b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E' b'\x0F') @@ -184,6 +133,59 @@ class TestObjectFactory(testtools.TestCase): b'\x17\xE1\xF0\xC9\xB2\x3A\xFF\xA4\xD4\x96\x61\x8D\xBC\x02\x49\x86' b'\xED\x69\x0B\xBB\x7B\x02\x57\x68\xFF\x9D\xF8\xAC\x15\x41\x6F\x48' b'\x9F\x81\x29\xC3\x23\x41\xA8\xB4\x4F') + self.certificate_bytes = ( + b'\x30\x82\x03\x12\x30\x82\x01\xFA\xA0\x03\x02\x01\x02\x02\x01\x01' + b'\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30' + b'\x3B\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x0D' + b'\x30\x0B\x06\x03\x55\x04\x0A\x13\x04\x54\x45\x53\x54\x31\x0E\x30' + b'\x0C\x06\x03\x55\x04\x0B\x13\x05\x4F\x41\x53\x49\x53\x31\x0D\x30' + b'\x0B\x06\x03\x55\x04\x03\x13\x04\x4B\x4D\x49\x50\x30\x1E\x17\x0D' + b'\x31\x30\x31\x31\x30\x31\x32\x33\x35\x39\x35\x39\x5A\x17\x0D\x32' + b'\x30\x31\x31\x30\x31\x32\x33\x35\x39\x35\x39\x5A\x30\x3B\x31\x0B' + b'\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x0D\x30\x0B\x06' + b'\x03\x55\x04\x0A\x13\x04\x54\x45\x53\x54\x31\x0E\x30\x0C\x06\x03' + b'\x55\x04\x0B\x13\x05\x4F\x41\x53\x49\x53\x31\x0D\x30\x0B\x06\x03' + b'\x55\x04\x03\x13\x04\x4B\x4D\x49\x50\x30\x82\x01\x22\x30\x0D\x06' + b'\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F' + b'\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\xAB\x7F\x16\x1C\x00\x42' + b'\x49\x6C\xCD\x6C\x6D\x4D\xAD\xB9\x19\x97\x34\x35\x35\x77\x76\x00' + b'\x3A\xCF\x54\xB7\xAF\x1E\x44\x0A\xFB\x80\xB6\x4A\x87\x55\xF8\x00' + b'\x2C\xFE\xBA\x6B\x18\x45\x40\xA2\xD6\x60\x86\xD7\x46\x48\x34\x6D' + b'\x75\xB8\xD7\x18\x12\xB2\x05\x38\x7C\x0F\x65\x83\xBC\x4D\x7D\xC7' + b'\xEC\x11\x4F\x3B\x17\x6B\x79\x57\xC4\x22\xE7\xD0\x3F\xC6\x26\x7F' + b'\xA2\xA6\xF8\x9B\x9B\xEE\x9E\x60\xA1\xD7\xC2\xD8\x33\xE5\xA5\xF4' + b'\xBB\x0B\x14\x34\xF4\xE7\x95\xA4\x11\x00\xF8\xAA\x21\x49\x00\xDF' + b'\x8B\x65\x08\x9F\x98\x13\x5B\x1C\x67\xB7\x01\x67\x5A\xBD\xBC\x7D' + b'\x57\x21\xAA\xC9\xD1\x4A\x7F\x08\x1F\xCE\xC8\x0B\x64\xE8\xA0\xEC' + b'\xC8\x29\x53\x53\xC7\x95\x32\x8A\xBF\x70\xE1\xB4\x2E\x7B\xB8\xB7' + b'\xF4\xE8\xAC\x8C\x81\x0C\xDB\x66\xE3\xD2\x11\x26\xEB\xA8\xDA\x7D' + b'\x0C\xA3\x41\x42\xCB\x76\xF9\x1F\x01\x3D\xA8\x09\xE9\xC1\xB7\xAE' + b'\x64\xC5\x41\x30\xFB\xC2\x1D\x80\xE9\xC2\xCB\x06\xC5\xC8\xD7\xCC' + b'\xE8\x94\x6A\x9A\xC9\x9B\x1C\x28\x15\xC3\x61\x2A\x29\xA8\x2D\x73' + b'\xA1\xF9\x93\x74\xFE\x30\xE5\x49\x51\x66\x2A\x6E\xDA\x29\xC6\xFC' + b'\x41\x13\x35\xD5\xDC\x74\x26\xB0\xF6\x05\x02\x03\x01\x00\x01\xA3' + b'\x21\x30\x1F\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x04\xE5' + b'\x7B\xD2\xC4\x31\xB2\xE8\x16\xE1\x80\xA1\x98\x23\xFA\xC8\x58\x27' + b'\x3F\x6B\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05' + b'\x00\x03\x82\x01\x01\x00\xA8\x76\xAD\xBC\x6C\x8E\x0F\xF0\x17\x21' + b'\x6E\x19\x5F\xEA\x76\xBF\xF6\x1A\x56\x7C\x9A\x13\xDC\x50\xD1\x3F' + b'\xEC\x12\xA4\x27\x3C\x44\x15\x47\xCF\xAB\xCB\x5D\x61\xD9\x91\xE9' + b'\x66\x31\x9D\xF7\x2C\x0D\x41\xBA\x82\x6A\x45\x11\x2F\xF2\x60\x89' + b'\xA2\x34\x4F\x4D\x71\xCF\x7C\x92\x1B\x4B\xDF\xAE\xF1\x60\x0D\x1B' + b'\xAA\xA1\x53\x36\x05\x7E\x01\x4B\x8B\x49\x6D\x4F\xAE\x9E\x8A\x6C' + b'\x1D\xA9\xAE\xB6\xCB\xC9\x60\xCB\xF2\xFA\xE7\x7F\x58\x7E\xC4\xBB' + b'\x28\x20\x45\x33\x88\x45\xB8\x8D\xD9\xAE\xEA\x53\xE4\x82\xA3\x6E' + b'\x73\x4E\x4F\x5F\x03\xB9\xD0\xDF\xC4\xCA\xFC\x6B\xB3\x4E\xA9\x05' + b'\x3E\x52\xBD\x60\x9E\xE0\x1E\x86\xD9\xB0\x9F\xB5\x11\x20\xC1\x98' + b'\x34\xA9\x97\xB0\x9C\xE0\x8D\x79\xE8\x13\x11\x76\x2F\x97\x4B\xB1' + b'\xC8\xC0\x91\x86\xC4\xD7\x89\x33\xE0\xDB\x38\xE9\x05\x08\x48\x77' + b'\xE1\x47\xC7\x8A\xF5\x2F\xAE\x07\x19\x2F\xF1\x66\xD1\x9F\xA9\x4A' + b'\x11\xCC\x11\xB2\x7E\xD0\x50\xF7\xA2\x7F\xAE\x13\xB2\x05\xA5\x74' + b'\xC4\xEE\x00\xAA\x8B\xD6\x5D\x0D\x70\x57\xC9\x85\xC8\x39\xEF\x33' + b'\x6A\x44\x1E\xD5\x3A\x53\xC6\xB6\xB6\x96\xF1\xBD\xEB\x5F\x7E\xA8' + b'\x11\xEB\xB2\x5A\x7F\x86') + self.secret_bytes = ( + b'\x53\x65\x63\x72\x65\x74\x50\x61\x73\x73\x77\x6F\x72\x64') def tearDown(self): super(TestObjectFactory, self).tearDown() @@ -345,17 +347,53 @@ class TestObjectFactory(testtools.TestCase): core_cert.certificate_type.enum, pie_cert.certificate_type) self.assertEqual(core_cert.certificate_value.value, pie_cert.value) - def test_build_pie_certificate_on_invalid_type(self): + def test_convert_secret_data_pie_to_core(self): """ - Test that a TypeError exception is raised when attempting to create a - Pie Certificate object from a core Certificate object with an - unsupported certificate type. + Test that a Pie secret data object can be converted into a core secret + data object. """ - core_cert = secrets.Certificate( - enums.CertificateTypeEnum.PGP, self.certificate_bytes) - args = (core_cert, ) - self.assertRaises( - TypeError, self.factory._build_pie_certificate, *args) + pie_secret = pobjects.SecretData( + self.secret_bytes, enums.SecretDataType.PASSWORD) + core_secret = self.factory.convert(pie_secret) + + self.assertIsInstance(core_secret, secrets.SecretData) + + data_type = core_secret.secret_data_type.enum + self.assertEqual(enums.SecretDataType.PASSWORD, data_type) + + key_block = core_secret.key_block + self.assertIsInstance(key_block, cobjects.KeyBlock) + + key_value = key_block.key_value + self.assertIsInstance(key_value, cobjects.KeyValue) + + key_material = key_value.key_material + self.assertIsInstance(key_material, cobjects.KeyMaterial) + self.assertEqual(self.secret_bytes, key_material.value) + + def test_convert_secret_data_core_to_pie(self): + """ + Test that a core secret data object can be converted into a Pie secret + data object. + """ + format_type = misc.KeyFormatType(enums.KeyFormatType.OPAQUE) + key_material = cobjects.KeyMaterial(self.secret_bytes) + key_value = cobjects.KeyValue(key_material) + key_block = cobjects.KeyBlock( + key_format_type=format_type, + key_compression_type=None, + key_value=key_value, + cryptographic_algorithm=None, + cryptographic_length=None, + key_wrapping_data=None) + data_type = secrets.SecretData.SecretDataType( + enums.SecretDataType.PASSWORD) + core_key = secrets.SecretData(data_type, key_block) + + pie_key = self.factory.convert(core_key) + self.assertIsInstance(pie_key, pobjects.SecretData) + self.assertEqual(enums.SecretDataType.PASSWORD, pie_key.data_type) + self.assertEqual(self.secret_bytes, pie_key.value) def test_build_pie_symmetric_key(self): """ @@ -446,6 +484,18 @@ class TestObjectFactory(testtools.TestCase): core_key, enums.CryptographicAlgorithm.AES, 128, self.symmetric_bytes, enums.KeyFormatType.RAW) + def test_build_pie_certificate_on_invalid_type(self): + """ + Test that a TypeError exception is raised when attempting to create a + Pie Certificate object from a core Certificate object with an + unsupported certificate type. + """ + core_cert = secrets.Certificate( + enums.CertificateTypeEnum.PGP, self.certificate_bytes) + args = (core_cert, ) + self.assertRaises( + TypeError, self.factory._build_pie_certificate, *args) + def _test_core_key(self, key, algorithm, length, value, format_type): key_block = key.key_block self.assertIsInstance(key_block, cobjects.KeyBlock)