mirror of https://github.com/OpenKMIP/PyKMIP.git
Adding KmipEngine support for CreateKeyPair
This change adds support for the CreateKeyPair operation to the KmipEngine. New exceptions and test cases are included.
This commit is contained in:
parent
23b27590f8
commit
934fc7b93e
|
@ -33,6 +33,7 @@ from kmip.core.messages import contents
|
|||
from kmip.core.messages import messages
|
||||
|
||||
from kmip.core.messages.payloads import create
|
||||
from kmip.core.messages.payloads import create_key_pair
|
||||
from kmip.core.messages.payloads import destroy
|
||||
from kmip.core.messages.payloads import discover_versions
|
||||
from kmip.core.messages.payloads import get
|
||||
|
@ -71,6 +72,7 @@ class KmipEngine(object):
|
|||
* Registration of empty managed objects (e.g., Private Keys)
|
||||
* Managed object state tracking
|
||||
* Managed object usage limit tracking and enforcement
|
||||
* Cryptographic usage mask enforcement per object type
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
@ -619,6 +621,8 @@ class KmipEngine(object):
|
|||
def _process_operation(self, operation, payload):
|
||||
if operation == enums.Operation.CREATE:
|
||||
return self._process_create(payload)
|
||||
elif operation == enums.Operation.CREATE_KEY_PAIR:
|
||||
return self._process_create_key_pair(payload)
|
||||
elif operation == enums.Operation.REGISTER:
|
||||
return self._process_register(payload)
|
||||
elif operation == enums.Operation.GET:
|
||||
|
@ -722,6 +726,167 @@ class KmipEngine(object):
|
|||
|
||||
return response_payload
|
||||
|
||||
@_kmip_version_supported('1.0')
|
||||
def _process_create_key_pair(self, payload):
|
||||
self._logger.info("Processing operation: CreateKeyPair")
|
||||
|
||||
algorithm = None
|
||||
length = None
|
||||
|
||||
# Process attribute sets
|
||||
public_key_attributes = {}
|
||||
private_key_attributes = {}
|
||||
common_attributes = {}
|
||||
if payload.public_key_template_attribute:
|
||||
public_key_attributes = self._process_template_attribute(
|
||||
payload.public_key_template_attribute
|
||||
)
|
||||
if payload.private_key_template_attribute:
|
||||
private_key_attributes = self._process_template_attribute(
|
||||
payload.private_key_template_attribute
|
||||
)
|
||||
if payload.common_template_attribute:
|
||||
common_attributes = self._process_template_attribute(
|
||||
payload.common_template_attribute
|
||||
)
|
||||
|
||||
# Propagate common attributes if not overridden by the public/private
|
||||
# attribute sets
|
||||
for key, value in six.iteritems(common_attributes):
|
||||
if key not in public_key_attributes.keys():
|
||||
public_key_attributes.update([(key, value)])
|
||||
if key not in private_key_attributes.keys():
|
||||
private_key_attributes.update([(key, value)])
|
||||
|
||||
# Error check for required attributes.
|
||||
public_algorithm = public_key_attributes.get('Cryptographic Algorithm')
|
||||
if public_algorithm:
|
||||
public_algorithm = public_algorithm.value
|
||||
else:
|
||||
raise exceptions.InvalidField(
|
||||
"The cryptographic algorithm must be specified as an "
|
||||
"attribute for the public key."
|
||||
)
|
||||
|
||||
public_length = public_key_attributes.get('Cryptographic Length')
|
||||
if public_length:
|
||||
public_length = public_length.value
|
||||
else:
|
||||
# TODO (peterhamilton) The cryptographic length is technically not
|
||||
# required per the spec. Update the CryptographyEngine to accept a
|
||||
# None length, allowing it to pick the length dynamically. Default
|
||||
# to the strongest key size allowed for the algorithm type.
|
||||
raise exceptions.InvalidField(
|
||||
"The cryptographic length must be specified as an attribute "
|
||||
"for the public key."
|
||||
)
|
||||
|
||||
public_usage_mask = public_key_attributes.get(
|
||||
'Cryptographic Usage Mask'
|
||||
)
|
||||
if public_usage_mask is None:
|
||||
raise exceptions.InvalidField(
|
||||
"The cryptographic usage mask must be specified as an "
|
||||
"attribute for the public key."
|
||||
)
|
||||
|
||||
private_algorithm = private_key_attributes.get(
|
||||
'Cryptographic Algorithm'
|
||||
)
|
||||
if private_algorithm:
|
||||
private_algorithm = private_algorithm.value
|
||||
else:
|
||||
raise exceptions.InvalidField(
|
||||
"The cryptographic algorithm must be specified as an "
|
||||
"attribute for the private key."
|
||||
)
|
||||
|
||||
private_length = private_key_attributes.get('Cryptographic Length')
|
||||
if private_length:
|
||||
private_length = private_length.value
|
||||
else:
|
||||
# TODO (peterhamilton) The cryptographic length is technically not
|
||||
# required per the spec. Update the CryptographyEngine to accept a
|
||||
# None length, allowing it to pick the length dynamically. Default
|
||||
# to the strongest key size allowed for the algorithm type.
|
||||
raise exceptions.InvalidField(
|
||||
"The cryptographic length must be specified as an attribute "
|
||||
"for the private key."
|
||||
)
|
||||
|
||||
private_usage_mask = private_key_attributes.get(
|
||||
'Cryptographic Usage Mask'
|
||||
)
|
||||
if private_usage_mask is None:
|
||||
raise exceptions.InvalidField(
|
||||
"The cryptographic usage mask must be specified as an "
|
||||
"attribute for the private key."
|
||||
)
|
||||
|
||||
if public_algorithm == private_algorithm:
|
||||
algorithm = public_algorithm
|
||||
else:
|
||||
raise exceptions.InvalidField(
|
||||
"The public and private key algorithms must be the same."
|
||||
)
|
||||
|
||||
if public_length == private_length:
|
||||
length = public_length
|
||||
else:
|
||||
raise exceptions.InvalidField(
|
||||
"The public and private key lengths must be the same."
|
||||
)
|
||||
|
||||
public, private = self._cryptography_engine.create_asymmetric_key_pair(
|
||||
algorithm,
|
||||
length
|
||||
)
|
||||
|
||||
public_key = objects.PublicKey(
|
||||
algorithm,
|
||||
length,
|
||||
public.get('value'),
|
||||
public.get('format')
|
||||
)
|
||||
private_key = objects.PrivateKey(
|
||||
algorithm,
|
||||
length,
|
||||
private.get('value'),
|
||||
private.get('format')
|
||||
)
|
||||
public_key.names = []
|
||||
private_key.names = []
|
||||
|
||||
self._set_attributes_on_managed_object(
|
||||
public_key,
|
||||
public_key_attributes
|
||||
)
|
||||
self._set_attributes_on_managed_object(
|
||||
private_key,
|
||||
private_key_attributes
|
||||
)
|
||||
|
||||
# TODO (peterhamilton) Set additional server-only attributes.
|
||||
|
||||
self._data_session.add(public_key)
|
||||
self._data_session.add(private_key)
|
||||
|
||||
# NOTE (peterhamilton) SQLAlchemy will *not* assign an ID until
|
||||
# commit is called. This makes future support for UNDO problematic.
|
||||
self._data_session.commit()
|
||||
|
||||
response_payload = create_key_pair.CreateKeyPairResponsePayload(
|
||||
private_key_uuid=attributes.PrivateKeyUniqueIdentifier(
|
||||
str(private_key.unique_identifier)
|
||||
),
|
||||
public_key_uuid=attributes.PublicKeyUniqueIdentifier(
|
||||
str(public_key.unique_identifier)
|
||||
)
|
||||
)
|
||||
|
||||
self._id_placeholder = str(private_key.unique_identifier)
|
||||
return response_payload
|
||||
|
||||
@_kmip_version_supported('1.0')
|
||||
def _process_register(self, payload):
|
||||
self._logger.info("Processing operation: Register")
|
||||
|
@ -847,20 +1012,22 @@ class KmipEngine(object):
|
|||
else:
|
||||
unique_identifier = self._id_placeholder
|
||||
|
||||
object_type = self._get_object_type(unique_identifier)
|
||||
self._get_object_type(unique_identifier)
|
||||
|
||||
# TODO (peterhamilton) Process attributes to see if destroy possible
|
||||
# 1. Check object state. If invalid, error out.
|
||||
# 2. Check object deactivation date. If invalid, error out.
|
||||
|
||||
self._data_session.query(object_type).filter(
|
||||
object_type.unique_identifier == unique_identifier
|
||||
self._data_session.query(objects.ManagedObject).filter(
|
||||
objects.ManagedObject.unique_identifier == unique_identifier
|
||||
).delete()
|
||||
|
||||
response_payload = destroy.DestroyResponsePayload(
|
||||
unique_identifier=attributes.UniqueIdentifier(unique_identifier)
|
||||
)
|
||||
|
||||
self._data_session.commit()
|
||||
|
||||
return response_payload
|
||||
|
||||
@_kmip_version_supported('1.0')
|
||||
|
@ -879,6 +1046,7 @@ class KmipEngine(object):
|
|||
if enums.QueryFunction.QUERY_OPERATIONS in queries:
|
||||
operations = list([
|
||||
contents.Operation(enums.Operation.CREATE),
|
||||
contents.Operation(enums.Operation.CREATE_KEY_PAIR),
|
||||
contents.Operation(enums.Operation.REGISTER),
|
||||
contents.Operation(enums.Operation.GET),
|
||||
contents.Operation(enums.Operation.DESTROY),
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue