Пример #1
0
    def setUp(self):
        super(TestKMIPClientIntegration, self).setUp()

        self.attr_factory = AttributeFactory()
        self.cred_factory = CredentialFactory()
        self.secret_factory = SecretFactory()

        # Set up the KMIP server process
        path = os.path.join(os.path.dirname(__file__), os.path.pardir, 'utils',
                            'server.py')
        self.server = Popen(
            ['python', '{0}'.format(path), '-p', '{0}'.format(self.KMIP_PORT)],
            stderr=sys.stdout)

        time.sleep(self.STARTUP_TIME)

        if self.server.poll() is not None:
            raise KMIPServerSuicideError(self.server.pid)

        # Set up and open the client proxy; shutdown the server if open fails
        try:
            self.client = KMIPProxy(port=self.KMIP_PORT,
                                    ca_certs=self.CA_CERTS_PATH)
            self.client.open()
        except Exception as e:
            self._shutdown_server()
            raise e
Пример #2
0
    def __init__(self,
                 host=None,
                 port=None,
                 keyfile=None,
                 certfile=None,
                 cert_reqs=None,
                 ssl_version=None,
                 ca_certs=None,
                 do_handshake_on_connect=None,
                 suppress_ragged_eofs=None,
                 username=None,
                 password=None,
                 timeout=30,
                 config='client'):
        super(KMIPProxy, self).__init__()
        self.logger = logging.getLogger(__name__)
        self.credential_factory = CredentialFactory()
        self.config = config

        self._set_variables(host, port, keyfile, certfile, cert_reqs,
                            ssl_version, ca_certs, do_handshake_on_connect,
                            suppress_ragged_eofs, username, password, timeout)
        self.batch_items = []

        self.conformance_clauses = [ConformanceClause.DISCOVER_VERSIONS]

        self.authentication_suites = [
            AuthenticationSuite.BASIC, AuthenticationSuite.TLS12
        ]
        self.socket = None
Пример #3
0
    def setUp(self):
        super(TestKMIPClientIntegration, self).setUp()

        self.attr_factory = AttributeFactory()
        self.cred_factory = CredentialFactory()
        self.secret_factory = SecretFactory()

        # Set up the KMIP server process
        path = os.path.join(os.path.dirname(__file__), os.path.pardir,
                            'utils', 'server.py')
        self.server = Popen(['python', '{0}'.format(path), '-p',
                             '{0}'.format(self.KMIP_PORT)], stderr=sys.stdout)

        time.sleep(self.STARTUP_TIME)

        if self.server.poll() is not None:
            raise KMIPServerSuicideError(self.server.pid)

        # Set up and open the client proxy; shutdown the server if open fails
        try:
            self.client = KMIPProxy(port=self.KMIP_PORT,
                                    ca_certs=self.CA_CERTS_PATH)
            self.client.open()
        except Exception as e:
            self._shutdown_server()
            raise e
Пример #4
0
    def setUp(self):
        super(TestIntegration, self).setUp()

        self.logger = logging.getLogger(__name__)

        self.attr_factory = AttributeFactory()
        self.cred_factory = CredentialFactory()
        self.secret_factory = SecretFactory()
Пример #5
0
def get_kmip_client():
    credential_factory = CredentialFactory()
    credential_type = CredentialType.USERNAME_AND_PASSWORD
    credential_value = {
        'Username': Kms.KMS_USER_NAME, 'Password': Kms.KMS_PASSWORD}
    credential = credential_factory.create_credential(credential_type,
                                                      credential_value)
    client = KMIPProxy(
        host=Kms.KMS_HOST,
        port=Kms.KMS_PORT,
        cert_reqs=Kms.KMS_CERT_REQUIRES,
        ssl_version=Kms.KMS_SSL_VERSION,
        certfile=Kms.KMS_CLIENT_CERTFILE,
        ca_certs=Kms.KMS_CA_CERTS,
        keyfile=Kms.KMS_KEY_FILE,
        do_handshake_on_connect=Kms.KMS_HANDSHAKE_ON_CONNECT,
        suppress_ragged_eofs=Kms.KMS_SUPPRESSED_RAGGED_EOFS,
        username=Kms.KMS_USER_NAME,
        password=Kms.KMS_PASSWORD)
    if client:
        client.open()
    return (client, credential)
Пример #6
0
    def __init__(self, host=None, port=None, keyfile=None, certfile=None,
                 cert_reqs=None, ssl_version=None, ca_certs=None,
                 do_handshake_on_connect=None,
                 suppress_ragged_eofs=None,
                 username=None, password=None, config='client'):
        super(self.__class__, self).__init__()
        self.logger = logging.getLogger(__name__)
        self.credential_factory = CredentialFactory()
        self.config = config

        self._set_variables(host, port, keyfile, certfile,
                            cert_reqs, ssl_version, ca_certs,
                            do_handshake_on_connect, suppress_ragged_eofs,
                            username, password)
        self.batch_items = []
Пример #7
0
    def setUp(self):
        super(TestKMIPClient, self).setUp()

        self.attr_factory = AttributeFactory()
        self.cred_factory = CredentialFactory()
        self.secret_factory = SecretFactory()

        self.client = KMIPProxy()

        KMIP_PORT = 9090
        CA_CERTS_PATH = os.path.normpath(os.path.join(os.path.dirname(
            os.path.abspath(__file__)), '../utils/certs/server.crt'))

        self.mock_client = KMIPProxy(host="IP_ADDR_1, IP_ADDR_2",
                                     port=KMIP_PORT, ca_certs=CA_CERTS_PATH)
        self.mock_client.socket = mock.MagicMock()
        self.mock_client.socket.connect = mock.MagicMock()
        self.mock_client.socket.close = mock.MagicMock()
Пример #8
0
    def __init__(
        self,
        host=None,
        port=None,
        keyfile=None,
        certfile=None,
        cert_reqs=None,
        ssl_version=None,
        ca_certs=None,
        do_handshake_on_connect=None,
        suppress_ragged_eofs=None,
        username=None,
        password=None,
        timeout=30,
        config="client",
    ):
        super(KMIPProxy, self).__init__()
        self.logger = logging.getLogger(__name__)
        self.credential_factory = CredentialFactory()
        self.config = config

        self._set_variables(
            host,
            port,
            keyfile,
            certfile,
            cert_reqs,
            ssl_version,
            ca_certs,
            do_handshake_on_connect,
            suppress_ragged_eofs,
            username,
            password,
            timeout,
        )
        self.batch_items = []

        self.conformance_clauses = [ConformanceClause.DISCOVER_VERSIONS]

        self.authentication_suites = [AuthenticationSuite.BASIC, AuthenticationSuite.TLS12]
        self.socket = None
Пример #9
0
    opts, args = parser.parse_args(sys.argv[1:])

    username = opts.username
    password = opts.password
    config = opts.config
    name = opts.name
    initial_dates = opts.initial_dates
    state = opts.state
    object_type = opts.object_type
    cryptographic_algorithm = opts.cryptographic_algorithm
    cryptographic_length = opts.cryptographic_length
    unique_identifier = opts.unique_identifier
    operation_policy_name = opts.operation_policy_name

    attribute_factory = AttributeFactory()
    credential_factory = CredentialFactory()

    # 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 = enums.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 = kmip_client.KMIPProxy(config=config, config_file=opts.config_file)
    client.open()
Пример #10
0
    config = opts.config
    name = opts.name

    # Exit early if the UUID is not specified
    if name is None:
        logging.debug('No name provided, exiting early from demo')
        sys.exit()

    # 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()

    # 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()
