From 43ecea23a6c0cedf056442717ef3f5ccf3739bb2 Mon Sep 17 00:00:00 2001
From: Peter Hamilton <peter.hamilton@jhuapl.edu>
Date: Fri, 13 Mar 2015 16:31:39 -0400
Subject: [PATCH] Updating the Register unit demo

This change updates the Register unit demo, adding support for the
registration of different types of secret objects. The changes required
to support this include implementation updates to the KeyValue backing
objects.
---
 kmip/core/factories/secrets.py            |  10 +-
 kmip/core/objects.py                      | 147 ++++++++-------
 kmip/core/server.py                       |   8 +-
 kmip/demos/units/register.py              |  86 ++-------
 kmip/demos/utils.py                       | 219 +++++++++++++++++++---
 kmip/tests/core/messages/test_messages.py |  49 +++--
 kmip/tests/core/test_server.py            |   8 +-
 kmip/tests/services/test_kmip_client.py   |  45 +++--
 8 files changed, 358 insertions(+), 214 deletions(-)

diff --git a/kmip/core/factories/secrets.py b/kmip/core/factories/secrets.py
index f09c891..0fda6ad 100644
--- a/kmip/core/factories/secrets.py
+++ b/kmip/core/factories/secrets.py
@@ -24,8 +24,8 @@ from kmip.core.misc import KeyFormatType
 
 from kmip.core.objects import Attribute
 from kmip.core.objects import KeyBlock
+from kmip.core.objects import KeyMaterial
 from kmip.core.objects import KeyWrappingData
-from kmip.core.objects import KeyValueStruct
 from kmip.core.objects import KeyValue
 
 from kmip.core.secrets import PrivateKey
@@ -84,12 +84,8 @@ class SecretFactory(object):
                 key_comp_type = KeyBlock.KeyCompressionType(
                     key_compression_type)
 
-            key_material = self.key_factory.create_key(key_type,
-                                                       key_value)
-            key_val_struc = KeyValueStruct(key_format_type=key_format_type,
-                                           key_material=key_material)
-            key_value = KeyValue(key_value=key_val_struc,
-                                 key_format_type=key_format_type)
+            key_material = KeyMaterial(key_value)
+            key_value = KeyValue(key_material)
             crypto_algorithm = CryptographicAlgorithm(cryptographic_algorithm)
             crypto_length = CryptographicLength(cryptographic_length)
 
diff --git a/kmip/core/objects.py b/kmip/core/objects.py
index 84746a8..f1b8964 100644
--- a/kmip/core/objects.py
+++ b/kmip/core/objects.py
@@ -19,7 +19,6 @@ from kmip.core import attributes
 from kmip.core.attributes import CryptographicParameters
 
 from kmip.core.factories.attribute_values import AttributeValueFactory
-from kmip.core.factories.keys import KeyFactory
 
 from kmip.core import enums
 from kmip.core.enums import AttributeType
@@ -373,13 +372,12 @@ class KeyBlock(Struct):
 
         self.key_format_type = KeyFormatType()
         self.key_format_type.read(tstream)
-        key_format_type = self.key_format_type.enum
 
         if self.is_tag_next(Tags.KEY_COMPRESSION_TYPE, tstream):
             self.key_compression_type = KeyBlock.KeyCompressionType()
             self.key_compression_type.read(tstream)
 
-        self.key_value = KeyValue(key_format_type=key_format_type)
+        self.key_value = KeyValue()
         self.key_value.read(tstream)
 
         if self.is_tag_next(Tags.CRYPTOGRAPHIC_ALGORITHM, tstream):
@@ -434,35 +432,78 @@ class KeyBlock(Struct):
 
 
 # 2.1.4
-class KeyValueString(ByteString):
+class KeyMaterial(ByteString):
 
     def __init__(self, value=None):
-        super(self.__class__, self).__init__(value, Tags.KEY_VALUE)
+        super(self.__class__, self).__init__(value, Tags.KEY_MATERIAL)
 
 
-class KeyValueStruct(Struct):
+# TODO (peter-hamilton) Get rid of this and replace with a KeyMaterial factory.
+class KeyMaterialStruct(Struct):
+
+    def __init__(self):
+        super(KeyMaterialStruct, self).__init__(Tags.SERVER_INFORMATION)
+
+        self.data = BytearrayStream()
+
+        self.validate()
+
+    def read(self, istream):
+        super(KeyMaterialStruct, self).read(istream)
+        tstream = BytearrayStream(istream.read(self.length))
+
+        self.data = BytearrayStream(tstream.read())
+
+        self.is_oversized(tstream)
+        self.validate()
+
+    def write(self, ostream):
+        tstream = BytearrayStream()
+        tstream.write(self.data.buffer)
+
+        self.length = tstream.length()
+        super(KeyMaterialStruct, self).write(ostream)
+        ostream.write(tstream.buffer)
+
+    def validate(self):
+        self.__validate()
+
+    def __validate(self):
+        # NOTE (peter-hamilton): Intentional pass, no way to validate data.
+        pass
+
+
+class KeyValue(Struct):
 
     def __init__(self,
-                 key_format_type=None,
                  key_material=None,
                  attributes=None):
         super(self.__class__, self).__init__(Tags.KEY_VALUE)
-        self.key_format_type = key_format_type
-        self.key_material = key_material
-        self.attributes = attributes
-        self.key_factory = KeyFactory()
+
+        if key_material is None:
+            self.key_material = KeyMaterial()
+        else:
+            self.key_material = key_material
+
+        if attributes is None:
+            self.attributes = list()
+        else:
+            self.attributes = attributes
+
         self.validate()
 
     def read(self, istream):
         super(self.__class__, self).read(istream)
         tstream = BytearrayStream(istream.read(self.length))
 
