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)
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() # Build attributes if any are specified attributes = [] if name: attributes.append( attribute_factory.create_attribute(enums.AttributeType.NAME, name)) for initial_date in initial_dates: try: t = time.strptime(initial_date) except ValueError: logger.error(
'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() # Build name attribute # TODO (peter-hamilton) Push this into the AttributeFactory attribute_name = Attribute.AttributeName('Name') name_value = Name.NameValue(name) name_type = Name.NameType(NameType.UNINTERPRETED_TEXT_STRING) value = Name.create(name_value=name_value, name_type=name_type) name_obj = Attribute(attribute_name=attribute_name, attribute_value=value) attributes = [name_obj] # Locate UUID of specified SYMMETRIC_KEY object result = client.locate(attributes=attributes,
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)
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
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)
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)