Пример #11
0
class TestKMIPClientIntegration(TestCase):
    STARTUP_TIME = 1.0
    SHUTDOWN_TIME = 0.1
    KMIP_PORT = 9090
    CA_CERTS_PATH = os.path.normpath(os.path.join(os.path.dirname(
        os.path.abspath(__file__)), '../../demos/certs/server.crt'))

    def setUp(self):
        super(TestKMIPClientIntegration, self).setUp()

        self.attr_factory = AttributeFactory()
        self.cred_factory = CredentialFactory()
        self.secret_factory = SecretFactory()

        # Set up the KMIP server process
        path = os.path.join(os.path.dirname(__file__), os.path.pardir,
                            'utils', 'server.py')
        self.server = Popen(['python', '{0}'.format(path), '-p',
                             '{0}'.format(self.KMIP_PORT)], stderr=sys.stdout)

        time.sleep(self.STARTUP_TIME)

        if self.server.poll() is not None:
            raise KMIPServerSuicideError(self.server.pid)

        # Set up and open the client proxy; shutdown the server if open fails
        try:
            self.client = KMIPProxy(port=self.KMIP_PORT,
                                    ca_certs=self.CA_CERTS_PATH)
            self.client.open()
        except Exception as e:
            self._shutdown_server()
            raise e

    def tearDown(self):
        super(TestKMIPClientIntegration, self).tearDown()

        # Close the client proxy and shutdown the server
        self.client.close()
        self._shutdown_server()

    def test_create(self):
        result = self._create_symmetric_key()

        self._check_result_status(result.result_status.enum, ResultStatus,
                                  ResultStatus.SUCCESS)
        self._check_object_type(result.object_type.enum, ObjectType,
                                ObjectType.SYMMETRIC_KEY)
        self._check_uuid(result.uuid.value, str)

        # Check the template attribute type
        self._check_template_attribute(result.template_attribute,
                                       TemplateAttribute, 2,
                                       [[str, 'Cryptographic Length', int,
                                         256],
                                        [str, 'Unique Identifier', str,
                                         None]])

    def test_get(self):
        credential_type = CredentialType.USERNAME_AND_PASSWORD
        credential_value = {'Username': '******', 'Password': '******'}
        credential = self.cred_factory.create_credential(credential_type,
                                                         credential_value)
        result = self._create_symmetric_key()
        uuid = result.uuid.value

        result = self.client.get(uuid=uuid, credential=credential)

        self._check_result_status(result.result_status.enum, ResultStatus,
                                  ResultStatus.SUCCESS)
        self._check_object_type(result.object_type.enum, ObjectType,
                                ObjectType.SYMMETRIC_KEY)
        self._check_uuid(result.uuid.value, str)

        # Check the secret type
        secret = result.secret

        expected = SymmetricKey
        message = utils.build_er_error(result.__class__, 'type', expected,
                                       secret, 'secret')
        self.assertIsInstance(secret, expected, message)

    def test_destroy(self):
        credential_type = CredentialType.USERNAME_AND_PASSWORD
        credential_value = {'Username': '******', 'Password': '******'}
        credential = self.cred_factory.create_credential(credential_type,
                                                         credential_value)
        result = self._create_symmetric_key()
        uuid = result.uuid.value

        # Verify the secret was created
        result = self.client.get(uuid=uuid, credential=credential)

        self._check_result_status(result.result_status.enum, ResultStatus,
                                  ResultStatus.SUCCESS)
        self._check_object_type(result.object_type.enum, ObjectType,
                                ObjectType.SYMMETRIC_KEY)
        self._check_uuid(result.uuid.value, str)

        secret = result.secret

        expected = SymmetricKey
        message = utils.build_er_error(result.__class__, 'type', expected,
                                       secret, 'secret')
        self.assertIsInstance(secret, expected, message)

        # Destroy the SYMMETRIC_KEY object
        result = self.client.destroy(uuid, credential)
        self._check_result_status(result.result_status.enum, ResultStatus,
                                  ResultStatus.SUCCESS)
        self._check_uuid(result.uuid.value, str)

        # Verify the secret was destroyed
        result = self.client.get(uuid=uuid, credential=credential)

        self._check_result_status(result.result_status.enum, ResultStatus,
                                  ResultStatus.OPERATION_FAILED)

        expected = ResultReason
        observed = type(result.result_reason.enum)
        message = utils.build_er_error(result.result_reason.__class__, 'type',
                                       expected, observed)
        self.assertEqual(expected, observed, message)

        expected = ResultReason.ITEM_NOT_FOUND
        observed = result.result_reason.enum
        message = utils.build_er_error(result.result_reason.__class__,
                                       'value', expected, observed)
        self.assertEqual(expected, observed, message)

    def test_register(self):
        credential_type = CredentialType.USERNAME_AND_PASSWORD
        credential_value = {'Username': '******', 'Password': '******'}
        credential = self.cred_factory.create_credential(credential_type,
                                                         credential_value)

        object_type = ObjectType.SYMMETRIC_KEY
        algorithm_value = CryptoAlgorithmEnum.AES
        mask_flags = [CryptographicUsageMask.ENCRYPT,
                      CryptographicUsageMask.DECRYPT]
        attribute_type = AttributeType.CRYPTOGRAPHIC_USAGE_MASK
        usage_mask = self.attr_factory.create_attribute(attribute_type,
                                                        mask_flags)
        attributes = [usage_mask]
        template_attribute = TemplateAttribute(attributes=attributes)

        key_format_type = KeyFormatType(KeyFormatTypeEnum.RAW)

        key_data = (
            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
            b'\x00')

        key_material = KeyMaterial(key_data)
        key_value = KeyValue(key_material)
        cryptographic_algorithm = CryptographicAlgorithm(algorithm_value)
        cryptographic_length = CryptographicLength(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 = SymmetricKey(key_block)

        result = self.client.register(object_type, template_attribute, secret,
                                      credential)

        self._check_result_status(result.result_status.enum, ResultStatus,
                                  ResultStatus.SUCCESS)
        self._check_uuid(result.uuid.value, str)

        # Check the template attribute type
        self._check_template_attribute(result.template_attribute,
                                       TemplateAttribute, 1,
                                       [[str, 'Unique Identifier', str,
                                         None]])
        # Check that the returned key bytes match what was provided
        uuid = result.uuid.value
        result = self.client.get(uuid=uuid, credential=credential)

        self._check_result_status(result.result_status.enum, ResultStatus,
                                  ResultStatus.SUCCESS)
        self._check_object_type(result.object_type.enum, ObjectType,
                                ObjectType.SYMMETRIC_KEY)
        self._check_uuid(result.uuid.value, str)

        # Check the secret type
        secret = result.secret

        expected = SymmetricKey
        message = utils.build_er_error(result.__class__, 'type', expected,
                                       secret, 'secret')
        self.assertIsInstance(secret, expected, message)

        key_block = result.secret.key_block
        key_value = key_block.key_value
        key_material = key_value.key_material

        expected = key_data
        observed = key_material.value
        message = utils.build_er_error(key_material.__class__, 'value',
                                       expected, observed, 'value')
        self.assertEqual(expected, observed, message)

    def _shutdown_server(self):
        if self.server.poll() is not None:
            return
        else:
            # Terminate the server process. If it resists, kill it.
            pid = self.server.pid
            self.server.terminate()
            time.sleep(self.SHUTDOWN_TIME)

            if self.server.poll() is None:
                raise KMIPServerZombieError(pid)

    def _create_symmetric_key(self):
        credential_type = CredentialType.USERNAME_AND_PASSWORD
        credential_value = {'Username': '******', 'Password': '******'}
        credential = self.cred_factory.create_credential(credential_type,
                                                         credential_value)

        object_type = ObjectType.SYMMETRIC_KEY
        attribute_type = AttributeType.CRYPTOGRAPHIC_ALGORITHM
        algorithm = self.attr_factory.create_attribute(
            attribute_type,
            CryptoAlgorithmEnum.AES)

        mask_flags = [CryptographicUsageMask.ENCRYPT,
                      CryptographicUsageMask.DECRYPT]
        attribute_type = AttributeType.CRYPTOGRAPHIC_USAGE_MASK
        usage_mask = self.attr_factory.create_attribute(attribute_type,
                                                        mask_flags)
        attributes = [algorithm, usage_mask]
        template_attribute = TemplateAttribute(attributes=attributes)

        return self.client.create(object_type, template_attribute,
                                  credential)

    def _check_result_status(self, result_status, result_status_type,
                             result_status_value):
        # Error check the result status type and value
        expected = result_status_type
        message = utils.build_er_error(result_status_type, 'type', expected,
                                       result_status)
        self.assertIsInstance(result_status, expected, message)

        expected = result_status_value
        message = utils.build_er_error(result_status_type, 'value', expected,
                                       result_status)
        self.assertEqual(expected, result_status, message)

    def _check_uuid(self, uuid, uuid_type):
        # Error check the UUID type and value
        not_expected = None
        message = utils.build_er_error(uuid_type, 'type',
                                       'not {0}'.format(not_expected), uuid)
        self.assertNotEqual(not_expected, uuid, message)

        expected = uuid_type
        message = utils.build_er_error(uuid_type, 'type', expected, uuid)
        self.assertEqual(expected, type(uuid), message)

    def _check_object_type(self, object_type, object_type_type,
                           object_type_value):
        # Error check the object type type and value
        expected = object_type_type
        message = utils.build_er_error(object_type_type, 'type', expected,
                                       object_type)
        self.assertIsInstance(object_type, expected, message)

        expected = object_type_value
        message = utils.build_er_error(object_type_type, 'value', expected,
                                       object_type)
        self.assertEqual(expected, object_type, message)

    def _check_template_attribute(self, template_attribute,
                                  template_attribute_type, num_attributes,
                                  attribute_features):
        # Error check the template attribute type
        expected = template_attribute_type
        message = utils.build_er_error(template_attribute.__class__, 'type',
                                       expected, template_attribute)
        self.assertIsInstance(template_attribute, expected, message)

        attributes = template_attribute.attributes

        expected = num_attributes
        observed = len(attributes)
        message = utils.build_er_error(TemplateAttribute.__class__, 'number',
                                       expected, observed, 'attributes')

        for i in range(num_attributes):
            features = attribute_features[i]
            self._check_attribute(attributes[i], features[0], features[1],
                                  features[2], features[3])

    def _check_attribute(self, attribute, attribute_name_type,
                         attribute_name_value, attribute_value_type,
                         attribute_value_value):
        # Error check the attribute name and value type and value
        attribute_name = attribute.attribute_name
        attribute_value = attribute.attribute_value

        self._check_attribute_name(attribute_name, attribute_name_type,
                                   attribute_name_value)

        if attribute_name_value == 'Unique Identifier':
            self._check_uuid(attribute_value.value, attribute_value_type)
        else:
            self._check_attribute_value(attribute_value, attribute_value_type,
                                        attribute_value_value)

    def _check_attribute_name(self, attribute_name, attribute_name_type,
                              attribute_name_value):
        # Error check the attribute name type and value
        expected = attribute_name_type
        observed = type(attribute_name.value)
        message = utils.build_er_error(attribute_name_type, 'type', expected,
                                       observed)
        self.assertEqual(expected, observed, message)

        expected = attribute_name_value
        observed = attribute_name.value
        message = utils.build_er_error(attribute_name_type, 'value', expected,
                                       observed)
        self.assertEqual(expected, observed, message)

    def _check_attribute_value(self, attribute_value, attribute_value_type,
                               attribute_value_value):
        expected = attribute_value_type
        observed = type(attribute_value.value)
        message = utils.build_er_error(Attribute, 'type', expected, observed,
                                       'attribute_value')
        self.assertEqual(expected, observed, message)

        expected = attribute_value_value
        observed = attribute_value.value
        message = utils.build_er_error(Attribute, 'value', expected, observed,
                                       'attribute_value')
        self.assertEqual(expected, observed, message)
Пример #12
0
class KMIPProxy(KMIP):

    def __init__(self, host=None, port=None, keyfile=None,
                 certfile=None,
                 cert_reqs=None, ssl_version=None, ca_certs=None,
                 do_handshake_on_connect=None,
                 suppress_ragged_eofs=None,
                 username=None, password=None, timeout=30, config='client'):
        super(KMIPProxy, self).__init__()
        self.logger = logging.getLogger(__name__)
        self.credential_factory = CredentialFactory()
        self.config = config

        self._set_variables(host, port, keyfile, certfile,
                            cert_reqs, ssl_version, ca_certs,
                            do_handshake_on_connect, suppress_ragged_eofs,
                            username, password, timeout)
        self.batch_items = []

        self.conformance_clauses = [
            ConformanceClause.DISCOVER_VERSIONS]

        self.authentication_suites = [
            AuthenticationSuite.BASIC,
            AuthenticationSuite.TLS12]
        self.socket = None

    def get_supported_conformance_clauses(self):
        """
        Get the list of conformance clauses supported by the client.

        Returns:
            list: A shallow copy of the list of supported conformance clauses.

        Example:
            >>> client.get_supported_conformance_clauses()
            [<ConformanceClause.DISCOVER_VERSIONS: 1>]
        """
        return self.conformance_clauses[:]

    def get_supported_authentication_suites(self):
        """
        Get the list of authentication suites supported by the client.

        Returns:
            list: A shallow copy of the list of supported authentication
                suites.

        Example:
            >>> client.get_supported_authentication_suites()
            [<AuthenticationSuite.BASIC: 1>, <AuthenticationSuite.TLS12: 2>]
        """
        return self.authentication_suites[:]

    def is_conformance_clause_supported(self, conformance_clause):
        """
        Check if a ConformanceClause is supported by the client.

        Args:
            conformance_clause (ConformanceClause): A ConformanceClause
                enumeration to check against the list of supported
                ConformanceClauses.

        Returns:
            bool: True if the ConformanceClause is supported, False otherwise.

        Example:
            >>> clause = ConformanceClause.DISCOVER_VERSIONS
            >>> client.is_conformance_clause_supported(clause)
            True
            >>> clause = ConformanceClause.BASELINE
            >>> client.is_conformance_clause_supported(clause)
            False
        """
        return conformance_clause in self.conformance_clauses

    def is_authentication_suite_supported(self, authentication_suite):
        """
        Check if an AuthenticationSuite is supported by the client.

        Args:
            authentication_suite (AuthenticationSuite): An AuthenticationSuite
                enumeration to check against the list of supported
                AuthenticationSuites.

        Returns:
            bool: True if the AuthenticationSuite is supported, False
                otherwise.

        Example:
            >>> suite = AuthenticationSuite.BASIC
            >>> client.is_authentication_suite_supported(suite)
            True
            >>> suite = AuthenticationSuite.TLS12
            >>> client.is_authentication_suite_supported(suite)
            False
        """
        return authentication_suite in self.authentication_suites

    def is_profile_supported(self, conformance_clause, authentication_suite):
        """
        Check if a profile is supported by the client.

        Args:
            conformance_clause (ConformanceClause):
            authentication_suite (AuthenticationSuite):

        Returns:
            bool: True if the profile is supported, False otherwise.

        Example:
            >>> client.is_profile_supported(
            ... ConformanceClause.DISCOVER_VERSIONS,
            ... AuthenticationSuite.BASIC)
            True
        """
        return (self.is_conformance_clause_supported(conformance_clause) and
                self.is_authentication_suite_supported(authentication_suite))

    def open(self):

        self.logger.debug("KMIPProxy keyfile: {0}".format(self.keyfile))
        self.logger.debug("KMIPProxy certfile: {0}".format(self.certfile))
        self.logger.debug(
            "KMIPProxy cert_reqs: {0} (CERT_REQUIRED: {1})".format(
                self.cert_reqs, ssl.CERT_REQUIRED))
        self.logger.debug(
            "KMIPProxy ssl_version: {0} (PROTOCOL_SSLv23: {1})".format(
                self.ssl_version, ssl.PROTOCOL_SSLv23))
        self.logger.debug("KMIPProxy ca_certs: {0}".format(self.ca_certs))
        self.logger.debug("KMIPProxy do_handshake_on_connect: {0}".format(
            self.do_handshake_on_connect))
        self.logger.debug("KMIPProxy suppress_ragged_eofs: {0}".format(
            self.suppress_ragged_eofs))

        last_error = None

        for host in self.host_list:
            self.host = host
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self._create_socket(sock)
            self.protocol = KMIPProtocol(self.socket)
            try:
                self.socket.connect((self.host, self.port))
            except Exception as e:
                self.logger.error("An error occurred while connecting to "
                                  "appliance " + self.host)
                self.socket.close()
                last_error = e
            else:
                return

        self.socket = None
        if last_error:
            raise last_error

    def _create_socket(self, sock):
        self.socket = ssl.wrap_socket(
            sock,
            keyfile=self.keyfile,
            certfile=self.certfile,
            cert_reqs=self.cert_reqs,
            ssl_version=self.ssl_version,
            ca_certs=self.ca_certs,
            do_handshake_on_connect=self.do_handshake_on_connect,
            suppress_ragged_eofs=self.suppress_ragged_eofs)
        self.socket.settimeout(self.timeout)

    def __del__(self):
        # Close the socket properly, helpful in case close() is not called.
        self.close()

    def close(self):
        # Shutdown and close the socket.
        if self.socket:
            try:
                self.socket.shutdown(socket.SHUT_RDWR)
                self.socket.close()
            except OSError:
                # Can be thrown if the socket is not actually connected to
                # anything. In this case, ignore the error.
                pass
            self.socket = None

    def create(self, object_type, template_attribute, credential=None):
        object_type = attr.ObjectType(object_type)
        return self._create(object_type=object_type,
                            template_attribute=template_attribute,
                            credential=credential)

    def create_key_pair(self, batch=False, common_template_attribute=None,
                        private_key_template_attribute=None,
                        public_key_template_attribute=None, credential=None):
        batch_item = self._build_create_key_pair_batch_item(
            common_template_attribute, private_key_template_attribute,
            public_key_template_attribute)

        if batch:
            self.batch_items.append(batch_item)
        else:
            request = self._build_request_message(credential, [batch_item])
            response = self._send_and_receive_message(request)
            results = self._process_batch_items(response)
            return results[0]

    def activate(self, uuid=None, credential=None):
        """
        Send an Activate request to the server.

        Args:
            uuid (string): The unique identifier of a managed cryptographic
                object that should be activated.
            credential (Credential): A Credential object containing
                authentication information for the server. Optional, defaults
                to None.
        """
        return self._activate(uuid, credential=credential)

    def get(self, uuid=None, key_format_type=None, key_compression_type=None,
            key_wrapping_specification=None, credential=None):
        return self._get(
            unique_identifier=uuid,
            key_format_type=key_format_type,
            key_compression_type=key_compression_type,
            key_wrapping_specification=key_wrapping_specification,
            credential=credential)

    def get_attributes(self, uuid=None, attribute_names=None):
        """
        Send a GetAttributes request to the server.

        Args:
            uuid (string): The ID of the managed object with which the
                retrieved attributes should be associated. Optional, defaults
                to None.
            attribute_names (list): A list of AttributeName values indicating
                what object attributes the client wants from the server.
                Optional, defaults to None.

        Returns:
            result (GetAttributesResult): A structure containing the results
                of the operation.
        """
        batch_item = self._build_get_attributes_batch_item(
            uuid,
            attribute_names
        )

        request = self._build_request_message(None, [batch_item])
        response = self._send_and_receive_message(request)
        results = self._process_batch_items(response)
        return results[0]

    def get_attribute_list(self, uid=None):
        """
        Send a GetAttributeList request to the server.

        Args:
            uid (string): The ID of the managed object with which the retrieved
                attribute names should be associated.

        Returns:
            result (GetAttributeListResult): A structure containing the results
                of the operation.
        """
        batch_item = self._build_get_attribute_list_batch_item(uid)

        request = self._build_request_message(None, [batch_item])
        response = self._send_and_receive_message(request)
        results = self._process_batch_items(response)
        return results[0]

    def revoke(self, revocation_reason, uuid=None, revocation_message=None,
               compromise_occurrence_date=None, credential=None):
        return self._revoke(
            unique_identifier=uuid,
            revocation_reason=revocation_reason,
            revocation_message=revocation_message,
            compromise_occurrence_date=compromise_occurrence_date,
            credential=credential)

    def destroy(self, uuid=None, credential=None):
        return self._destroy(unique_identifier=uuid,
                             credential=credential)

    def register(self, object_type, template_attribute, secret,
                 credential=None):
        object_type = attr.ObjectType(object_type)
        return self._register(object_type=object_type,
                              template_attribute=template_attribute,
                              secret=secret,
                              credential=credential)

    def rekey_key_pair(self, batch=False, private_key_uuid=None, offset=None,
                       common_template_attribute=None,
                       private_key_template_attribute=None,
                       public_key_template_attribute=None, credential=None):
        batch_item = self._build_rekey_key_pair_batch_item(
            private_key_uuid, offset, common_template_attribute,
            private_key_template_attribute, public_key_template_attribute)

        if batch:
            self.batch_items.append(batch_item)
        else:
            request = self._build_request_message(credential, [batch_item])
            response = self._send_and_receive_message(request)
            results = self._process_batch_items(response)
            return results[0]

    def locate(self, maximum_items=None, storage_status_mask=None,
               object_group_member=None, attributes=None, credential=None):
        return self._locate(maximum_items=maximum_items,
                            storage_status_mask=storage_status_mask,
                            object_group_member=object_group_member,
                            attributes=attributes, credential=credential)

    def query(self, batch=False, query_functions=None, credential=None):
        """
        Send a Query request to the server.

        Args:
            batch (boolean): A flag indicating if the operation should be sent
                with a batch of additional operations. Defaults to False.
            query_functions (list): A list of QueryFunction enumerations
                indicating what information the client wants from the server.
                Optional, defaults to None.
            credential (Credential): A Credential object containing
                authentication information for the server. Optional, defaults
                to None.
        """
        batch_item = self._build_query_batch_item(query_functions)

        # TODO (peter-hamilton): Replace this with official client batch mode.
        if batch:
            self.batch_items.append(batch_item)
        else:
            request = self._build_request_message(credential, [batch_item])
            response = self._send_and_receive_message(request)
            results = self._process_batch_items(response)
            return results[0]

    def discover_versions(self, batch=False, protocol_versions=None,
                          credential=None):
        batch_item = self._build_discover_versions_batch_item(
            protocol_versions)

        if batch:
            self.batch_items.append(batch_item)
        else:
            request = self._build_request_message(credential, [batch_item])
            response = self._send_and_receive_message(request)
            results = self._process_batch_items(response)
            return results[0]

    def mac(self, data, unique_identifier=None,
            cryptographic_parameters=None, credential=None):
        return self._mac(
            data=data,
            unique_identifier=unique_identifier,
            cryptographic_parameters=cryptographic_parameters,
            credential=credential)

    def _create(self,
                object_type=None,
                template_attribute=None,
                credential=None):
        operation = Operation(OperationEnum.CREATE)

        if object_type is None:
            raise ValueError('object_type cannot be None')

        req_pl = create.CreateRequestPayload(
            object_type=object_type,
            template_attribute=template_attribute)
        batch_item = messages.RequestBatchItem(operation=operation,
                                               request_payload=req_pl)

        message = self._build_request_message(credential, [batch_item])
        self._send_message(message)
        message = messages.ResponseMessage()
        data = self._receive_message()
        message.read(data)
        batch_items = message.batch_items
        batch_item = batch_items[0]
        payload = batch_item.response_payload

        if payload is None:
            payload_unique_identifier = None
            payload_template_attribute = None
            payload_object_type = None
        else:
            payload_unique_identifier = payload.unique_identifier
            payload_template_attribute = payload.template_attribute
            payload_object_type = payload.object_type

        result = CreateResult(batch_item.result_status,
                              batch_item.result_reason,
                              batch_item.result_message,
                              payload_object_type,
                              payload_unique_identifier,
                              payload_template_attribute)
        return result

    def _build_create_key_pair_batch_item(self, common_template_attribute=None,
                                          private_key_template_attribute=None,
                                          public_key_template_attribute=None):
        operation = Operation(OperationEnum.CREATE_KEY_PAIR)
        payload = create_key_pair.CreateKeyPairRequestPayload(
            common_template_attribute=common_template_attribute,
            private_key_template_attribute=private_key_template_attribute,
            public_key_template_attribute=public_key_template_attribute)
        batch_item = messages.RequestBatchItem(
            operation=operation, request_payload=payload)
        return batch_item

    def _build_rekey_key_pair_batch_item(self,
                                         private_key_uuid=None, offset=None,
                                         common_template_attribute=None,
                                         private_key_template_attribute=None,
                                         public_key_template_attribute=None):
        operation = Operation(OperationEnum.REKEY_KEY_PAIR)
        payload = rekey_key_pair.RekeyKeyPairRequestPayload(
            private_key_uuid, offset,
            common_template_attribute=common_template_attribute,
            private_key_template_attribute=private_key_template_attribute,
            public_key_template_attribute=public_key_template_attribute)
        batch_item = messages.RequestBatchItem(
            operation=operation, request_payload=payload)
        return batch_item

    def _build_query_batch_item(self, query_functions=None):
        operation = Operation(OperationEnum.QUERY)
        payload = query.QueryRequestPayload(query_functions)
        batch_item = messages.RequestBatchItem(
            operation=operation, request_payload=payload)
        return batch_item

    def _build_get_attributes_batch_item(
            self,
            uuid=None,
            attribute_names=None
    ):
        operation = Operation(OperationEnum.GET_ATTRIBUTES)
        payload = get_attributes.GetAttributesRequestPayload(
            uuid,
            attribute_names
        )
        batch_item = messages.RequestBatchItem(
            operation=operation,
            request_payload=payload
        )
        return batch_item

    def _build_get_attribute_list_batch_item(self, uid=None):
        operation = Operation(OperationEnum.GET_ATTRIBUTE_LIST)
        payload = get_attribute_list.GetAttributeListRequestPayload(uid)
        batch_item = messages.RequestBatchItem(
            operation=operation, request_payload=payload)
        return batch_item

    def _build_discover_versions_batch_item(self, protocol_versions=None):
        operation = Operation(OperationEnum.DISCOVER_VERSIONS)

        payload = discover_versions.DiscoverVersionsRequestPayload(
            protocol_versions)

        batch_item = messages.RequestBatchItem(
            operation=operation, request_payload=payload)
        return batch_item

    def _process_batch_items(self, response):
        results = []
        for batch_item in response.batch_items:
            operation = None
            if batch_item.operation is not None:
                operation = batch_item.operation.value
            processor = self._get_batch_item_processor(operation)
            result = processor(batch_item)
            results.append(result)
        return results

    def _get_batch_item_processor(self, operation):
        if operation is None:
            return self._process_response_error
        elif operation == OperationEnum.CREATE_KEY_PAIR:
            return self._process_create_key_pair_batch_item
        elif operation == OperationEnum.GET_ATTRIBUTES:
            return self._process_get_attributes_batch_item
        elif operation == OperationEnum.GET_ATTRIBUTE_LIST:
            return self._process_get_attribute_list_batch_item
        elif operation == OperationEnum.REKEY_KEY_PAIR:
            return self._process_rekey_key_pair_batch_item
        elif operation == OperationEnum.QUERY:
            return self._process_query_batch_item
        elif operation == OperationEnum.DISCOVER_VERSIONS:
            return self._process_discover_versions_batch_item
        else:
            raise ValueError("no processor for operation: {0}".format(
                operation))

    def _process_get_attributes_batch_item(self, batch_item):
        payload = batch_item.response_payload

        uuid = None
        attributes = None

        if payload:
            uuid = payload.unique_identifier
            attributes = payload.attributes

        return GetAttributesResult(
            batch_item.result_status,
            batch_item.result_reason,
            batch_item.result_message,
            uuid,
            attributes
        )

    def _process_get_attribute_list_batch_item(self, batch_item):
        payload = batch_item.response_payload

        uid = None
        names = None

        if payload:
            uid = payload.unique_identifier
            names = payload.attribute_names

        return GetAttributeListResult(
            batch_item.result_status,
            batch_item.result_reason,
            batch_item.result_message,
            uid,
            names)

    def _process_key_pair_batch_item(self, batch_item, result):
        payload = batch_item.response_payload

        payload_private_key_uuid = None
        payload_public_key_uuid = None
        payload_private_key_template_attribute = None
        payload_public_key_template_attribute = None

        if payload is not None:
            payload_private_key_uuid = payload.private_key_uuid
            payload_public_key_uuid = payload.public_key_uuid
            payload_private_key_template_attribute = \
                payload.private_key_template_attribute
            payload_public_key_template_attribute = \
                payload.public_key_template_attribute

        return result(batch_item.result_status, batch_item.result_reason,
                      batch_item.result_message, payload_private_key_uuid,
                      payload_public_key_uuid,
                      payload_private_key_template_attribute,
                      payload_public_key_template_attribute)

    def _process_create_key_pair_batch_item(self, batch_item):
        return self._process_key_pair_batch_item(
            batch_item, CreateKeyPairResult)

    def _process_rekey_key_pair_batch_item(self, batch_item):
        return self._process_key_pair_batch_item(
            batch_item, RekeyKeyPairResult)

    def _process_query_batch_item(self, batch_item):
        payload = batch_item.response_payload

        operations = None
        object_types = None
        vendor_identification = None
        server_information = None
        application_namespaces = None
        extension_information = None

        if payload is not None:
            operations = payload.operations
            object_types = payload.object_types
            vendor_identification = payload.vendor_identification
            server_information = payload.server_information
            application_namespaces = payload.application_namespaces
            extension_information = payload.extension_information

        return QueryResult(
            batch_item.result_status,
            batch_item.result_reason,
            batch_item.result_message,
            operations,
            object_types,
            vendor_identification,
            server_information,
            application_namespaces,
            extension_information)

    def _process_discover_versions_batch_item(self, batch_item):
        payload = batch_item.response_payload

        result = DiscoverVersionsResult(
            batch_item.result_status, batch_item.result_reason,
            batch_item.result_message, payload.protocol_versions)

        return result

    def _process_response_error(self, batch_item):
        result = OperationResult(
            batch_item.result_status, batch_item.result_reason,
            batch_item.result_message)
        return result

    def _get(self,
             unique_identifier=None,
             key_format_type=None,
             key_compression_type=None,
             key_wrapping_specification=None,
             credential=None):
        operation = Operation(OperationEnum.GET)

        uuid = None
        kft = None
        kct = None
        kws = None

        if unique_identifier is not None:
            uuid = attr.UniqueIdentifier(unique_identifier)
        if key_format_type is not None:
            kft = get.GetRequestPayload.KeyFormatType(key_format_type.value)
        if key_compression_type is not None:
            kct = key_compression_type
            kct = get.GetRequestPayload.KeyCompressionType(kct)
        if key_wrapping_specification is not None:
            kws = objects.KeyWrappingSpecification(key_wrapping_specification)

        req_pl = get.GetRequestPayload(unique_identifier=uuid,
                                       key_format_type=kft,
                                       key_compression_type=kct,
                                       key_wrapping_specification=kws)

        batch_item = messages.RequestBatchItem(operation=operation,
                                               request_payload=req_pl)
        message = self._build_request_message(credential, [batch_item])
        self._send_message(message)
        message = messages.ResponseMessage()
        data = self._receive_message()
        message.read(data)
        batch_items = message.batch_items
        batch_item = batch_items[0]
        payload = batch_item.response_payload

        if payload is None:
            payload_unique_identifier = None
            payload_object_type = None
            payload_secret = None
        else:
            payload_unique_identifier = payload.unique_identifier
            payload_object_type = payload.object_type
            payload_secret = payload.secret

        result = GetResult(batch_item.result_status,
                           batch_item.result_reason,
                           batch_item.result_message,
                           payload_object_type,
                           payload_unique_identifier,
                           payload_secret)
        return result

    def _activate(self, unique_identifier=None, credential=None):
        operation = Operation(OperationEnum.ACTIVATE)

        uuid = None
        if unique_identifier is not None:
            uuid = attr.UniqueIdentifier(unique_identifier)

        payload = activate.ActivateRequestPayload(unique_identifier=uuid)

        batch_item = messages.RequestBatchItem(operation=operation,
                                               request_payload=payload)
        message = self._build_request_message(credential, [batch_item])
        self._send_message(message)
        message = messages.ResponseMessage()
        data = self._receive_message()
        message.read(data)
        batch_items = message.batch_items
        batch_item = batch_items[0]
        payload = batch_item.response_payload

        if payload is None:
            payload_unique_identifier = None
        else:
            payload_unique_identifier = payload.unique_identifier

        result = ActivateResult(batch_item.result_status,
                                batch_item.result_reason,
                                batch_item.result_message,
                                payload_unique_identifier)
        return result

    def _destroy(self,
                 unique_identifier=None,
                 credential=None):
        operation = Operation(OperationEnum.DESTROY)

        uuid = None
        if unique_identifier is not None:
            uuid = attr.UniqueIdentifier(unique_identifier)

        payload = destroy.DestroyRequestPayload(unique_identifier=uuid)

        batch_item = messages.RequestBatchItem(operation=operation,
                                               request_payload=payload)
        message = self._build_request_message(credential, [batch_item])
        self._send_message(message)
        message = messages.ResponseMessage()
        data = self._receive_message()
        message.read(data)
        batch_items = message.batch_items
        batch_item = batch_items[0]
        payload = batch_item.response_payload

        if payload is None:
            payload_unique_identifier = None
        else:
            payload_unique_identifier = payload.unique_identifier

        result = DestroyResult(batch_item.result_status,
                               batch_item.result_reason,
                               batch_item.result_message,
                               payload_unique_identifier)
        return result

    def _revoke(self, unique_identifier=None, revocation_reason=None,
                revocation_message=None, compromise_occurrence_date=None,
                credential=None):
        operation = Operation(OperationEnum.REVOKE)

        reason = objects.RevocationReason(code=revocation_reason,
                                          message=revocation_message)
        uuid = None
        if unique_identifier is not None:
            uuid = attr.UniqueIdentifier(unique_identifier)

        payload = revoke.RevokeRequestPayload(
            unique_identifier=uuid,
            revocation_reason=reason,
            compromise_occurrence_date=compromise_occurrence_date)

        batch_item = messages.RequestBatchItem(operation=operation,
                                               request_payload=payload)
        message = self._build_request_message(credential, [batch_item])
        self._send_message(message)
        message = messages.ResponseMessage()
        data = self._receive_message()
        message.read(data)
        batch_items = message.batch_items
        batch_item = batch_items[0]
        payload = batch_item.response_payload

        if payload is None:
            payload_unique_identifier = None
        else:
            payload_unique_identifier = payload.unique_identifier

        result = RevokeResult(batch_item.result_status,
                              batch_item.result_reason,
                              batch_item.result_message,
                              payload_unique_identifier)
        return result

    def _register(self,
                  object_type=None,
                  template_attribute=None,
                  secret=None,
                  credential=None):
        operation = Operation(OperationEnum.REGISTER)

        if object_type is None:
            raise ValueError('object_type cannot be None')

        req_pl = register.RegisterRequestPayload(
            object_type=object_type,
            template_attribute=template_attribute,
            secret=secret)
        batch_item = messages.RequestBatchItem(operation=operation,
                                               request_payload=req_pl)

        message = self._build_request_message(credential, [batch_item])
        self._send_message(message)
        message = messages.ResponseMessage()
        data = self._receive_message()
        message.read(data)
        batch_items = message.batch_items
        batch_item = batch_items[0]
        payload = batch_item.response_payload

        if payload is None:
            payload_unique_identifier = None
            payload_template_attribute = None
        else:
            payload_unique_identifier = payload.unique_identifier
            payload_template_attribute = payload.template_attribute

        result = RegisterResult(batch_item.result_status,
                                batch_item.result_reason,
                                batch_item.result_message,
                                payload_unique_identifier,
                                payload_template_attribute)
        return result

    def _locate(self, maximum_items=None, storage_status_mask=None,
                object_group_member=None, attributes=[], credential=None):

        operation = Operation(OperationEnum.LOCATE)

        mxi = None
        ssmask = None
        objgrp = None

        if maximum_items is not None:
            mxi = locate.LocateRequestPayload.MaximumItems(maximum_items)
        if storage_status_mask is not None:
            m = storage_status_mask
            ssmask = locate.LocateRequestPayload.StorageStatusMask(m)
        if object_group_member is not None:
            o = object_group_member
            objgrp = locate.LocateRequestPayload.ObjectGroupMember(o)

        payload = locate.LocateRequestPayload(maximum_items=mxi,
                                              storage_status_mask=ssmask,
                                              object_group_member=objgrp,
                                              attributes=attributes)

        batch_item = messages.RequestBatchItem(operation=operation,
                                               request_payload=payload)

        message = self._build_request_message(credential, [batch_item])
        self._send_message(message)
        message = messages.ResponseMessage()
        data = self._receive_message()

        message.read(data)
        batch_items = message.batch_items
        batch_item = batch_items[0]
        payload = batch_item.response_payload

        if payload is None:
            uuids = None
        else:
            uuids = payload.unique_identifiers

        result = LocateResult(batch_item.result_status,
                              batch_item.result_reason,
                              batch_item.result_message,
                              uuids)
        return result

    def _mac(self,
             data,
             unique_identifier=None,
             cryptographic_parameters=None,
             credential=None):
        operation = Operation(OperationEnum.MAC)

        req_pl = mac.MACRequestPayload(
            unique_identifier=attr.UniqueIdentifier(unique_identifier),
            cryptographic_parameters=cryptographic_parameters,
            data=objects.Data(data))
        batch_item = messages.RequestBatchItem(operation=operation,
                                               request_payload=req_pl)

        message = self._build_request_message(credential, [batch_item])
        self._send_message(message)
        message = messages.ResponseMessage()
        data = self._receive_message()
        message.read(data)
        batch_items = message.batch_items
        batch_item = batch_items[0]
        payload = batch_item.response_payload

        if payload is None:
            payload_unique_identifier = None
            payload_mac_data = None
        else:
            payload_unique_identifier = payload.unique_identifier
            payload_mac_data = payload.mac_data

        result = MACResult(batch_item.result_status,
                           batch_item.result_reason,
                           batch_item.result_message,
                           payload_unique_identifier,
                           payload_mac_data)
        return result

    # TODO (peter-hamilton) Augment to handle device credentials
    def _build_credential(self):
        if (self.username is None) and (self.password is None):
            return None
        if self.username is None:
            raise ValueError('cannot build credential, username is None')
        if self.password is None:
            raise ValueError('cannot build credential, password is None')

        credential_type = CredentialType.USERNAME_AND_PASSWORD
        credential_value = {'Username': self.username,
                            'Password': self.password}
        credential = self.credential_factory.create_credential(
            credential_type,
            credential_value)
        return credential

    def _build_request_message(self, credential, batch_items):
        protocol_version = ProtocolVersion.create(1, 2)

        if credential is None:
            credential = self._build_credential()

        authentication = None
        if credential is not None:
            authentication = Authentication(credential)

        batch_count = BatchCount(len(batch_items))
        req_header = messages.RequestHeader(protocol_version=protocol_version,
                                            authentication=authentication,
                                            batch_count=batch_count)

        return messages.RequestMessage(request_header=req_header,
                                       batch_items=batch_items)

    def _send_message(self, message):
        stream = BytearrayStream()
        message.write(stream)
        self.protocol.write(stream.buffer)

    def _receive_message(self):
        return self.protocol.read()

    def _send_and_receive_message(self, request):
        self._send_message(request)
        response = messages.ResponseMessage()
        data = self._receive_message()
        response.read(data)
        return response

    def _set_variables(self, host, port, keyfile, certfile,
                       cert_reqs, ssl_version, ca_certs,
                       do_handshake_on_connect, suppress_ragged_eofs,
                       username, password, timeout):
        conf = ConfigHelper()

        # TODO: set this to a host list
        self.host_list_str = conf.get_valid_value(
            host, self.config, 'host', conf.DEFAULT_HOST)

        self.host_list = self._build_host_list(self.host_list_str)

        self.host = self.host_list[0]

        self.port = int(conf.get_valid_value(
            port, self.config, 'port', conf.DEFAULT_PORT))

        self.keyfile = conf.get_valid_value(
            keyfile, self.config, 'keyfile', None)

        self.certfile = conf.get_valid_value(
            certfile, self.config, 'certfile', None)

        self.cert_reqs = getattr(ssl, conf.get_valid_value(
            cert_reqs, self.config, 'cert_reqs', 'CERT_REQUIRED'))

        self.ssl_version = getattr(ssl, conf.get_valid_value(
            ssl_version, self.config, 'ssl_version', conf.DEFAULT_SSL_VERSION))

        self.ca_certs = conf.get_valid_value(
            ca_certs, self.config, 'ca_certs', conf.DEFAULT_CA_CERTS)

        if conf.get_valid_value(
                do_handshake_on_connect, self.config,
                'do_handshake_on_connect', 'True') == 'True':
            self.do_handshake_on_connect = True
        else:
            self.do_handshake_on_connect = False

        if conf.get_valid_value(
                suppress_ragged_eofs, self.config,
                'suppress_ragged_eofs', 'True') == 'True':
            self.suppress_ragged_eofs = True
        else:
            self.suppress_ragged_eofs = False

        self.username = conf.get_valid_value(
            username, self.config, 'username', conf.DEFAULT_USERNAME)

        self.password = conf.get_valid_value(
            password, self.config, 'password', conf.DEFAULT_PASSWORD)

        self.timeout = int(conf.get_valid_value(
            timeout, self.config, 'timeout', conf.DEFAULT_TIMEOUT))
        if self.timeout < 0:
            self.logger.warning(
                "Negative timeout value specified, "
                "resetting to safe default of {0} seconds".format(
                    conf.DEFAULT_TIMEOUT))
            self.timeout = conf.DEFAULT_TIMEOUT

    def _build_host_list(self, host_list_str):
        '''
        This internal function takes the host string from the config file
        and turns it into a list
        :return: LIST host list
        '''

        host_list = []
        if isinstance(host_list_str, str):
            host_list = host_list_str.replace(' ', '').split(',')
        else:
            raise TypeError("Unrecognized variable type provided for host "
                            "list string. 'String' type expected but '" +
                            str(type(host_list_str)) + "' received")
        return host_list
Пример #13
0
class KMIPProxy(KMIP):

    def __init__(self, host=None, port=None, keyfile=None, certfile=None,
                 cert_reqs=None, ssl_version=None, ca_certs=None,
                 do_handshake_on_connect=None,
                 suppress_ragged_eofs=None,
                 username=None, password=None, config='client'):
        super(KMIPProxy, self).__init__()
        self.logger = logging.getLogger(__name__)
        self.credential_factory = CredentialFactory()
        self.config = config

        self._set_variables(host, port, keyfile, certfile,
                            cert_reqs, ssl_version, ca_certs,
                            do_handshake_on_connect, suppress_ragged_eofs,
                            username, password)
        self.batch_items = []

        self.conformance_clauses = [
            ConformanceClause.DISCOVER_VERSIONS]

        self.authentication_suites = [
            AuthenticationSuite.BASIC,
            AuthenticationSuite.TLS12]

    def get_supported_conformance_clauses(self):
        """
        Get the list of conformance clauses supported by the client.

        Returns:
            list: A shallow copy of the list of supported conformance clauses.

        Example:
            >>> client.get_supported_conformance_clauses()
            [<ConformanceClause.DISCOVER_VERSIONS: 1>]
        """
        return self.conformance_clauses[:]

    def get_supported_authentication_suites(self):
        """
        Get the list of authentication suites supported by the client.

        Returns:
            list: A shallow copy of the list of supported authentication
                suites.

        Example:
            >>> client.get_supported_authentication_suites()
            [<AuthenticationSuite.BASIC: 1>, <AuthenticationSuite.TLS12: 2>]
        """
        return self.authentication_suites[:]

    def is_conformance_clause_supported(self, conformance_clause):
        """
        Check if a ConformanceClause is supported by the client.

        Args:
            conformance_clause (ConformanceClause): A ConformanceClause
                enumeration to check against the list of supported
                ConformanceClauses.

        Returns:
            bool: True if the ConformanceClause is supported, False otherwise.

        Example:
            >>> clause = ConformanceClause.DISCOVER_VERSIONS
            >>> client.is_conformance_clause_supported(clause)
            True
            >>> clause = ConformanceClause.BASELINE
            >>> client.is_conformance_clause_supported(clause)
            False
        """
        return conformance_clause in self.conformance_clauses

    def is_authentication_suite_supported(self, authentication_suite):
        """
        Check if an AuthenticationSuite is supported by the client.

        Args:
            authentication_suite (AuthenticationSuite): An AuthenticationSuite
                enumeration to check against the list of supported
                AuthenticationSuites.

        Returns:
            bool: True if the AuthenticationSuite is supported, False
                otherwise.

        Example:
            >>> suite = AuthenticationSuite.BASIC
            >>> client.is_authentication_suite_supported(suite)
            True
            >>> suite = AuthenticationSuite.TLS12
            >>> client.is_authentication_suite_supported(suite)
            False
        """
        return authentication_suite in self.authentication_suites

    def is_profile_supported(self, conformance_clause, authentication_suite):
        """
        Check if a profile is supported by the client.

        Args:
            conformance_clause (ConformanceClause):
            authentication_suite (AuthenticationSuite):

        Returns:
            bool: True if the profile is supported, False otherwise.

        Example:
            >>> client.is_profile_supported(
            ... ConformanceClause.DISCOVER_VERSIONS,
            ... AuthenticationSuite.BASIC)
            True
        """
        return (self.is_conformance_clause_supported(conformance_clause) and
                self.is_authentication_suite_supported(authentication_suite))

    def open(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        self.logger.debug("KMIPProxy keyfile: {0}".format(self.keyfile))
        self.logger.debug("KMIPProxy certfile: {0}".format(self.certfile))
        self.logger.debug(
            "KMIPProxy cert_reqs: {0} (CERT_REQUIRED: {1})".format(
                self.cert_reqs, ssl.CERT_REQUIRED))
        self.logger.debug(
            "KMIPProxy ssl_version: {0} (PROTOCOL_SSLv23: {1})".format(
                self.ssl_version, ssl.PROTOCOL_SSLv23))
        self.logger.debug("KMIPProxy ca_certs: {0}".format(self.ca_certs))
        self.logger.debug("KMIPProxy do_handshake_on_connect: {0}".format(
            self.do_handshake_on_connect))
        self.logger.debug("KMIPProxy suppress_ragged_eofs: {0}".format(
            self.suppress_ragged_eofs))

        self.socket = ssl.wrap_socket(
            sock,
            keyfile=self.keyfile,
            certfile=self.certfile,
            cert_reqs=self.cert_reqs,
            ssl_version=self.ssl_version,
            ca_certs=self.ca_certs,
            do_handshake_on_connect=self.do_handshake_on_connect,
            suppress_ragged_eofs=self.suppress_ragged_eofs)
        self.protocol = KMIPProtocol(self.socket)

        self.socket.connect((self.host, self.port))

    def close(self):
        self.socket.shutdown(socket.SHUT_RDWR)

    def create(self, object_type, template_attribute, credential=None):
        object_type = attr.ObjectType(object_type)
        return self._create(object_type=object_type,
                            template_attribute=template_attribute,
                            credential=credential)

    def create_key_pair(self, batch=False, common_template_attribute=None,
                        private_key_template_attribute=None,
                        public_key_template_attribute=None, credential=None):
        batch_item = self._build_create_key_pair_batch_item(
            common_template_attribute, private_key_template_attribute,
            public_key_template_attribute)

        if batch:
            self.batch_items.append(batch_item)
        else:
            request = self._build_request_message(credential, [batch_item])
            response = self._send_and_receive_message(request)
            results = self._process_batch_items(response)
            return results[0]

    def get(self, uuid=None, key_format_type=None, key_compression_type=None,
            key_wrapping_specification=None, credential=None):
        return self._get(
            unique_identifier=uuid,
            key_format_type=key_format_type,
            key_compression_type=key_compression_type,
            key_wrapping_specification=key_wrapping_specification,
            credential=credential)

    def destroy(self, uuid, credential=None):
        return self._destroy(unique_identifier=uuid,
                             credential=credential)

    def register(self, object_type, template_attribute, secret,
                 credential=None):
        object_type = attr.ObjectType(object_type)
        return self._register(object_type=object_type,
                              template_attribute=template_attribute,
                              secret=secret,
                              credential=credential)

    def rekey_key_pair(self, batch=False, private_key_uuid=None, offset=None,
                       common_template_attribute=None,
                       private_key_template_attribute=None,
                       public_key_template_attribute=None, credential=None):
        batch_item = self._build_rekey_key_pair_batch_item(
            private_key_uuid, offset, common_template_attribute,
            private_key_template_attribute, public_key_template_attribute)

        if batch:
            self.batch_items.append(batch_item)
        else:
            request = self._build_request_message(credential, [batch_item])
            response = self._send_and_receive_message(request)
            results = self._process_batch_items(response)
            return results[0]

    def locate(self, maximum_items=None, storage_status_mask=None,
               object_group_member=None, attributes=None, credential=None):
        return self._locate(maximum_items=maximum_items,
                            storage_status_mask=storage_status_mask,
                            object_group_member=object_group_member,
                            attributes=attributes, credential=credential)

    def query(self, batch=False, query_functions=None, credential=None):
        """
        Send a Query request to the server.

        Args:
            batch (boolean): A flag indicating if the operation should be sent
                with a batch of additional operations. Defaults to False.
            query_functions (list): A list of QueryFunction enumerations
                indicating what information the client wants from the server.
                Optional, defaults to None.
            credential (Credential): A Credential object containing
                authentication information for the server. Optional, defaults
                to None.
        """
        batch_item = self._build_query_batch_item(query_functions)

        # TODO (peter-hamilton): Replace this with official client batch mode.
        if batch:
            self.batch_items.append(batch_item)
        else:
            request = self._build_request_message(credential, [batch_item])
            response = self._send_and_receive_message(request)
            results = self._process_batch_items(response)
            return results[0]

    def discover_versions(self, batch=False, protocol_versions=None,
                          credential=None):
        batch_item = self._build_discover_versions_batch_item(
            protocol_versions)

        if batch:
            self.batch_items.append(batch_item)
        else:
            request = self._build_request_message(credential, [batch_item])
            response = self._send_and_receive_message(request)
            results = self._process_batch_items(response)
            return results[0]

    def _create(self,
                object_type=None,
                template_attribute=None,
                credential=None):
        operation = Operation(OperationEnum.CREATE)

        if object_type is None:
            raise ValueError('object_type cannot be None')

        req_pl = create.CreateRequestPayload(
            object_type=object_type,
            template_attribute=template_attribute)
        batch_item = messages.RequestBatchItem(operation=operation,
                                               request_payload=req_pl)

        message = self._build_request_message(credential, [batch_item])
        self._send_message(message)
        message = messages.ResponseMessage()
        data = self._receive_message()
        message.read(data)
        batch_items = message.batch_items
        batch_item = batch_items[0]
        payload = batch_item.response_payload

        if payload is None:
            payload_unique_identifier = None
            payload_template_attribute = None
            payload_object_type = None
        else:
            payload_unique_identifier = payload.unique_identifier
            payload_template_attribute = payload.template_attribute
            payload_object_type = payload.object_type

        result = CreateResult(batch_item.result_status,
                              batch_item.result_reason,
                              batch_item.result_message,
                              payload_object_type,
                              payload_unique_identifier,
                              payload_template_attribute)
        return result

    def _build_create_key_pair_batch_item(self, common_template_attribute=None,
                                          private_key_template_attribute=None,
                                          public_key_template_attribute=None):
        operation = Operation(OperationEnum.CREATE_KEY_PAIR)
        payload = create_key_pair.CreateKeyPairRequestPayload(
            common_template_attribute=common_template_attribute,
            private_key_template_attribute=private_key_template_attribute,
            public_key_template_attribute=public_key_template_attribute)
        batch_item = messages.RequestBatchItem(
            operation=operation, request_payload=payload)
        return batch_item

    def _build_rekey_key_pair_batch_item(self,
                                         private_key_uuid=None, offset=None,
                                         common_template_attribute=None,
                                         private_key_template_attribute=None,
                                         public_key_template_attribute=None):
        operation = Operation(OperationEnum.REKEY_KEY_PAIR)
        payload = rekey_key_pair.RekeyKeyPairRequestPayload(
            private_key_uuid, offset,
            common_template_attribute=common_template_attribute,
            private_key_template_attribute=private_key_template_attribute,
            public_key_template_attribute=public_key_template_attribute)
        batch_item = messages.RequestBatchItem(
            operation=operation, request_payload=payload)
        return batch_item

    def _build_query_batch_item(self, query_functions=None):
        operation = Operation(OperationEnum.QUERY)
        payload = query.QueryRequestPayload(query_functions)
        batch_item = messages.RequestBatchItem(
            operation=operation, request_payload=payload)
        return batch_item

    def _build_discover_versions_batch_item(self, protocol_versions=None):
        operation = Operation(OperationEnum.DISCOVER_VERSIONS)

        payload = discover_versions.DiscoverVersionsRequestPayload(
            protocol_versions)

        batch_item = messages.RequestBatchItem(
            operation=operation, request_payload=payload)
        return batch_item

    def _process_batch_items(self, response):
        results = []
        for batch_item in response.batch_items:
            operation = batch_item.operation.enum
            processor = self._get_batch_item_processor(operation)
            result = processor(batch_item)
            results.append(result)
        return results

    def _get_batch_item_processor(self, operation):
        if operation == OperationEnum.CREATE_KEY_PAIR:
            return self._process_create_key_pair_batch_item
        elif operation == OperationEnum.REKEY_KEY_PAIR:
            return self._process_rekey_key_pair_batch_item
        elif operation == OperationEnum.QUERY:
            return self._process_query_batch_item
        elif operation == OperationEnum.DISCOVER_VERSIONS:
            return self._process_discover_versions_batch_item
        else:
            raise ValueError("no processor for operation: {0}".format(
                operation))

    def _process_key_pair_batch_item(self, batch_item, result):
        payload = batch_item.response_payload

        payload_private_key_uuid = None
        payload_public_key_uuid = None
        payload_private_key_template_attribute = None
        payload_public_key_template_attribute = None

        if payload is not None:
            payload_private_key_uuid = payload.private_key_uuid
            payload_public_key_uuid = payload.public_key_uuid
            payload_private_key_template_attribute = \
                payload.private_key_template_attribute
            payload_public_key_template_attribute = \
                payload.public_key_template_attribute

        return result(batch_item.result_status, batch_item.result_reason,
                      batch_item.result_message, payload_private_key_uuid,
                      payload_public_key_uuid,
                      payload_private_key_template_attribute,
                      payload_public_key_template_attribute)

    def _process_create_key_pair_batch_item(self, batch_item):
        return self._process_key_pair_batch_item(
            batch_item, CreateKeyPairResult)

    def _process_rekey_key_pair_batch_item(self, batch_item):
        return self._process_key_pair_batch_item(
            batch_item, RekeyKeyPairResult)

    def _process_query_batch_item(self, batch_item):
        payload = batch_item.response_payload

        operations = None
        object_types = None
        vendor_identification = None
        server_information = None
        application_namespaces = None
        extension_information = None

        if payload is not None:
            operations = payload.operations
            object_types = payload.object_types
            vendor_identification = payload.vendor_identification
            server_information = payload.server_information
            application_namespaces = payload.application_namespaces
            extension_information = payload.extension_information

        return QueryResult(
            batch_item.result_status,
            batch_item.result_reason,
            batch_item.result_message,
            operations,
            object_types,
            vendor_identification,
            server_information,
            application_namespaces,
            extension_information)

    def _process_discover_versions_batch_item(self, batch_item):
        payload = batch_item.response_payload

        result = DiscoverVersionsResult(
            batch_item.result_status, batch_item.result_reason,
            batch_item.result_message, payload.protocol_versions)

        return result

    def _get(self,
             unique_identifier=None,
             key_format_type=None,
             key_compression_type=None,
             key_wrapping_specification=None,
             credential=None):
        operation = Operation(OperationEnum.GET)

        uuid = None
        kft = None
        kct = None
        kws = None

        if unique_identifier is not None:
            uuid = attr.UniqueIdentifier(unique_identifier)
        if key_format_type is not None:
            kft = get.GetRequestPayload.KeyFormatType(key_format_type.enum)
        if key_compression_type is not None:
            kct = key_compression_type
            kct = get.GetRequestPayload.KeyCompressionType(kct)
        if key_wrapping_specification is not None:
            kws = objects.KeyWrappingSpecification(key_wrapping_specification)

        req_pl = get.GetRequestPayload(unique_identifier=uuid,
                                       key_format_type=kft,
                                       key_compression_type=kct,
                                       key_wrapping_specification=kws)

        batch_item = messages.RequestBatchItem(operation=operation,
                                               request_payload=req_pl)
        message = self._build_request_message(credential, [batch_item])
        self._send_message(message)
        message = messages.ResponseMessage()
        data = self._receive_message()
        message.read(data)
        batch_items = message.batch_items
        batch_item = batch_items[0]
        payload = batch_item.response_payload

        if payload is None:
            payload_unique_identifier = None
            payload_object_type = None
            payload_secret = None
        else:
            payload_unique_identifier = payload.unique_identifier
            payload_object_type = payload.object_type
            payload_secret = payload.secret

        result = GetResult(batch_item.result_status,
                           batch_item.result_reason,
                           batch_item.result_message,
                           payload_object_type,
                           payload_unique_identifier,
                           payload_secret)
        return result

    def _destroy(self,
                 unique_identifier=None,
                 credential=None):
        operation = Operation(OperationEnum.DESTROY)

        uuid = None
        if unique_identifier is not None:
            uuid = attr.UniqueIdentifier(unique_identifier)

        payload = destroy.DestroyRequestPayload(unique_identifier=uuid)

        batch_item = messages.RequestBatchItem(operation=operation,
                                               request_payload=payload)
        message = self._build_request_message(credential, [batch_item])
        self._send_message(message)
        message = messages.ResponseMessage()
        data = self._receive_message()
        message.read(data)
        batch_items = message.batch_items
        batch_item = batch_items[0]
        payload = batch_item.response_payload

        if payload is None:
            payload_unique_identifier = None
        else:
            payload_unique_identifier = payload.unique_identifier

        result = DestroyResult(batch_item.result_status,
                               batch_item.result_reason,
                               batch_item.result_message,
                               payload_unique_identifier)
        return result

    def _register(self,
                  object_type=None,
                  template_attribute=None,
                  secret=None,
                  credential=None):
        operation = Operation(OperationEnum.REGISTER)

        if object_type is None:
            raise ValueError('object_type cannot be None')

        req_pl = register.RegisterRequestPayload(
            object_type=object_type,
            template_attribute=template_attribute,
            secret=secret)
        batch_item = messages.RequestBatchItem(operation=operation,
                                               request_payload=req_pl)

        message = self._build_request_message(credential, [batch_item])
        self._send_message(message)
        message = messages.ResponseMessage()
        data = self._receive_message()
        message.read(data)
        batch_items = message.batch_items
        batch_item = batch_items[0]
        payload = batch_item.response_payload

        if payload is None:
            payload_unique_identifier = None
            payload_template_attribute = None
        else:
            payload_unique_identifier = payload.unique_identifier
            payload_template_attribute = payload.template_attribute

        result = RegisterResult(batch_item.result_status,
                                batch_item.result_reason,
                                batch_item.result_message,
                                payload_unique_identifier,
                                payload_template_attribute)
        return result

    def _locate(self, maximum_items=None, storage_status_mask=None,
                object_group_member=None, attributes=[], credential=None):

        operation = Operation(OperationEnum.LOCATE)

        mxi = None
        ssmask = None
        objgrp = None

        if maximum_items is not None:
            mxi = locate.LocateRequestPayload.MaximumItems(maximum_items)
        if storage_status_mask is not None:
            m = storage_status_mask
            ssmask = locate.LocateRequestPayload.StorageStatusMask(m)
        if object_group_member is not None:
            o = object_group_member
            objgrp = locate.LocateRequestPayload.ObjectGroupMember(o)

        payload = locate.LocateRequestPayload(maximum_items=mxi,
                                              storage_status_mask=ssmask,
                                              object_group_member=objgrp,
                                              attributes=attributes)

        batch_item = messages.RequestBatchItem(operation=operation,
                                               request_payload=payload)

        message = self._build_request_message(credential, [batch_item])
        self._send_message(message)
        message = messages.ResponseMessage()
        data = self._receive_message()

        message.read(data)
        batch_items = message.batch_items
        batch_item = batch_items[0]
        payload = batch_item.response_payload

        if payload is None:
            uuids = None
        else:
            uuids = payload.unique_identifiers

        result = LocateResult(batch_item.result_status,
                              batch_item.result_reason,
                              batch_item.result_message,
                              uuids)
        return result

    # TODO (peter-hamilton) Augment to handle device credentials
    def _build_credential(self):
        if (self.username is None) and (self.password is None):
            return None
        if self.username is None:
            raise ValueError('cannot build credential, username is None')
        if self.password is None:
            raise ValueError('cannot build credential, password is None')

        credential_type = CredentialType.USERNAME_AND_PASSWORD
        credential_value = {'Username': self.username,
                            'Password': self.password}
        credential = self.credential_factory.create_credential(
            credential_type,
            credential_value)
        return credential

    def _build_request_message(self, credential, batch_items):
        protocol_version = ProtocolVersion.create(1, 1)

        if credential is None:
            credential = self._build_credential()

        authentication = None
        if credential is not None:
            authentication = Authentication(credential)

        batch_count = BatchCount(len(batch_items))
        req_header = messages.RequestHeader(protocol_version=protocol_version,
                                            authentication=authentication,
                                            batch_count=batch_count)

        return messages.RequestMessage(request_header=req_header,
                                       batch_items=batch_items)

    def _send_message(self, message):
        stream = BytearrayStream()
        message.write(stream)
        self.protocol.write(stream.buffer)

    def _receive_message(self):
        return self.protocol.read()

    def _send_and_receive_message(self, request):
        self._send_message(request)
        response = messages.ResponseMessage()
        data = self._receive_message()
        response.read(data)
        return response

    def _set_variables(self, host, port, keyfile, certfile,
                       cert_reqs, ssl_version, ca_certs,
                       do_handshake_on_connect, suppress_ragged_eofs,
                       username, password):
        conf = ConfigHelper()

        self.host = conf.get_valid_value(
            host, self.config, 'host', conf.DEFAULT_HOST)

        self.port = int(conf.get_valid_value(
            port, self.config, 'port', conf.DEFAULT_PORT))

        self.keyfile = conf.get_valid_value(
            keyfile, self.config, 'keyfile', None)

        self.certfile = conf.get_valid_value(
            certfile, self.config, 'certfile', None)

        self.cert_reqs = getattr(ssl, conf.get_valid_value(
            cert_reqs, self.config, 'cert_reqs', 'CERT_REQUIRED'))

        self.ssl_version = getattr(ssl, conf.get_valid_value(
            ssl_version, self.config, 'ssl_version', conf.DEFAULT_SSL_VERSION))

        self.ca_certs = conf.get_valid_value(
            ca_certs, self.config, 'ca_certs', conf.DEFAULT_CA_CERTS)

        if conf.get_valid_value(
                do_handshake_on_connect, self.config,
                'do_handshake_on_connect', 'True') == 'True':
            self.do_handshake_on_connect = True
        else:
            self.do_handshake_on_connect = False

        if conf.get_valid_value(
                suppress_ragged_eofs, self.config,
                'suppress_ragged_eofs', 'True') == 'True':
            self.suppress_ragged_eofs = True
        else:
            self.suppress_ragged_eofs = False

        self.username = conf.get_valid_value(
            username, self.config, 'username', conf.DEFAULT_USERNAME)

        self.password = conf.get_valid_value(
            password, self.config, 'password', conf.DEFAULT_PASSWORD)
Пример #14
0
class TestKMIPClientIntegration(TestCase):
    STARTUP_TIME = 1.0
    SHUTDOWN_TIME = 0.1
    KMIP_PORT = 9090
    CA_CERTS_PATH = os.path.normpath(
        os.path.join(os.path.dirname(os.path.abspath(__file__)),
                     '../utils/certs/server.crt'))

    def setUp(self):
        super(TestKMIPClientIntegration, self).setUp()

        self.attr_factory = AttributeFactory()
        self.cred_factory = CredentialFactory()
        self.secret_factory = SecretFactory()

        # Set up the KMIP server process
        path = os.path.join(os.path.dirname(__file__), os.path.pardir, 'utils',
                            'server.py')
        self.server = Popen(
            ['python', '{0}'.format(path), '-p', '{0}'.format(self.KMIP_PORT)],
            stderr=sys.stdout)

        time.sleep(self.STARTUP_TIME)

        if self.server.poll() is not None:
            raise KMIPServerSuicideError(self.server.pid)

        # Set up and open the client proxy; shutdown the server if open fails
        try:
            self.client = KMIPProxy(port=self.KMIP_PORT,
                                    ca_certs=self.CA_CERTS_PATH)
            self.client.open()
        except Exception as e:
            self._shutdown_server()
            raise e

    def tearDown(self):
        super(TestKMIPClientIntegration, self).tearDown()

        # Close the client proxy and shutdown the server
        self.client.close()
        self._shutdown_server()

    def test_create(self):
        result = self._create_symmetric_key()

        self._check_result_status(result.result_status.value, ResultStatus,
                                  ResultStatus.SUCCESS)
        self._check_object_type(result.object_type.value, ObjectType,
                                ObjectType.SYMMETRIC_KEY)
        self._check_uuid(result.uuid.value, str)

        # Check the template attribute type
        self._check_template_attribute(
            result.template_attribute, TemplateAttribute, 2,
            [[str, 'Cryptographic Length', int, 256],
             [str, 'Unique Identifier', str, None]])

    def test_get(self):
        credential_type = CredentialType.USERNAME_AND_PASSWORD
        credential_value = {'Username': '******', 'Password': '******'}
        credential = self.cred_factory.create_credential(
            credential_type, credential_value)
        result = self._create_symmetric_key()
        uuid = result.uuid.value

        result = self.client.get(uuid=uuid, credential=credential)

        self._check_result_status(result.result_status.value, ResultStatus,
                                  ResultStatus.SUCCESS)
        self._check_object_type(result.object_type.value, ObjectType,
                                ObjectType.SYMMETRIC_KEY)
        self._check_uuid(result.uuid.value, str)

        # Check the secret type
        secret = result.secret

        expected = SymmetricKey
        message = utils.build_er_error(result.__class__, 'type', expected,
                                       secret, 'secret')
        self.assertIsInstance(secret, expected, message)

    def test_destroy(self):
        credential_type = CredentialType.USERNAME_AND_PASSWORD
        credential_value = {'Username': '******', 'Password': '******'}
        credential = self.cred_factory.create_credential(
            credential_type, credential_value)
        result = self._create_symmetric_key()
        uuid = result.uuid.value

        # Verify the secret was created
        result = self.client.get(uuid=uuid, credential=credential)

        self._check_result_status(result.result_status.value, ResultStatus,
                                  ResultStatus.SUCCESS)
        self._check_object_type(result.object_type.value, ObjectType,
                                ObjectType.SYMMETRIC_KEY)
        self._check_uuid(result.uuid.value, str)

        secret = result.secret

        expected = SymmetricKey
        message = utils.build_er_error(result.__class__, 'type', expected,
                                       secret, 'secret')
        self.assertIsInstance(secret, expected, message)

        # Destroy the SYMMETRIC_KEY object
        result = self.client.destroy(uuid, credential)
        self._check_result_status(result.result_status.value, ResultStatus,
                                  ResultStatus.SUCCESS)
        self._check_uuid(result.uuid.value, str)

        # Verify the secret was destroyed
        result = self.client.get(uuid=uuid, credential=credential)

        self._check_result_status(result.result_status.value, ResultStatus,
                                  ResultStatus.OPERATION_FAILED)

        expected = ResultReason
        observed = type(result.result_reason.value)
        message = utils.build_er_error(result.result_reason.__class__, 'type',
                                       expected, observed)
        self.assertEqual(expected, observed, message)

        expected = ResultReason.ITEM_NOT_FOUND
        observed = result.result_reason.value
        message = utils.build_er_error(result.result_reason.__class__, 'value',
                                       expected, observed)
        self.assertEqual(expected, observed, message)

    def test_register(self):
        credential_type = CredentialType.USERNAME_AND_PASSWORD
        credential_value = {'Username': '******', 'Password': '******'}
        credential = self.cred_factory.create_credential(
            credential_type, credential_value)

        object_type = ObjectType.SYMMETRIC_KEY
        algorithm_value = CryptoAlgorithmEnum.AES
        mask_flags = [
            CryptographicUsageMask.ENCRYPT, CryptographicUsageMask.DECRYPT
        ]
        attribute_type = AttributeType.CRYPTOGRAPHIC_USAGE_MASK
        usage_mask = self.attr_factory.create_attribute(
            attribute_type, mask_flags)
        attributes = [usage_mask]
        template_attribute = TemplateAttribute(attributes=attributes)

        key_format_type = KeyFormatType(KeyFormatTypeEnum.RAW)

        key_data = (
            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
            b'\x00')

        key_material = KeyMaterial(key_data)
        key_value = KeyValue(key_material)
        cryptographic_algorithm = CryptographicAlgorithm(algorithm_value)
        cryptographic_length = CryptographicLength(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 = SymmetricKey(key_block)

        result = self.client.register(object_type, template_attribute, secret,
                                      credential)

        self._check_result_status(result.result_status.value, ResultStatus,
                                  ResultStatus.SUCCESS)
        self._check_uuid(result.uuid.value, str)

        # Check the template attribute type
        self._check_template_attribute(result.template_attribute,
                                       TemplateAttribute, 1,
                                       [[str, 'Unique Identifier', str, None]])
        # Check that the returned key bytes match what was provided
        uuid = result.uuid.value
        result = self.client.get(uuid=uuid, credential=credential)

        self._check_result_status(result.result_status.value, ResultStatus,
                                  ResultStatus.SUCCESS)
        self._check_object_type(result.object_type.value, ObjectType,
                                ObjectType.SYMMETRIC_KEY)
        self._check_uuid(result.uuid.value, str)

        # Check the secret type
        secret = result.secret

        expected = SymmetricKey
        message = utils.build_er_error(result.__class__, 'type', expected,
                                       secret, 'secret')
        self.assertIsInstance(secret, expected, message)

        key_block = result.secret.key_block
        key_value = key_block.key_value
        key_material = key_value.key_material

        expected = key_data
        observed = key_material.value
        message = utils.build_er_error(key_material.__class__, 'value',
                                       expected, observed, 'value')
        self.assertEqual(expected, observed, message)

    def _shutdown_server(self):
        if self.server.poll() is not None:
            return
        else:
            # Terminate the server process. If it resists, kill it.
            pid = self.server.pid
            self.server.terminate()
            time.sleep(self.SHUTDOWN_TIME)

            if self.server.poll() is None:
                raise KMIPServerZombieError(pid)

    def _create_symmetric_key(self):
        credential_type = CredentialType.USERNAME_AND_PASSWORD
        credential_value = {'Username': '******', 'Password': '******'}
        credential = self.cred_factory.create_credential(
            credential_type, credential_value)

        object_type = ObjectType.SYMMETRIC_KEY
        attribute_type = AttributeType.CRYPTOGRAPHIC_ALGORITHM
        algorithm = self.attr_factory.create_attribute(attribute_type,
                                                       CryptoAlgorithmEnum.AES)

        mask_flags = [
            CryptographicUsageMask.ENCRYPT, CryptographicUsageMask.DECRYPT
        ]
        attribute_type = AttributeType.CRYPTOGRAPHIC_USAGE_MASK
        usage_mask = self.attr_factory.create_attribute(
            attribute_type, mask_flags)
        attributes = [algorithm, usage_mask]
        template_attribute = TemplateAttribute(attributes=attributes)

        return self.client.create(object_type, template_attribute, credential)

    def _check_result_status(self, result_status, result_status_type,
                             result_status_value):
        # Error check the result status type and value
        expected = result_status_type
        message = utils.build_er_error(result_status_type, 'type', expected,
                                       result_status)
        self.assertIsInstance(result_status, expected, message)

        expected = result_status_value
        message = utils.build_er_error(result_status_type, 'value', expected,
                                       result_status)
        self.assertEqual(expected, result_status, message)

    def _check_uuid(self, uuid, uuid_type):
        # Error check the UUID type and value
        not_expected = None
        message = utils.build_er_error(uuid_type, 'type',
                                       'not {0}'.format(not_expected), uuid)
        self.assertNotEqual(not_expected, uuid, message)

        expected = uuid_type
        message = utils.build_er_error(uuid_type, 'type', expected, uuid)
        self.assertEqual(expected, type(uuid), message)

    def _check_object_type(self, object_type, object_type_type,
                           object_type_value):
        # Error check the object type type and value
        expected = object_type_type
        message = utils.build_er_error(object_type_type, 'type', expected,
                                       object_type)
        self.assertIsInstance(object_type, expected, message)

        expected = object_type_value
        message = utils.build_er_error(object_type_type, 'value', expected,
                                       object_type)
        self.assertEqual(expected, object_type, message)

    def _check_template_attribute(self, template_attribute,
                                  template_attribute_type, num_attributes,
                                  attribute_features):
        # Error check the template attribute type
        expected = template_attribute_type
        message = utils.build_er_error(template_attribute.__class__, 'type',
                                       expected, template_attribute)
        self.assertIsInstance(template_attribute, expected, message)

        attributes = template_attribute.attributes

        expected = num_attributes
        observed = len(attributes)
        message = utils.build_er_error(TemplateAttribute.__class__, 'number',
                                       expected, observed, 'attributes')

        for i in range(num_attributes):
            features = attribute_features[i]
            self._check_attribute(attributes[i], features[0], features[1],
                                  features[2], features[3])

    def _check_attribute(self, attribute, attribute_name_type,
                         attribute_name_value, attribute_value_type,
                         attribute_value_value):
        # Error check the attribute name and value type and value
        attribute_name = attribute.attribute_name
        attribute_value = attribute.attribute_value

        self._check_attribute_name(attribute_name, attribute_name_type,
                                   attribute_name_value)

        if attribute_name_value == 'Unique Identifier':
            self._check_uuid(attribute_value.value, attribute_value_type)
        else:
            self._check_attribute_value(attribute_value, attribute_value_type,
                                        attribute_value_value)

    def _check_attribute_name(self, attribute_name, attribute_name_type,
                              attribute_name_value):
        # Error check the attribute name type and value
        expected = attribute_name_type
        observed = type(attribute_name.value)
        message = utils.build_er_error(attribute_name_type, 'type', expected,
                                       observed)
        self.assertEqual(expected, observed, message)

        expected = attribute_name_value
        observed = attribute_name.value
        message = utils.build_er_error(attribute_name_type, 'value', expected,
                                       observed)
        self.assertEqual(expected, observed, message)

    def _check_attribute_value(self, attribute_value, attribute_value_type,
                               attribute_value_value):
        expected = attribute_value_type
        observed = type(attribute_value.value)
        message = utils.build_er_error(Attribute, 'type', expected, observed,
                                       'attribute_value')
        self.assertEqual(expected, observed, message)

        expected = attribute_value_value
        observed = attribute_value.value
        message = utils.build_er_error(Attribute, 'value', expected, observed,
                                       'attribute_value')
        self.assertEqual(expected, observed, message)