-        self.key_material = self.key_factory.create_key(self.key_format_type)
-        self.key_material.read(tstream)
+        # TODO (peter-hamilton) Replace this with a KeyMaterial factory.
+        if self.is_type_next(Types.STRUCTURE, tstream):
+            self.key_material = KeyMaterialStruct()
+            self.key_material.read(tstream)
+        else:
+            self.key_material = KeyMaterial()
+            self.key_material.read(tstream)
 
-        self.attributes = list()
-
-        # Read the attributes, 0 or more
         while self.is_tag_next(Tags.ATTRIBUTE, tstream):
             attribute = Attribute()
             attribute.read(tstream)
@@ -476,11 +517,9 @@ class KeyValueStruct(Struct):
 
         self.key_material.write(tstream)
 
-        if self.attributes is not None:
-            for attribute in self.attributes:
-                attribute.write(tstream)
+        for attribute in self.attributes:
+            attribute.write(tstream)
 
-        # Write the length and value of the credential
         self.length = tstream.length()
         super(self.__class__, self).write(ostream)
         ostream.write(tstream.buffer)
@@ -489,56 +528,26 @@ class KeyValueStruct(Struct):
         self.__validate()
 
     def __validate(self):
-        # TODO (peter-hamilton) Finish implementation.
-        pass
+        # TODO (peter-hamilton) Replace with check against KeyMaterial factory.
+        if not isinstance(self.key_material, KeyMaterial):
+            msg = "invalid key material"
+            msg += "; expected {0}, received {1}".format(
+                KeyMaterial, self.key_material)
+            raise TypeError(msg)
 
-
-class KeyValue(Struct):
-    '''
-    KeyValue can be either a ByteString or a Struct. Therefore, this class
-    acts as a wrapper for two different KeyValue objects, KeyValueString,
-    which represents the ByteString format, and KeyValueStruct, which
-    represents the Struct format, both of which are defined above. This
-    KeyValue object does not read or write itself; instead, it reads and
-    writes its internal key_value attribute, which is either a KeyValueString
-    or a KeyValueStruct.
-
-    When reading, the class determines what the format of its internal
-    structure should be by looking at the type of the object it will read
-    using KeyValue.is_type_next(). This is one of the only places in the
-    code where this approach is used.
-    '''
-
-    def __init__(self,
-                 key_value=None,
-                 key_format_type=None):
-        super(self.__class__, self).__init__(Tags.KEY_VALUE)
-        self.key_value = key_value
-        self.key_format_type = key_format_type
-        if self.key_value is not None:
-            self.type = key_value.type
-        self.validate()
-
-    def read(self, istream):
-        if self.is_type_next(Types.BYTE_STRING, istream):
-            self.key_value = KeyValueString()
-            self.key_value.read(istream)
-        elif self.is_type_next(Types.STRUCTURE, istream):
-            kft = self.key_format_type
-            self.key_value = KeyValueStruct(key_format_type=kft)
-            self.key_value.read(istream)
-
-    def write(self, ostream):
-        tstream = BytearrayStream()
-        self.key_value.write(tstream)
-        ostream.write(tstream.buffer)
-
-    def validate(self):
-        self.__validate()
-
-    def __validate(self):
-        # TODO (peter-hamilton) Finish implementation.
-        pass
+        if isinstance(self.attributes, list):
+            for i in xrange(len(self.attributes)):
+                attribute = self.attributes[i]
+                if not isinstance(attribute, Attribute):
+                    msg = "invalid attribute ({0} in list)".format(i)
+                    msg += "; expected {0}, received {1}".format(
+                        Attribute, attribute)
+                    raise TypeError(msg)
+        else:
+            msg = "invalid attributes list"
+            msg += "; expected {0}, received {1}".format(
+                list, self.attributes)
+            raise TypeError(msg)
 
 
 # 2.1.5
diff --git a/kmip/core/server.py b/kmip/core/server.py
index 33b66de..ff9aa00 100644
--- a/kmip/core/server.py
+++ b/kmip/core/server.py
@@ -29,7 +29,6 @@ from kmip.core.enums import ResultStatus as RS
 from kmip.core.factories.attributes import AttributeFactory
 from kmip.core.factories.keys import KeyFactory
 from kmip.core.factories.secrets import SecretFactory
-from kmip.core.keys import RawKey
 
 from kmip.core.messages.contents import ResultStatus
 from kmip.core.messages.contents import ResultReason
@@ -38,8 +37,8 @@ from kmip.core.messages.contents import ResultMessage
 from kmip.core.misc import KeyFormatType
 
 from kmip.core.objects import KeyBlock
+from kmip.core.objects import KeyMaterial
 from kmip.core.objects import KeyValue
-from kmip.core.objects import KeyValueStruct
 from kmip.core.objects import TemplateAttribute
 from kmip.core.repo.mem_repo import MemRepo
 from kmip.core.secrets import SymmetricKey
@@ -346,8 +345,8 @@ class KMIPImpl(KMIP):
 
     def _gen_symmetric_key(self, bit_length, crypto_alg):
         key_format_type = KeyFormatType(KeyFormatTypeEnum.RAW)
-        key_material = RawKey(bytearray(os.urandom(int(bit_length/8))))
-        key_value = KeyValueStruct(key_format_type, key_material)
+        key_material = KeyMaterial(os.urandom(int(bit_length/8)))
+        key_value = KeyValue(key_material)
         crypto_length = CryptographicLength(bit_length)
         key_block = KeyBlock(key_format_type, None, key_value, crypto_alg,
                              crypto_length, None)
