Beispiel #1
0
    def write(self, output_buffer, kmip_version=enums.KMIPVersion.KMIP_1_0):
        """
        Write the data encoding the GetAttributeList response payload to a
        stream.

        Args:
            output_buffer (stream): A data stream in which to encode object
                data, supporting a write method; usually a BytearrayStream
                object.
            kmip_version (KMIPVersion): An enumeration defining the KMIP
                version with which the object will be encoded. Optional,
                defaults to KMIP 1.0.

        Raises:
            InvalidField: Raised if the unique identifier or attribute name
                are not defined.
        """
        local_buffer = utils.BytearrayStream()

        if self._unique_identifier:
            self._unique_identifier.write(local_buffer,
                                          kmip_version=kmip_version)
        else:
            raise exceptions.InvalidField(
                "The GetAttributeList response payload is missing the unique "
                "identifier field.")

        if self._attribute_names:
            if kmip_version < enums.KMIPVersion.KMIP_2_0:
                for attribute_name in self._attribute_names:
                    attribute_name.write(local_buffer,
                                         kmip_version=kmip_version)
            else:
                # NOTE (ph) This approach simplifies backwards compatible
                #           issues but limits easy support for Attribute
                #           Reference structures going forward, specifically
                #           limiting the use of VendorIdentification for
                #           custom attributes. If custom attributes need to
                #           be retrieved using the GetAttributeList operation
                #           for KMIP 2.0 applications this code will need to
                #           change.
                for attribute_name in self._attribute_names:
                    t = enums.convert_attribute_name_to_tag(
                        attribute_name.value)
                    e = primitives.Enumeration(
                        enums.Tags,
                        value=t,
                        tag=enums.Tags.ATTRIBUTE_REFERENCE)
                    e.write(local_buffer, kmip_version=kmip_version)

        else:
            raise exceptions.InvalidField(
                "The GetAttributeList response payload is missing the "
                "attribute names field.")

        self.length = local_buffer.length()
        super(GetAttributeListResponsePayload,
              self).write(output_buffer, kmip_version=kmip_version)
        output_buffer.write(local_buffer.buffer)
Beispiel #2
0
    def _build_core_object(self, obj):
        try:
            object_type = obj._object_type
        except Exception:
            raise exceptions.InvalidField(
                "Cannot build an unsupported object type."
            )

        value = {}

        if object_type == enums.ObjectType.CERTIFICATE:
            value = {
                'certificate_type': obj.certificate_type,
                'certificate_value': obj.value
            }
        elif object_type == enums.ObjectType.SYMMETRIC_KEY:
            value = {
                'cryptographic_algorithm': obj.cryptographic_algorithm,
                'cryptographic_length': obj.cryptographic_length,
                'key_format_type': obj.key_format_type,
                'key_value': obj.value
            }
        elif object_type == enums.ObjectType.PUBLIC_KEY:
            value = {
                'cryptographic_algorithm': obj.cryptographic_algorithm,
                'cryptographic_length': obj.cryptographic_length,
                'key_format_type': obj.key_format_type,
                'key_value': obj.value
            }
        elif object_type == enums.ObjectType.PRIVATE_KEY:
            value = {
                'cryptographic_algorithm': obj.cryptographic_algorithm,
                'cryptographic_length': obj.cryptographic_length,
                'key_format_type': obj.key_format_type,
                'key_value': obj.value
            }
        elif object_type == enums.ObjectType.SECRET_DATA:
            value = {
                'key_format_type': enums.KeyFormatType.OPAQUE,
                'key_value': obj.value,
                'secret_data_type': obj.data_type
            }
        elif object_type == enums.ObjectType.OPAQUE_DATA:
            value = {
                'opaque_data_type': obj.opaque_type,
                'opaque_data_value': obj.value
            }
        else:
            name = object_type.name
            raise exceptions.InvalidField(
                "The {0} object type is not supported.".format(
                    ''.join(
                        [x.capitalize() for x in name.split('_')]
                    )
                )
            )

        secret_factory = secrets.SecretFactory()
        return secret_factory.create(object_type, value)
Beispiel #3
0
    def create_symmetric_key(self, algorithm, length):
        """
        Create a symmetric key.

        Args:
            algorithm(CryptographicAlgorithm): An enumeration specifying the
                algorithm for which the created key will be compliant.
            length(int): The length of the key to be created. This value must
                be compliant with the constraints of the provided algorithm.

        Returns:
            dict: A dictionary containing the key data, with the following
                key/value fields:
                * value - the bytes of the key
                * format - a KeyFormatType enumeration for the bytes format

        Raises:
            InvalidField: Raised when the algorithm is unsupported or the
                length is incompatible with the algorithm.
            CryptographicFailure: Raised when the key generation process
                fails.

        Example:
            >>> engine = CryptographyEngine()
            >>> key = engine.create_symmetric_key(
            ...     CryptographicAlgorithm.AES, 256)
        """
        if algorithm not in self._symmetric_key_algorithms.keys():
            raise exceptions.InvalidField(
                "The cryptographic algorithm {0} is not a supported symmetric "
                "key algorithm.".format(algorithm)
            )

        cryptography_algorithm = self._symmetric_key_algorithms.get(algorithm)

        if length not in cryptography_algorithm.key_sizes:
            raise exceptions.InvalidField(
                "The cryptographic length ({0}) is not valid for "
                "the cryptographic algorithm ({1}).".format(
                    length, algorithm.name
                )
            )

        self.logger.info(
            "Generating a {0} symmetric key with length: {1}".format(
                algorithm.name, length
            )
        )

        key_bytes = os.urandom(length // 8)
        try:
            cryptography_algorithm(key_bytes)
        except Exception as e:
            self.logger.exception(e)
            raise exceptions.CryptographicFailure(
                "Invalid bytes for the provided cryptographic algorithm.")

        return {'value': key_bytes, 'format': enums.KeyFormatType.RAW}
Beispiel #4
0
    def write(self, output_buffer, kmip_version=enums.KMIPVersion.KMIP_1_0):
        """
        Write the data encoding the CreateKeyPair response payload to a buffer.

        Args:
            output_buffer (stream): A data buffer in which to encode object
                data, supporting a write method.
            kmip_version (KMIPVersion): An enumeration defining the KMIP
                version with which the object will be encoded. Optional,
                defaults to KMIP 1.0.

        Raises:
            InvalidField: Raised if the private key unique identifier or the
                public key unique identifier is not defined.
        """
        local_buffer = utils.BytearrayStream()

        if self._private_key_unique_identifier:
            self._private_key_unique_identifier.write(
                local_buffer,
                kmip_version=kmip_version
            )
        else:
            raise exceptions.InvalidField(
                "The CreateKeyPair response payload is missing the private "
                "key unique identifier field."
            )

        if self._public_key_unique_identifier:
            self._public_key_unique_identifier.write(
                local_buffer,
                kmip_version=kmip_version
            )
        else:
            raise exceptions.InvalidField(
                "The CreateKeyPair response payload is missing the public "
                "key unique identifier field."
            )

        if self._private_key_template_attribute:
            self._private_key_template_attribute.write(
                local_buffer,
                kmip_version=kmip_version
            )

        if self._public_key_template_attribute:
            self._public_key_template_attribute.write(
                local_buffer,
                kmip_version=kmip_version
            )

        self.length = local_buffer.length()
        super(CreateKeyPairResponsePayload, self).write(
            output_buffer,
            kmip_version=kmip_version
        )
        output_buffer.write(local_buffer.buffer)
Beispiel #5
0
    def write(self, output_buffer, kmip_version=enums.KMIPVersion.KMIP_1_0):
        """
        Write the data encoding the Create request payload to a buffer.

        Args:
            output_buffer (stream): A data buffer in which to encode object
                data, supporting a write method.
            kmip_version (KMIPVersion): An enumeration defining the KMIP
                version with which the object will be encoded. Optional,
                defaults to KMIP 1.0.

        Raises:
            InvalidField: Raised if the object type attribute or template
                attribute is not defined.
        """
        local_buffer = utils.BytearrayStream()

        if self._object_type:
            self._object_type.write(local_buffer, kmip_version=kmip_version)
        else:
            raise exceptions.InvalidField(
                "The Create request payload is missing the object type field.")

        if kmip_version < enums.KMIPVersion.KMIP_2_0:
            if self._template_attribute:
                self._template_attribute.write(local_buffer,
                                               kmip_version=kmip_version)
            else:
                raise exceptions.InvalidField(
                    "The Create request payload is missing the template "
                    "attribute field.")
        else:
            # NOTE (ph) For now, leave attributes natively in TemplateAttribute
            # form and just convert to the KMIP 2.0 Attributes form as needed
            # for encoding/decoding purposes. Changing the payload to require
            # the new Attributes structure will trigger a bunch of second-order
            # effects across the client and server codebases that is beyond
            # the scope of updating the Create payloads to support KMIP 2.0.
            if self._template_attribute:
                attributes = objects.convert_template_attribute_to_attributes(
                    self._template_attribute)
                attributes.write(local_buffer, kmip_version=kmip_version)
            else:
                raise exceptions.InvalidField(
                    "The Create request payload is missing the template "
                    "attribute field.")

        if kmip_version >= enums.KMIPVersion.KMIP_2_0:
            if self._protection_storage_masks:
                self._protection_storage_masks.write(local_buffer,
                                                     kmip_version=kmip_version)

        self.length = local_buffer.length()
        super(CreateRequestPayload, self).write(output_buffer,
                                                kmip_version=kmip_version)
        output_buffer.write(local_buffer.buffer)
Beispiel #6
0
    def _set_attribute_on_managed_object(self, managed_object, attribute):
        """
        Set the attribute value on the kmip.pie managed object.
        """
        attribute_name = attribute[0]
        attribute_value = attribute[1]

        if self._attribute_policy.is_attribute_multivalued(attribute_name):
            if attribute_name == 'Name':
                managed_object.names.extend(
                    [x.name_value.value for x in attribute_value]
                )
                for name in managed_object.names:
                    if managed_object.names.count(name) > 1:
                        raise exceptions.InvalidField(
                            "Cannot set duplicate name values."
                        )
            else:
                # TODO (peterhamilton) Remove when all attributes are supported
                raise exceptions.InvalidField(
                    "The {0} attribute is unsupported.".format(attribute_name)
                )
        else:
            field = None
            value = attribute_value.value

            if attribute_name == 'Cryptographic Algorithm':
                field = 'cryptographic_algorithm'
            elif attribute_name == 'Cryptographic Length':
                field = 'cryptographic_length'
            elif attribute_name == 'Cryptographic Usage Mask':
                field = 'cryptographic_usage_masks'
                value = list()
                for e in enums.CryptographicUsageMask:
                    if e.value & attribute_value.value:
                        value.append(e)

            if field:
                existing_value = getattr(managed_object, field)
                if existing_value:
                    if existing_value != value:
                        raise exceptions.InvalidField(
                            "Cannot overwrite the {0} attribute.".format(
                                attribute_name
                            )
                        )
                else:
                    setattr(managed_object, field, value)
            else:
                # TODO (peterhamilton) Remove when all attributes are supported
                raise exceptions.InvalidField(
                    "The {0} attribute is unsupported.".format(attribute_name)
                )
Beispiel #7
0
    def _process_register(self, payload):
        self._logger.info("Processing operation: Register")

        object_type = payload.object_type.value
        template_attribute = payload.template_attribute

        if self._object_map.get(object_type) is None:
            name = object_type.name
            raise exceptions.InvalidField(
                "The {0} object type is not supported.".format(''.join(
                    [x.capitalize() for x in name.split('_')])))

        if payload.secret:
            secret = payload.secret
        else:
            # TODO (peterhamilton) It is possible to register 'empty' secrets
            # like Private Keys. For now, that feature is not supported.
            raise exceptions.InvalidField(
                "Cannot register a secret in absentia.")

        object_attributes = {}
        if template_attribute:
            object_attributes = self._process_template_attribute(
                template_attribute)

        managed_object_factory = factory.ObjectFactory()
        managed_object = managed_object_factory.convert(secret)
        managed_object.names = []

        self._set_attributes_on_managed_object(managed_object,
                                               object_attributes)

        # TODO (peterhamilton) Set additional server-only attributes.
        managed_object._owner = self._client_identity

        self._data_session.add(managed_object)

        # NOTE (peterhamilton) SQLAlchemy will *not* assign an ID until
        # commit is called. This makes future support for UNDO problematic.
        self._data_session.commit()

        self._logger.info("Registered a {0} with ID: {1}".format(
            ''.join([x.capitalize() for x in object_type.name.split('_')]),
            managed_object.unique_identifier))

        response_payload = register.RegisterResponsePayload(
            unique_identifier=attributes.UniqueIdentifier(
                str(managed_object.unique_identifier)))

        self._id_placeholder = str(managed_object.unique_identifier)

        return response_payload
Beispiel #8
0
    def write(self, output_buffer, kmip_version=enums.KMIPVersion.KMIP_1_0):
        """
        Write the data encoding the GetAttributes response payload to a
        stream.

        Args:
            output_buffer (stream): A data stream in which to encode object
                data, supporting a write method; usually a BytearrayStream
                object.
            kmip_version (KMIPVersion): An enumeration defining the KMIP
                version with which the object will be encoded. Optional,
                defaults to KMIP 1.0.
        """
        local_buffer = utils.BytearrayStream()

        if self._unique_identifier:
            self._unique_identifier.write(
                local_buffer,
                kmip_version=kmip_version
            )
        else:
            raise exceptions.InvalidField(
                "The GetAttributes response payload is missing the unique "
                "identifier field."
            )

        if kmip_version < enums.KMIPVersion.KMIP_2_0:
            for attribute in self._attributes:
                attribute.write(local_buffer, kmip_version=kmip_version)
        else:
            if self._attributes:
                # TODO (ph) Add a new utility to avoid using TemplateAttributes
                template_attribute = objects.TemplateAttribute(
                    attributes=self.attributes
                )
                attributes = objects.convert_template_attribute_to_attributes(
                    template_attribute
                )
                attributes.write(local_buffer, kmip_version=kmip_version)
            else:
                raise exceptions.InvalidField(
                    "The GetAttributes response payload is missing the "
                    "attributes list."
                )

        self.length = local_buffer.length()
        super(GetAttributesResponsePayload, self).write(
            output_buffer,
            kmip_version=kmip_version
        )
        output_buffer.write(local_buffer.buffer)
Beispiel #9
0
    def write(self, output_buffer, kmip_version=enums.KMIPVersion.KMIP_1_0):
        """
        Write the data encoding the DeleteAttribute request payload to a
        stream.

        Args:
            output_buffer (stream): A data stream in which to encode object
                data, supporting a write method; usually a BytearrayStream
                object.
            kmip_version (KMIPVersion): An enumeration defining the KMIP
                version with which the object will be encoded. Optional,
                defaults to KMIP 1.0.

        Raises:
            InvalidField
        """
        local_buffer = utils.BytearrayStream()

        if self._unique_identifier:
            self._unique_identifier.write(local_buffer,
                                          kmip_version=kmip_version)

        if kmip_version < enums.KMIPVersion.KMIP_2_0:
            if self._attribute_name:
                self._attribute_name.write(local_buffer,
                                           kmip_version=kmip_version)
            else:
                raise exceptions.InvalidField(
                    "The DeleteAttribute request payload is missing the "
                    "attribute name field.")

            if self._attribute_index:
                self._attribute_index.write(local_buffer,
                                            kmip_version=kmip_version)
        else:
            if self._current_attribute == self._attribute_reference:
                raise exceptions.InvalidField(
                    "The DeleteAttribute request payload is missing either "
                    "the current attribute or the attribute reference field.")

            if self._current_attribute:
                self._current_attribute.write(local_buffer,
                                              kmip_version=kmip_version)
            if self._attribute_reference:
                self._attribute_reference.write(local_buffer,
                                                kmip_version=kmip_version)

        self.length = local_buffer.length()
        super(DeleteAttributeRequestPayload,
              self).write(output_buffer, kmip_version=kmip_version)
        output_buffer.write(local_buffer.buffer)
Beispiel #10
0
    def write(self, output_buffer, kmip_version=enums.KMIPVersion.KMIP_1_0):
        """
        Write the data encoding the DeleteAttribute response payload to a
        buffer.

        Args:
            output_buffer (buffer): A data buffer in which to encode object
                data, supporting a write method; usually a BytearrayStream
                object.
            kmip_version (enum): A KMIPVersion enumeration defining the KMIP
                version with which the object will be encoded. Optional,
                defaults to KMIP 1.0.

        Raises:
            InvalidField: Raised if a required field is missing from the
                payload object.
        """
        local_buffer = utils.BytearrayStream()

        if self._unique_identifier:
            self._unique_identifier.write(
                local_buffer,
                kmip_version=kmip_version
            )
        else:
            raise exceptions.InvalidField(
                "The DeleteAttribute response payload is missing the unique "
                "identifier field."
            )

        if kmip_version < enums.KMIPVersion.KMIP_2_0:
            if self._attribute:
                self._attribute.write(
                    local_buffer,
                    kmip_version=kmip_version
                )
            else:
                raise exceptions.InvalidField(
                    "The DeleteAttribute response payload is missing the "
                    "attribute field."
                )

        self.length = local_buffer.length()
        super(DeleteAttributeResponsePayload, self).write(
            output_buffer,
            kmip_version=kmip_version
        )
        output_buffer.write(local_buffer.buffer)
Beispiel #11
0
    def _get_object_type(self, unique_identifier):
        try:
            object_type = self._data_session.query(
                objects.ManagedObject._object_type).filter(
                    objects.ManagedObject.unique_identifier ==
                    unique_identifier).one()[0]
        except exc.NoResultFound as e:
            self._logger.warning(
                "Could not identify object type for object: {0}".format(
                    unique_identifier))
            self._logger.exception(e)
            raise exceptions.ItemNotFound(
                "Could not locate object: {0}".format(unique_identifier))
        except exc.MultipleResultsFound as e:
            self._logger.warning(
                "Multiple objects found for ID: {0}".format(unique_identifier))
            raise e

        class_type = self._object_map.get(object_type)
        if class_type is None:
            name = object_type.name
            raise exceptions.InvalidField(
                "The {0} object type is not supported.".format(''.join(
                    [x.capitalize() for x in name.split('_')])))

        return class_type
Beispiel #12
0
    def write(self, output_buffer, kmip_version=enums.KMIPVersion.KMIP_1_0):
        """
        Write the data encoding the DeriveKey response payload to a stream.

        Args:
            output_buffer (stream): A data stream in which to encode object
                data, supporting a write method; usually a BytearrayStream
                object.
            kmip_version (KMIPVersion): An enumeration defining the KMIP
                version with which the object will be encoded. Optional,
                defaults to KMIP 1.0.

        Raises:
            ValueError: Raised if the data attribute is not defined.
        """
        local_buffer = utils.BytearrayStream()

        if self._unique_identifier:
            self._unique_identifier.write(local_buffer,
                                          kmip_version=kmip_version)
        else:
            raise exceptions.InvalidField(
                "The DeriveKey response payload is missing the unique "
                "identifier field.")

        if kmip_version < enums.KMIPVersion.KMIP_2_0:
            if self._template_attribute:
                self._template_attribute.write(local_buffer,
                                               kmip_version=kmip_version)

        self.length = local_buffer.length()
        super(DeriveKeyResponsePayload, self).write(output_buffer,
                                                    kmip_version=kmip_version)
        output_buffer.write(local_buffer.buffer)
Beispiel #13
0
    def write(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
        """
        Write the data encoding the GetAttributes response payload to a
        stream.

        Args:
            ostream (stream): A data stream in which to encode object data,
                supporting a write method; usually a BytearrayStream object.
            kmip_version (KMIPVersion): An enumeration defining the KMIP
                version with which the object will be encoded. Optional,
                defaults to KMIP 1.0.
        """
        tstream = utils.BytearrayStream()

        if self._unique_identifier:
            self._unique_identifier.write(tstream, kmip_version=kmip_version)
        else:
            raise exceptions.InvalidField(
                "The GetAttributes response unique identifier is required.")

        for attribute in self._attributes:
            attribute.write(tstream, kmip_version=kmip_version)

        self.length = tstream.length()
        super(GetAttributesResponsePayload,
              self).write(ostream, kmip_version=kmip_version)
        ostream.write(tstream.buffer)
Beispiel #14
0
    def write(self, output_buffer, kmip_version=enums.KMIPVersion.KMIP_1_0):
        """
        Write the data encoding the QueryRequestPayload object to a stream.

        Args:
            output_buffer (Stream): A data stream in which to encode object
                data, supporting a write method; usually a BytearrayStream
                object.
            kmip_version (KMIPVersion): An enumeration defining the KMIP
                version with which the object will be encoded. Optional,
                defaults to KMIP 1.0.

        Raises:
            InvalidField: Raised if the query functions are not defined.
        """
        local_buffer = utils.BytearrayStream()

        if self._query_functions:
            for query_function in self._query_functions:
                query_function.write(local_buffer, kmip_version=kmip_version)
        else:
            raise exceptions.InvalidField(
                "The Query request payload is missing the query functions "
                "field.")

        self.length = local_buffer.length()
        super(QueryRequestPayload, self).write(output_buffer,
                                               kmip_version=kmip_version)
        output_buffer.write(local_buffer.buffer)
Beispiel #15
0
    def write(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
        tstream = BytearrayStream()

        if self._unique_identifier is not None:
            self._unique_identifier.write(tstream, kmip_version=kmip_version)
        else:
            raise exceptions.InvalidField(
                "The mac response unique identifier is required")
        if self._mac_data is not None:
            self._mac_data.write(tstream, kmip_version=kmip_version)
        else:
            raise exceptions.InvalidField(
                "The mac response mac data is required")
        self.length = tstream.length()
        super(MACResponsePayload, self).write(ostream,
                                              kmip_version=kmip_version)
        ostream.write(tstream.buffer)
Beispiel #16
0
    def _process_template_attribute(self, template_attribute):
        """
        Given a kmip.core TemplateAttribute object, extract the attribute
        value data into a usable dictionary format.
        """
        attributes = {}

        if len(template_attribute.names) > 0:
            raise exceptions.ItemNotFound(
                "Attribute templates are not supported."
            )

        for attribute in template_attribute.attributes:
            name = attribute.attribute_name.value

            if not self._attribute_policy.is_attribute_supported(name):
                raise exceptions.InvalidField(
                    "The {0} attribute is unsupported.".format(name)
                )

            if self._attribute_policy.is_attribute_multivalued(name):
                values = attributes.get(name, list())
                if (not attribute.attribute_index) and len(values) > 0:
                    raise exceptions.InvalidField(
                        "Attribute index missing from multivalued attribute."
                    )

                values.append(attribute.attribute_value)
                attributes.update([(name, values)])
            else:
                if attribute.attribute_index:
                    if attribute.attribute_index.value != 0:
                        raise exceptions.InvalidField(
                            "Non-zero attribute index found for "
                            "single-valued attribute."
                        )
                value = attributes.get(name, None)
                if value:
                    raise exceptions.IndexOutOfBounds(
                        "Cannot set multiple instances of the "
                        "{0} attribute.".format(name)
                    )
                else:
                    attributes.update([(name, attribute.attribute_value)])

        return attributes
Beispiel #17
0
    def write(self, output_buffer, kmip_version=enums.KMIPVersion.KMIP_1_0):
        """
        Write the data encoding the Locate request payload to a buffer.

        Args:
            output_buffer (stream): A data buffer in which to encode object
                data, supporting a write method.
            kmip_version (KMIPVersion): An enumeration defining the KMIP
                version with which the object will be encoded. Optional,
                defaults to KMIP 1.0.
        """
        local_buffer = utils.BytearrayStream()

        if self._maximum_items:
            self._maximum_items.write(local_buffer, kmip_version=kmip_version)

        if self._offset_items:
            self._offset_items.write(local_buffer, kmip_version=kmip_version)

        if self._storage_status_mask:
            self._storage_status_mask.write(local_buffer,
                                            kmip_version=kmip_version)

        if self._object_group_member:
            self._object_group_member.write(local_buffer,
                                            kmip_version=kmip_version)

        if kmip_version < enums.KMIPVersion.KMIP_2_0:
            if self._attributes:
                for attribute in self.attributes:
                    attribute.write(local_buffer, kmip_version=kmip_version)
        else:
            if self._attributes:
                # TODO (ph) Add a new utility to avoid using TemplateAttributes
                template_attribute = objects.TemplateAttribute(
                    attributes=self.attributes)
                attributes = objects.convert_template_attribute_to_attributes(
                    template_attribute)
                attributes.write(local_buffer, kmip_version=kmip_version)
            else:
                raise exceptions.InvalidField(
                    "The Locate request payload is missing the attributes "
                    "list.")

        self.length = local_buffer.length()
        super(LocateRequestPayload, self).write(output_buffer,
                                                kmip_version=kmip_version)
        output_buffer.write(local_buffer.buffer)
Beispiel #18
0
    def write(self, ostream):
        tstream = BytearrayStream()

        if self._unique_identifier is not None:
            self._unique_identifier.write(tstream)
        if self._cryptographic_parameters is not None:
            self._cryptographic_parameters.write(tstream)
        if self._data is not None:
            self.data.write(tstream)
        else:
            raise exceptions.InvalidField(
                "The mac request data is required"
            )

        self.length = tstream.length()
        super(MACRequestPayload, self).write(ostream)
        ostream.write(tstream.buffer)
Beispiel #19
0
 def _set_attributes_on_managed_object(self, managed_object, attributes):
     """
     Given a kmip.pie object and a dictionary of attributes, attempt to set
     the attribute values on the object.
     """
     for attribute_name, attribute_value in six.iteritems(attributes):
         object_type = managed_object._object_type
         if self._attribute_policy.is_attribute_applicable_to_object_type(
                 attribute_name, object_type):
             self._set_attribute_on_managed_object(
                 managed_object, (attribute_name, attribute_value))
         else:
             name = object_type.name
             raise exceptions.InvalidField(
                 "Cannot set {0} attribute on {1} object.".format(
                     attribute_name,
                     ''.join([x.capitalize() for x in name.split('_')])))
Beispiel #20
0
    def write(self, output_buffer, kmip_version=enums.KMIPVersion.KMIP_2_0):
        """
        Write the data encoding the SetAttribute request payload to a
        stream.

        Args:
            output_buffer (stream): A data stream in which to encode object
                data, supporting a write method; usually a BytearrayStream
                object.
            kmip_version (KMIPVersion): An enumeration defining the KMIP
                version with which the object will be encoded. Optional,
                defaults to KMIP 1.0.

        Raises:
            VersionNotSupported: Raised when a KMIP version is provided that
                does not support the SetAttribute operation.
            InvalidField: Raised if a required field is missing from the
                payload object.
        """
        if kmip_version < enums.KMIPVersion.KMIP_2_0:
            raise exceptions.VersionNotSupported(
                "KMIP {} does not support the SetAttribute operation.".format(
                    kmip_version.value))

        local_buffer = utils.BytearrayStream()

        if self._unique_identifier:
            self._unique_identifier.write(local_buffer,
                                          kmip_version=kmip_version)

        if self._new_attribute:
            self._new_attribute.write(local_buffer, kmip_version=kmip_version)
        else:
            raise exceptions.InvalidField(
                "The SetAttribute request payload is missing the new "
                "attribute field.")

        self.length = local_buffer.length()
        super(SetAttributeRequestPayload,
              self).write(output_buffer, kmip_version=kmip_version)
        output_buffer.write(local_buffer.buffer)
Beispiel #21
0
    def write(self, ostream):
        """
        Write the data encoding the GetAttributes response payload to a
        stream.

        Args:
            ostream (stream): A data stream in which to encode object data,
                supporting a write method; usually a BytearrayStream object.
        """
        tstream = utils.BytearrayStream()

        if self._unique_identifier:
            self._unique_identifier.write(tstream)
        else:
            raise exceptions.InvalidField(
                "The GetAttributes response unique identifier is required.")

        for attribute in self._attributes:
            attribute.write(tstream)

        self.length = tstream.length()
        super(GetAttributesResponsePayload, self).write(ostream)
        ostream.write(tstream.buffer)
Beispiel #22
0
    def create_asymmetric_key_pair(self, algorithm, length):
        """
        Create an asymmetric key pair.

        Args:
            algorithm(CryptographicAlgorithm): An enumeration specifying the
                algorithm for which the created keys will be compliant.
            length(int): The length of the keys to be created. This value must
                be compliant with the constraints of the provided algorithm.

        Returns:
            dict: A dictionary containing the public key data, with at least
                the following key/value fields:
                * value - the bytes of the key
                * format - a KeyFormatType enumeration for the bytes format
            dict: A dictionary containing the private key data, identical in
                structure to the one above.

        Raises:
            InvalidField: Raised when the algorithm is unsupported or the
                length is incompatible with the algorithm.
            CryptographicFailure: Raised when the key generation process
                fails.

        Example:
            >>> engine = CryptographyEngine()
            >>> key = engine.create_asymmetric_key(
            ...     CryptographicAlgorithm.RSA, 2048)
        """
        if algorithm not in self._asymetric_key_algorithms.keys():
            raise exceptions.InvalidField(
                "The cryptographic algorithm ({0}) is not a supported "
                "asymmetric key algorithm.".format(algorithm)
            )

        engine_method = self._asymetric_key_algorithms.get(algorithm)
        return engine_method(length)
Beispiel #23
0
    def mac(self, algorithm, key, data):
        """
        Generate message authentication code.

        Args:
            algorithm(CryptographicAlgorithm): An enumeration specifying the
                algorithm for which the MAC operation will use.
            key(bytes): secret key used in the MAC operation
            data(bytes): The data to be MACed.

        Returns:
            bytes: The MACed data

        Raises:
            InvalidField: Raised when the algorithm is unsupported or the
                length is incompatible with the algorithm.
            CryptographicFailure: Raised when the key generation process
                fails.

        Example:
            >>> engine = CryptographyEngine()
            >>> mac_data = engine.mac(
            ...     CryptographicAlgorithm.HMAC-SHA256, b'\x01\x02\x03\x04',
            ...     b'\x05\x06\x07\x08')
        """

        mac_data = None

        if algorithm in self._hash_algorithms.keys():
            self.logger.info(
                "Generating a hash-based message authentication code using "
                "{0}".format(algorithm.name))
            hash_algorithm = self._hash_algorithms.get(algorithm)
            try:
                h = hmac.HMAC(key, hash_algorithm(), backend=default_backend())
                h.update(data)
                mac_data = h.finalize()
            except Exception as e:
                self.logger.exception(e)
                raise exceptions.CryptographicFailure(
                    "An error occurred while computing an HMAC. "
                    "See the server log for more information.")
        elif algorithm in self._symmetric_key_algorithms.keys():
            self.logger.info(
                "Generating a cipher-based message authentication code using "
                "{0}".format(algorithm.name))
            cipher_algorithm = self._symmetric_key_algorithms.get(algorithm)
            try:
                # ARC4 and IDEA algorithms will raise exception as CMAC
                # requires block ciphers
                c = cmac.CMAC(cipher_algorithm(key), backend=default_backend())
                c.update(data)
                mac_data = c.finalize()
            except Exception as e:
                raise exceptions.CryptographicFailure(
                    "An error occurred while computing a CMAC. "
                    "See the server log for more information.")
        else:
            raise exceptions.InvalidField(
                "The cryptographic algorithm ({0}) is not a supported "
                "for a MAC operation.".format(algorithm))
        return mac_data
Beispiel #24
0
    def write(self, output_buffer, kmip_version=enums.KMIPVersion.KMIP_1_0):
        """
        Write the data encoding the SplitKey object to a buffer.

        Args:
            output_buffer (stream): A data stream in which to encode object
                data, supporting a write method; usually a BytearrayStream
                object.
            kmip_version (KMIPVersion): An enumeration defining the KMIP
                version with which the object will be encoded. Optional,
                defaults to KMIP 1.0.
        """
        local_buffer = utils.BytearrayStream()

        if self._split_key_parts:
            self._split_key_parts.write(
                local_buffer,
                kmip_version=kmip_version
            )
        else:
            raise exceptions.InvalidField(
                "The SplitKey object is missing the SplitKeyParts field."
            )

        if self._key_part_identifier:
            self._key_part_identifier.write(
                local_buffer,
                kmip_version=kmip_version
            )
        else:
            raise exceptions.InvalidField(
                "The SplitKey object is missing the KeyPartIdentifier field."
            )

        if self._split_key_threshold:
            self._split_key_threshold.write(
                local_buffer,
                kmip_version=kmip_version
            )
        else:
            raise exceptions.InvalidField(
                "The SplitKey object is missing the SplitKeyThreshold field."
            )

        if self._split_key_method:
            self._split_key_method.write(
                local_buffer,
                kmip_version=kmip_version
            )
        else:
            raise exceptions.InvalidField(
                "The SplitKey object is missing the SplitKeyMethod field."
            )

        if self._prime_field_size:
            self._prime_field_size.write(
                local_buffer,
                kmip_version=kmip_version
            )
        else:
            corner_case = enums.SplitKeyMethod.POLYNOMIAL_SHARING_PRIME_FIELD
            if self.split_key_method == corner_case:
                raise exceptions.InvalidField(
                    "The SplitKey object is missing the PrimeFieldSize field. "
                    "This field is required when the SplitKeyMethod is "
                    "PolynomialSharingPrimeField."
                )

        if self._key_block:
            self._key_block.write(local_buffer, kmip_version=kmip_version)
        else:
            raise exceptions.InvalidField(
                "The SplitKey object is missing the KeyBlock field."
            )

        self.length = local_buffer.length()
        super(SplitKey, self).write(output_buffer, kmip_version=kmip_version)
        output_buffer.write(local_buffer.buffer)
Beispiel #25
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.
        public_key._owner = self._client_identity
        private_key._owner = self._client_identity

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

        self._logger.info("Created a PublicKey with ID: {0}".format(
            public_key.unique_identifier))
        self._logger.info("Created a PrivateKey with ID: {0}".format(
            private_key.unique_identifier))

        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
Beispiel #26
0
    def _process_create(self, payload):
        self._logger.info("Processing operation: Create")

        object_type = payload.object_type.value
        template_attribute = payload.template_attribute

        if object_type != enums.ObjectType.SYMMETRIC_KEY:
            name = object_type.name
            raise exceptions.InvalidField(
                "Cannot create a {0} object with the Create operation.".format(
                    ''.join([x.capitalize() for x in name.split('_')])))

        object_attributes = {}
        if template_attribute:
            object_attributes = self._process_template_attribute(
                template_attribute)

        algorithm = object_attributes.get('Cryptographic Algorithm')
        if algorithm:
            algorithm = algorithm.value
        else:
            raise exceptions.InvalidField(
                "The cryptographic algorithm must be specified as an "
                "attribute.")

        length = object_attributes.get('Cryptographic Length')
        if length:
            length = 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.")

        usage_mask = object_attributes.get('Cryptographic Usage Mask')
        if usage_mask is None:
            raise exceptions.InvalidField(
                "The cryptographic usage mask must be specified as an "
                "attribute.")

        result = self._cryptography_engine.create_symmetric_key(
            algorithm, length)

        managed_object = objects.SymmetricKey(algorithm, length,
                                              result.get('value'))
        managed_object.names = []

        self._set_attributes_on_managed_object(managed_object,
                                               object_attributes)

        # TODO (peterhamilton) Set additional server-only attributes.
        managed_object._owner = self._client_identity

        self._data_session.add(managed_object)

        # NOTE (peterhamilton) SQLAlchemy will *not* assign an ID until
        # commit is called. This makes future support for UNDO problematic.
        self._data_session.commit()

        self._logger.info("Created a SymmetricKey with ID: {0}".format(
            managed_object.unique_identifier))

        response_payload = create.CreateResponsePayload(
            object_type=payload.object_type,
            unique_identifier=attributes.UniqueIdentifier(
                str(managed_object.unique_identifier)),
            template_attribute=None)

        self._id_placeholder = str(managed_object.unique_identifier)

        return response_payload