@@ -385,7 +384,6 @@ class KMIPImpl(KMIP):
             kv = key_block.key_value
             if isinstance(kv, KeyValue):
                 kv = key_block.key_value
-            if isinstance(kv, KeyValueStruct):
                 if kv.attributes is not None:
                     self.logger.debug('adding the key value struct attributes')
                     attributes.extend(kv.attributes)
diff --git a/kmip/demos/units/register.py b/kmip/demos/units/register.py
index c2b0919..7bc04e4 100644
--- a/kmip/demos/units/register.py
+++ b/kmip/demos/units/register.py
@@ -13,19 +13,11 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-from kmip.core.enums import AttributeType
-from kmip.core.enums import CredentialType
-from kmip.core.enums import CryptographicAlgorithm
-from kmip.core.enums import CryptographicUsageMask
 from kmip.core.enums import KeyFormatType
 from kmip.core.enums import ObjectType
 from kmip.core.enums import Operation
 from kmip.core.enums import ResultStatus
 
-from kmip.core.factories.attributes import AttributeFactory
-from kmip.core.factories.credentials import CredentialFactory
-from kmip.core.factories.secrets import SecretFactory
-
 from kmip.core.objects import TemplateAttribute
 
 from kmip.demos import utils
@@ -38,87 +30,45 @@ import sys
 
 
 if __name__ == '__main__':
-    # Build and parse arguments
     parser = utils.build_cli_parser(Operation.REGISTER)
     opts, args = parser.parse_args(sys.argv[1:])
 
     username = opts.username
     password = opts.password
     config = opts.config
-    algorithm = opts.algorithm
-    length = opts.length
+    object_type = opts.type
+    format_type = opts.format
 
     # Exit early if the arguments are not specified
-    if algorithm is None:
-        logging.debug('No algorithm provided, exiting early from demo')
-        sys.exit()
-    if length is None:
-        logging.debug("No key length provided, exiting early from demo")
+    object_type = getattr(ObjectType, object_type, None)
+    if object_type is None:
+        logging.error("Invalid object type specified; exiting early from demo")
         sys.exit()
 
+    key_format_type = getattr(KeyFormatType, format_type, None)
+    if key_format_type is None:
+        logging.error(
+            "Invalid key format type specified; exiting early from demo")
+
     # Build and setup logging and needed factories
     f_log = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir,
                          'logconfig.ini')
     logging.config.fileConfig(f_log)
     logger = logging.getLogger(__name__)
 
-    attribute_factory = AttributeFactory()
-    credential_factory = CredentialFactory()
-    secret_factory = SecretFactory()
-
-    # Build the KMIP server account credentials
-    # TODO (peter-hamilton) Move up into KMIPProxy
-    if (username is None) and (password is None):
-        credential = None
-    else:
-        credential_type = CredentialType.USERNAME_AND_PASSWORD
-        credential_value = {'Username': username,
-                            'Password': password}
-        credential = credential_factory.create_credential(credential_type,
-                                                          credential_value)
-    # Build the client and connect to the server
-    client = KMIPProxy(config=config)
-    client.open()
-
-    # Build the different object attributes
-    object_type = ObjectType.SYMMETRIC_KEY
-
-    attribute_type = AttributeType.CRYPTOGRAPHIC_ALGORITHM
-    algorithm_enum = getattr(CryptographicAlgorithm, algorithm, None)
-
-    if algorithm_enum is None:
-        logging.debug("{0} not found".format(algorithm))
-        logging.debug("Invalid algorithm specified, exiting early from demo")
-
-        client.close()
-        sys.exit()
-
-    mask_flags = [CryptographicUsageMask.ENCRYPT,
-                  CryptographicUsageMask.DECRYPT]
-    attribute_type = AttributeType.CRYPTOGRAPHIC_USAGE_MASK
-    usage_mask = attribute_factory.create_attribute(attribute_type,
-                                                    mask_flags)
+    # Create the template attribute for the secret and then build the secret
+    usage_mask = utils.build_cryptographic_usage_mask(logger, object_type)
     attributes = [usage_mask]
     template_attribute = TemplateAttribute(attributes=attributes)
 
-    secret_features = {}
+    secret = utils.build_object(logger, object_type, key_format_type)
 
-    key_format_type = KeyFormatType.RAW
-    secret_features.update([('key_format_type', key_format_type)])
+    # Build the client, connect to the server, register the secret, and
+    # disconnect from the server
+    client = KMIPProxy(config=config)
 
-    # TODO (peter-hamilton) Replace with calls to crypto libraries
-    key_data = {'bytes': bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00'
-                                   b'\x00\x00\x00\x00\x00\x00\x00\x00')}
-
-    secret_features.update([('key_value', key_data)])
-    secret_features.update([('cryptographic_algorithm', algorithm_enum)])
-    secret_features.update([('cryptographic_length', length)])
-
-    secret = secret_factory.create(object_type, secret_features)
-
-    # Register the SYMMETRIC_KEY object
-    result = client.register(object_type, template_attribute, secret,
-                             credential)
+    client.open()
+    result = client.register(object_type, template_attribute, secret)
     client.close()
 
     # Display operation results
diff --git a/kmip/demos/utils.py b/kmip/demos/utils.py
index a8b18c8..6d5a724 100644
--- a/kmip/demos/utils.py
+++ b/kmip/demos/utils.py
@@ -13,10 +13,29 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+from kmip.core.attributes import CryptographicAlgorithm
+from kmip.core.attributes import CryptographicLength
+
+from kmip.core.enums import AttributeType
+from kmip.core.enums import CryptographicAlgorithm as CryptoAlgorithmEnum
+from kmip.core.enums import CryptographicUsageMask
 from kmip.core.enums import ObjectType
 from kmip.core.enums import Operation
 
+from kmip.core.factories.attributes import AttributeFactory
+
+from kmip.core.misc import KeyFormatType
+
+from kmip.core.objects import KeyBlock
+from kmip.core.objects import KeyMaterial
+from kmip.core.objects import KeyValue
+
+from kmip.core.secrets import PrivateKey
+from kmip.core.secrets import PublicKey
+from kmip.core.secrets import SymmetricKey
+
 import optparse
+import sys
 
 
 def build_cli_parser(operation):
@@ -130,21 +149,23 @@ def build_cli_parser(operation):
             help="Name of secret to retrieve from the KMIP server")
     elif operation is Operation.REGISTER:
         parser.add_option(
-            "-a",
-            "--algorithm",
+            "-f",
+            "--format",
             action="store",
             type="str",
-            default=None,
-            dest="algorithm",
-            help="Encryption algorithm for the secret (e.g., AES)")
+            default="RAW",
+            dest="format",
+            help=("Format in which to store the secret. Supported formats "
+                  "include: RAW, PKCS_1, PKCS_8, X_509"))
         parser.add_option(
-            "-l",
-            "--length",
+            "-t",
+            "--type",
             action="store",
-            type="int",
-            default=None,
-            dest="length",
-            help="Key length in bits (e.g., 128, 256)")
+            type="str",
+            default="SYMMETRIC_KEY",
+            dest="type",
+            help=("Type of the object to register. Supported types include: "
+                  "PRIVATE_KEY, PUBLIC_KEY, SYMMETRIC_KEY"))
     elif operation is Operation.QUERY:
         pass
     elif operation is Operation.DISCOVER_VERSIONS:
@@ -155,6 +176,162 @@ def build_cli_parser(operation):
     return parser
 
 
+def build_cryptographic_usage_mask(logger, object_type):
+    if object_type == ObjectType.SYMMETRIC_KEY:
+        flags = [CryptographicUsageMask.ENCRYPT,
+                 CryptographicUsageMask.DECRYPT]
+    elif object_type == ObjectType.PUBLIC_KEY:
+        flags = [CryptographicUsageMask.VERIFY]
+    elif object_type == ObjectType.PRIVATE_KEY:
+        flags = [CryptographicUsageMask.SIGN]
+    else:
+        logger.error("Unrecognized object type, could not build cryptographic "
+                     "usage mask")
+        sys.exit()
+
+    attribute_type = AttributeType.CRYPTOGRAPHIC_USAGE_MASK
+    attribute_factory = AttributeFactory()
+    usage_mask = attribute_factory.create_attribute(attribute_type, flags)
+
+    return usage_mask
+
+
+def build_object(logger, object_type, key_format_type):
+
+    key_value = build_key_value(logger, object_type)
+    cryptographic_algorithm = build_cryptographic_algorithm(
+        logger, object_type)
+    cryptographic_length = build_cryptographic_length(logger, object_type)
+
+    key_block = build_key_block(
+        key_format_type,
+        key_value,
+        cryptographic_algorithm,
+        cryptographic_length)
+
+    if object_type == ObjectType.SYMMETRIC_KEY:
+        return SymmetricKey(key_block)
+    elif object_type == ObjectType.PUBLIC_KEY:
+        return PublicKey(key_block)
+    elif object_type == ObjectType.PRIVATE_KEY:
+        return PrivateKey(key_block)
+    else:
+        logger.error("Unrecognized object type, could not build object")
+        sys.exit()
+
+
+def build_cryptographic_length(logger, object_type):
+    if object_type == ObjectType.SYMMETRIC_KEY:
+        return CryptographicLength(128)
+    elif object_type == ObjectType.PUBLIC_KEY:
+        return CryptographicLength(1024)
+    elif object_type == ObjectType.PRIVATE_KEY:
+        return CryptographicLength(1024)
+    else:
+        logger.error("Unrecognized object type, could not build cryptographic "
+                     "length")
+        sys.exit()
+
+
+def build_cryptographic_algorithm(logger, object_type):
+    if object_type == ObjectType.SYMMETRIC_KEY:
+        return CryptographicAlgorithm(CryptoAlgorithmEnum.AES)
+    elif object_type == ObjectType.PUBLIC_KEY:
+        return CryptographicAlgorithm(CryptoAlgorithmEnum.RSA)
+    elif object_type == ObjectType.PRIVATE_KEY:
+        return CryptographicAlgorithm(CryptoAlgorithmEnum.RSA)
+    else:
+        logger.error("Unrecognized object type, could not build cryptographic "
+                     "algorithm")
+        sys.exit()
+
+
+def build_key_value(logger, object_type):
+    if object_type == ObjectType.SYMMETRIC_KEY:
+        return (
+            b'\x30\x82\x02\x76\x02\x01\x00\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7'
+            b'\x0D\x01\x01\x01\x05\x00\x04\x82\x02\x60\x30\x82\x02\x5C\x02\x01'
+            b'\x00\x02\x81\x81\x00\x93\x04\x51\xC9\xEC\xD9\x4F\x5B\xB9\xDA\x17'
+            b'\xDD\x09\x38\x1B\xD2\x3B\xE4\x3E\xCA\x8C\x75\x39\xF3\x01\xFC\x8A'
+            b'\x8C\xD5\xD5\x27\x4C\x3E\x76\x99\xDB\xDC\x71\x1C\x97\xA7\xAA\x91'
+            b'\xE2\xC5\x0A\x82\xBD\x0B\x10\x34\xF0\xDF\x49\x3D\xEC\x16\x36\x24'
+            b'\x27\xE5\x8A\xCC\xE7\xF6\xCE\x0F\x9B\xCC\x61\x7B\xBD\x8C\x90\xD0'
+            b'\x09\x4A\x27\x03\xBA\x0D\x09\xEB\x19\xD1\x00\x5F\x2F\xB2\x65'
+            b'\x52')
+    elif object_type == ObjectType.PUBLIC_KEY:
+        return (
+            b'\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01'
+            b'\x05\x00\x03\x81\x8D\x00\x30\x81\x89\x02\x81\x81\x00\x93\x04\x51'
+            b'\xC9\xEC\xD9\x4F\x5B\xB9\xDA\x17\xDD\x09\x38\x1B\xD2\x3B\xE4\x3E'
+            b'\xCA\x8C\x75\x39\xF3\x01\xFC\x8A\x8C\xD5\xD5\x27\x4C\x3E\x76\x99'
+            b'\xDB\xDC\x71\x1C\x97\xA7\xAA\x91\xE2\xC5\x0A\x82\xBD\x0B\x10\x34'
+            b'\xF0\xDF\x49\x3D\xEC\x16\x36\x24\x27\xE5\x8A\xCC\xE7\xF6\xCE\x0F'
+            b'\x9B\xCC\x61\x7B\xBD\x8C\x90\xD0\x09\x4A\x27\x03\xBA\x0D\x09\xEB'
+            b'\x19\xD1\x00\x5F\x2F\xB2\x65\x52\x6A\xAC\x75\xAF\x32\xF8\xBC\x78'
+            b'\x2C\xDE\xD2\xA5\x7F\x81\x1E\x03\xEA\xF6\x7A\x94\x4D\xE5\xE7\x84'
+            b'\x13\xDC\xA8\xF2\x32\xD0\x74\xE6\xDC\xEA\x4C\xEC\x9F\x02\x03\x01'
+            b'\x00\x01')
+    elif object_type == ObjectType.PRIVATE_KEY:
+        return (
+            b'\x30\x82\x02\x76\x02\x01\x00\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7'
+            b'\x0D\x01\x01\x01\x05\x00\x04\x82\x02\x60\x30\x82\x02\x5C\x02\x01'
+            b'\x00\x02\x81\x81\x00\x93\x04\x51\xC9\xEC\xD9\x4F\x5B\xB9\xDA\x17'
+            b'\xDD\x09\x38\x1B\xD2\x3B\xE4\x3E\xCA\x8C\x75\x39\xF3\x01\xFC\x8A'
+            b'\x8C\xD5\xD5\x27\x4C\x3E\x76\x99\xDB\xDC\x71\x1C\x97\xA7\xAA\x91'
+            b'\xE2\xC5\x0A\x82\xBD\x0B\x10\x34\xF0\xDF\x49\x3D\xEC\x16\x36\x24'
+            b'\x27\xE5\x8A\xCC\xE7\xF6\xCE\x0F\x9B\xCC\x61\x7B\xBD\x8C\x90\xD0'
+            b'\x09\x4A\x27\x03\xBA\x0D\x09\xEB\x19\xD1\x00\x5F\x2F\xB2\x65\x52'
+            b'\x6A\xAC\x75\xAF\x32\xF8\xBC\x78\x2C\xDE\xD2\xA5\x7F\x81\x1E\x03'
+            b'\xEA\xF6\x7A\x94\x4D\xE5\xE7\x84\x13\xDC\xA8\xF2\x32\xD0\x74\xE6'
+            b'\xDC\xEA\x4C\xEC\x9F\x02\x03\x01\x00\x01\x02\x81\x80\x0B\x6A\x7D'
+            b'\x73\x61\x99\xEA\x48\xA4\x20\xE4\x53\x7C\xA0\xC7\xC0\x46\x78\x4D'
+            b'\xCB\xEA\xA6\x3B\xAE\xBC\x0B\xC1\x32\x78\x74\x49\xCD\xE8\xD7\xCA'
+            b'\xD0\xC0\xC8\x63\xC0\xFE\xFB\x06\xC3\x06\x2B\xEF\xC5\x00\x33\xEC'
+            b'\xF8\x7B\x4E\x33\xA9\xBE\x7B\xCB\xC8\xF1\x51\x1A\xE2\x15\xE8\x0D'
+            b'\xEB\x5D\x8A\xF2\xBD\x31\x31\x9D\x78\x21\x19\x66\x40\x93\x5A\x0C'
+            b'\xD6\x7C\x94\x59\x95\x79\xF2\x10\x0D\x65\xE0\x38\x83\x1F\xDA\xFB'
+            b'\x0D\xBE\x2B\xBD\xAC\x00\xA6\x96\xE6\x7E\x75\x63\x50\xE1\xC9\x9A'
+            b'\xCE\x11\xA3\x6D\xAB\xAC\x3E\xD3\xE7\x30\x96\x00\x59\x02\x41\x00'
+            b'\xDD\xF6\x72\xFB\xCC\x5B\xDA\x3D\x73\xAF\xFC\x4E\x79\x1E\x0C\x03'
+            b'\x39\x02\x24\x40\x5D\x69\xCC\xAA\xBC\x74\x9F\xAA\x0D\xCD\x4C\x25'
+            b'\x83\xC7\x1D\xDE\x89\x41\xA7\xB9\xAA\x03\x0F\x52\xEF\x14\x51\x46'
+            b'\x6C\x07\x4D\x4D\x33\x8F\xE6\x77\x89\x2A\xCD\x9E\x10\xFD\x35\xBD'
+            b'\x02\x41\x00\xA9\x8F\xBC\x3E\xD6\xB4\xC6\xF8\x60\xF9\x71\x65\xAC'
+            b'\x2F\x7B\xB6\xF2\xE2\xCB\x19\x2A\x9A\xBD\x49\x79\x5B\xE5\xBC\xF3'
+            b'\x7D\x8E\xE6\x9A\x6E\x16\x9C\x24\xE5\xC3\x2E\x4E\x7F\xA3\x32\x65'
+            b'\x46\x14\x07\xF9\x52\xBA\x49\xE2\x04\x81\x8A\x2F\x78\x5F\x11\x3F'
+            b'\x92\x2B\x8B\x02\x40\x25\x3F\x94\x70\x39\x0D\x39\x04\x93\x03\x77'
+            b'\x7D\xDB\xC9\x75\x0E\x9D\x64\x84\x9C\xE0\x90\x3E\xAE\x70\x4D\xC9'
+            b'\xF5\x89\xB7\x68\x0D\xEB\x9D\x60\x9F\xD5\xBC\xD4\xDE\xCD\x6F\x12'
+            b'\x05\x42\xE5\xCF\xF5\xD7\x6F\x2A\x43\xC8\x61\x5F\xB5\xB3\xA9\x21'
+            b'\x34\x63\x79\x7A\xA9\x02\x41\x00\xA1\xDD\xF0\x23\xC0\xCD\x94\xC0'
+            b'\x19\xBB\x26\xD0\x9B\x9E\x3C\xA8\xFA\x97\x1C\xB1\x6A\xA5\x8B\x9B'
+            b'\xAF\x79\xD6\x08\x1A\x1D\xBB\xA4\x52\xBA\x53\x65\x3E\x28\x04\xBA'
+            b'\x98\xFF\x69\xE8\xBB\x1B\x3A\x16\x1E\xA2\x25\xEA\x50\x14\x63\x21'
+            b'\x6A\x8D\xAB\x9B\x88\xA7\x5E\x5F\x02\x40\x61\x78\x64\x6E\x11\x2C'
+            b'\xF7\x9D\x92\x1A\x8A\x84\x3F\x17\xF6\xE7\xFF\x97\x4F\x68\x81\x22'
+            b'\x36\x5B\xF6\x69\x0C\xDF\xC9\x96\xE1\x89\x09\x52\xEB\x38\x20\xDD'
+            b'\x18\x90\xEC\x1C\x86\x19\xE8\x7A\x2B\xD3\x8F\x9D\x03\xB3\x7F\xAC'
+            b'\x74\x2E\xFB\x74\x8C\x78\x85\x94\x2C\x39')
+    else:
+        logger.error("Unrecognized object type, could not build key value")
+        sys.exit()
+
+
+def build_key_block(key_format_type, key_value, cryptographic_algorithm,
+                    cryptographic_length):
+    key_material = KeyMaterial(key_value)
+    key_value = KeyValue(key_material)
+
+    return KeyBlock(
+        key_format_type=KeyFormatType(key_format_type),
+        key_compression_type=None,
+        key_value=key_value,
+        cryptographic_algorithm=cryptographic_algorithm,
+        cryptographic_length=cryptographic_length,
+        key_wrapping_data=None)
+
+
 def log_template_attribute(logger, template_attribute):
     names = template_attribute.names
     attributes = template_attribute.attributes
@@ -164,7 +341,7 @@ def log_template_attribute(logger, template_attribute):
         name = names[i]
         logger.info('name {0}: {1}'.format(i, name))
 
-    log_attribute_list(attributes)
+    log_attribute_list(logger, attributes)
 
 
 def log_attribute_list(logger, attributes):
@@ -230,22 +407,14 @@ def log_key_block(logger, key_block):
 
 def log_key_value(logger, key_value):
     if key_value is not None:
-        key_format_type = key_value.key_format_type
-        key_value = key_value.key_value
+        logger.info('key value:')
 
-        logger.info('key format type: {0}'.format(key_format_type))
+        key_material = key_value.key_material
+        attributes = key_value.attributes
 
-        if key_value is not None:
-            logger.info('key value:')
+        logger.info('key material: {0}'.format(repr(key_material)))
 
-            key_material = key_value.key_material
-            attributes = key_value.attributes
-
-            logger.info('key material: {0}'.format(repr(key_material)))
-
-            log_attribute_list(logger, attributes)
-        else:
-            logger.info('key value: {0}'.format(key_value))
+        log_attribute_list(logger, attributes)
     else:
         logger.info('key value: {0}'.format(key_value))
 
diff --git a/kmip/tests/core/messages/test_messages.py b/kmip/tests/core/messages/test_messages.py
index f4e40e3..5145557 100644
--- a/kmip/tests/core/messages/test_messages.py
+++ b/kmip/tests/core/messages/test_messages.py
@@ -24,23 +24,22 @@ from kmip.core.attributes import ApplicationData
 from kmip.core.attributes import ApplicationNamespace
 from kmip.core.attributes import ApplicationSpecificInformation
 from kmip.core.attributes import ContactInformation
+from kmip.core.attributes import CryptographicAlgorithm
+from kmip.core.attributes import CryptographicLength
 from kmip.core.attributes import Name
 from kmip.core.attributes import ObjectGroup
 
 from kmip.core import enums
 from kmip.core.enums import AttributeType
-from kmip.core.enums import CryptographicAlgorithm
+from kmip.core.enums import CryptographicAlgorithm as CryptoAlgorithmEnum
 from kmip.core.enums import CryptographicUsageMask
 from kmip.core.enums import NameType
-from kmip.core.enums import ObjectType
 
 from kmip.core import errors
 from kmip.core.errors import ErrorStrings
 
 from kmip.core import objects
 
-from kmip.core.keys import RawKey
-
 from kmip.core.messages import contents
 from kmip.core.messages import messages
 from kmip.core.messages.payloads import create
@@ -357,7 +356,7 @@ class TestRequestMessage(TestCase):
         object_type = attr.ObjectType(enums.ObjectType.SYMMETRIC_KEY)
 
         name = AttributeType.CRYPTOGRAPHIC_ALGORITHM
-        value = CryptographicAlgorithm.AES
+        value = CryptoAlgorithmEnum.AES
         attr_a = self.attribute_factory.create_attribute(name, value)
 
         name = AttributeType.CRYPTOGRAPHIC_LENGTH
@@ -1341,13 +1340,13 @@ class TestResponseMessage(TestCase):
                                                   objects.KeyValue,
                                                   type(key_value)))
 
-            key_material = key_value.key_value.key_material
-            value = bytearray(b'\x73\x67\x57\x80\x51\x01\x2A\x6D\x13\x4A\x85'
-                              b'\x5E\x25\xC8\xCD\x5E\x4C\xA1\x31\x45\x57\x29'
-                              b'\xD3\xC8')
-            self.assertIsInstance(key_material, RawKey,
+            key_material = key_value.key_material
+            value = (
+                b'\x73\x67\x57\x80\x51\x01\x2A\x6D\x13\x4A\x85\x5E\x25\xC8\xCD'
+                b'\x5E\x4C\xA1\x31\x45\x57\x29\xD3\xC8')
+            self.assertIsInstance(key_material, objects.KeyMaterial,
                                   self.msg.format('key_material', 'type',
-                                                  RawKey,
+                                                  objects.KeyMaterial,
                                                   type(key_material)))
             exp = utils.hexlify_bytearray(value)
             obs = utils.hexlify_bytearray(key_material.value)
@@ -1395,17 +1394,29 @@ class TestResponseMessage(TestCase):
         uuid = '49a1ca88-6bea-4fb2-b450-7e58802c3038'
         uniq_id = attr.UniqueIdentifier(uuid)
 
-        key_type = enums.KeyFormatType.RAW
-        key = bytearray(b'\x73\x67\x57\x80\x51\x01\x2A\x6D\x13\x4A\x85\x5E\x25'
-                        b'\xC8\xCD\x5E\x4C\xA1\x31\x45\x57\x29\xD3\xC8')
+        key = (
+            b'\x73\x67\x57\x80\x51\x01\x2A\x6D\x13\x4A\x85\x5E\x25\xC8\xCD\x5E'
+            b'\x4C\xA1\x31\x45\x57\x29\xD3\xC8')
 
         crypto_algorithm = enums.CryptographicAlgorithm.TRIPLE_DES
         cryptographic_length = 168
-        value = {'key_format_type': key_type,
-                 'key_value': {'bytes': key},
-                 'cryptographic_algorithm': crypto_algorithm,
-                 'cryptographic_length': cryptographic_length}
-        secret = self.secret_factory.create(ObjectType.SYMMETRIC_KEY, value)
+        key_format_type = KeyFormatType(enums.KeyFormatType.RAW)
+
+        key_material = objects.KeyMaterial(key)
+        key_value = objects.KeyValue(key_material)
+        cryptographic_algorithm = CryptographicAlgorithm(crypto_algorithm)
+        cryptographic_length = CryptographicLength(cryptographic_length)
+
+        key_block = objects.KeyBlock(
+            key_format_type=key_format_type,
+            key_compression_type=None,
+            key_value=key_value,
+            cryptographic_algorithm=cryptographic_algorithm,
+            cryptographic_length=cryptographic_length,
+            key_wrapping_data=None)
+
+        secret = SymmetricKey(key_block)
+
         resp_pl = get.GetResponsePayload(object_type=object_type,
                                          unique_identifier=uniq_id,
                                          secret=secret)
diff --git a/kmip/tests/core/test_server.py b/kmip/tests/core/test_server.py
index 17d7e70..65c7d23 100644
--- a/kmip/tests/core/test_server.py
+++ b/kmip/tests/core/test_server.py
@@ -33,13 +33,13 @@ from kmip.core.enums import ResultStatus
 from kmip.core.enums import NameType
 
 from kmip.core.factories.attributes import AttributeFactory
-from kmip.core.keys import RawKey
 
 from kmip.core.messages.contents import KeyCompressionType
 from kmip.core.misc import KeyFormatType
 
 from kmip.core.objects import KeyBlock
-from kmip.core.objects import KeyValueStruct
+from kmip.core.objects import KeyMaterial
+from kmip.core.objects import KeyValue
 from kmip.core.objects import TemplateAttribute
 
 from kmip.core.secrets import SymmetricKey
@@ -472,8 +472,8 @@ class TestKMIPServer(TestCase):
         # only need usage attribute
         attrs = [self._get_attrs()[1]]
         key_format_type = KeyFormatType(KeyFormatTypeEnum.RAW)
-        key_material = RawKey(self.key)
-        key_value = KeyValueStruct(key_format_type, key_material, attrs)
+        key_material = KeyMaterial(self.key)
+        key_value = KeyValue(key_material, attrs)
         crypto_alg = CryptographicAlgorithm(self.algorithm_name)
         crypto_length = CryptographicLength(self.key_length)
         usage = CryptographicUsageMask(self.usage_mask)
diff --git a/kmip/tests/services/test_kmip_client.py b/kmip/tests/services/test_kmip_client.py
index 33f3758..8592859 100644
--- a/kmip/tests/services/test_kmip_client.py
+++ b/kmip/tests/services/test_kmip_client.py
@@ -21,15 +21,17 @@ import os
 import sys
 import time
 
+from kmip.core.attributes import CryptographicAlgorithm
+from kmip.core.attributes import CryptographicLength
 from kmip.core.attributes import PrivateKeyUniqueIdentifier
 
 from kmip.core.enums import AttributeType
 from kmip.core.enums import CredentialType
-from kmip.core.enums import CryptographicAlgorithm
+from kmip.core.enums import CryptographicAlgorithm as CryptoAlgorithmEnum
 from kmip.core.enums import CryptographicUsageMask
 from kmip.core.enums import ObjectType
 from kmip.core.enums import Operation as OperationEnum
-from kmip.core.enums import KeyFormatType
+from kmip.core.enums import KeyFormatType as KeyFormatTypeEnum
 from kmip.core.enums import QueryFunction as QueryFunctionEnum
 from kmip.core.enums import ResultStatus
 from kmip.core.enums import ResultReason
@@ -44,10 +46,8 @@ from kmip.core.factories.secrets import SecretFactory
 from kmip.core.messages.messages import RequestBatchItem
 from kmip.core.messages.messages import ResponseBatchItem
 from kmip.core.messages.messages import ResponseMessage
-
 from kmip.core.messages.contents import Operation
 from kmip.core.messages.contents import ProtocolVersion
-
 from kmip.core.messages.payloads.create_key_pair import \
     CreateKeyPairRequestPayload, CreateKeyPairResponsePayload
 from kmip.core.messages.payloads.discover_versions import \
@@ -57,6 +57,7 @@ from kmip.core.messages.payloads.query import \
 from kmip.core.messages.payloads.rekey_key_pair import \
     RekeyKeyPairRequestPayload, RekeyKeyPairResponsePayload
 
+from kmip.core.misc import KeyFormatType
 from kmip.core.misc import Offset
 from kmip.core.misc import QueryFunction
 from kmip.core.misc import ServerInformation
@@ -64,6 +65,9 @@ from kmip.core.misc import VendorIdentification
 
 from kmip.core.objects import Attribute
 from kmip.core.objects import CommonTemplateAttribute
+from kmip.core.objects import KeyBlock
+from kmip.core.objects import KeyMaterial
+from kmip.core.objects import KeyValue
 from kmip.core.objects import PrivateKeyTemplateAttribute
 from kmip.core.objects import PublicKeyTemplateAttribute
 from kmip.core.objects import TemplateAttribute
@@ -218,7 +222,7 @@ class TestKMIPClientIntegration(TestCase):
                                                          credential_value)
 
         object_type = ObjectType.SYMMETRIC_KEY
-        algorithm_value = CryptographicAlgorithm.AES
+        algorithm_value = CryptoAlgorithmEnum.AES
         mask_flags = [CryptographicUsageMask.ENCRYPT,
                       CryptographicUsageMask.DECRYPT]
         attribute_type = AttributeType.CRYPTOGRAPHIC_USAGE_MASK
@@ -227,19 +231,26 @@ class TestKMIPClientIntegration(TestCase):
         attributes = [usage_mask]
         template_attribute = TemplateAttribute(attributes=attributes)
 
-        secret_features = {}
+        key_format_type = KeyFormatType(KeyFormatTypeEnum.RAW)
 
-        key_format_type = KeyFormatType.RAW
-        secret_features.update([('key_format_type', key_format_type)])
+        key_data = (
+            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+            b'\x00')
 
-        key_data = {'bytes': bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00'
-                                       b'\x00\x00\x00\x00\x00\x00\x00\x00')}
+        key_material = KeyMaterial(key_data)
+        key_value = KeyValue(key_material)
+        cryptographic_algorithm = CryptographicAlgorithm(algorithm_value)
+        cryptographic_length = CryptographicLength(128)
 
-        secret_features.update([('key_value', key_data)])
-        secret_features.update([('cryptographic_algorithm', algorithm_value)])
-        secret_features.update([('cryptographic_length', 128)])
+        key_block = KeyBlock(
+            key_format_type=key_format_type,
+            key_compression_type=None,
+            key_value=key_value,
+            cryptographic_algorithm=cryptographic_algorithm,
+            cryptographic_length=cryptographic_length,
+            key_wrapping_data=None)
 
-        secret = self.secret_factory.create(object_type, secret_features)
+        secret = SymmetricKey(key_block)
 
         result = self.client.register(object_type, template_attribute, secret,
                                       credential)
@@ -273,9 +284,9 @@ class TestKMIPClientIntegration(TestCase):
 
         key_block = result.secret.key_block
         key_value = key_block.key_value
-        key_material = key_value.key_value.key_material
+        key_material = key_value.key_material
 
-        expected = key_data.get('bytes')
+        expected = key_data
         observed = key_material.value
         message = utils.build_er_error(key_material.__class__, 'value',
                                        expected, observed, 'value')
@@ -303,7 +314,7 @@ class TestKMIPClientIntegration(TestCase):
         attribute_type = AttributeType.CRYPTOGRAPHIC_ALGORITHM
         algorithm = self.attr_factory.create_attribute(
             attribute_type,
-            CryptographicAlgorithm.AES)
+            CryptoAlgorithmEnum.AES)
 
         mask_flags = [CryptographicUsageMask.ENCRYPT,
                       CryptographicUsageMask.DECRYPT]