"Fossies" - the Fresh Open Source Software Archive

Member "barbican-12.0.0/barbican/plugin/crypto/base.py" (14 Apr 2021, 15140 Bytes) of package /linux/misc/openstack/barbican-12.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "base.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 11.0.0_vs_12.0.0.

    1 # Licensed under the Apache License, Version 2.0 (the "License");
    2 # you may not use this file except in compliance with the License.
    3 # You may obtain a copy of the License at
    4 #
    5 #    http://www.apache.org/licenses/LICENSE-2.0
    6 #
    7 # Unless required by applicable law or agreed to in writing, software
    8 # distributed under the License is distributed on an "AS IS" BASIS,
    9 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
   10 # implied.
   11 # See the License for the specific language governing permissions and
   12 # limitations under the License.
   13 
   14 import abc
   15 
   16 from barbican.common import exception
   17 from barbican import i18n as u
   18 
   19 
   20 class CryptoPluginNotFound(exception.BarbicanException):
   21     """Raised when no plugins are installed."""
   22     message = u._("Crypto plugin not found.")
   23 
   24 
   25 class CryptoKEKBindingException(exception.BarbicanException):
   26     """Raised when the bind_kek_metadata method from a plugin returns None."""
   27     def __init__(self, plugin_name=u._('Unknown')):
   28         super(CryptoKEKBindingException, self).__init__(
   29             u._('Failed to bind kek metadata for '
   30                 'plugin: {name}').format(name=plugin_name)
   31         )
   32         self.plugin_name = plugin_name
   33 
   34 
   35 class CryptoPrivateKeyFailureException(exception.BarbicanException):
   36     """Raised when could not generate private key."""
   37     def __init__(self):
   38         super(CryptoPrivateKeyFailureException, self).__init__(
   39             u._('Could not generate private key')
   40         )
   41 
   42 
   43 class CryptoPluginUnsupportedOperation(exception.BarbicanException):
   44     """Raised when no crypto plugins support the operation."""
   45     def __init__(self, operation):
   46         message = (
   47             u._('Could not find an enabled crypto plugin backend '
   48                 'that supports the requested operation: {operation}')
   49             .format(operation=operation))
   50         super(CryptoPluginUnsupportedOperation, self).__init__(message)
   51 
   52 
   53 # TODO(john-wood-w) Need to harmonize these lower-level constants with the
   54 #  higher level constants in secret_store.py.
   55 class PluginSupportTypes(object):
   56     """Class to hold the type enumeration that plugins may support."""
   57     ENCRYPT_DECRYPT = "ENCRYPT_DECRYPT"
   58     SYMMETRIC_KEY_GENERATION = "SYMMETRIC_KEY_GENERATION"
   59     # A list of symmetric algorithms that are used to determine type of key gen
   60     SYMMETRIC_ALGORITHMS = ['aes', 'des', '3des', 'hmacsha1',
   61                             'hmacsha256', 'hmacsha384', 'hmacsha512']
   62     SYMMETRIC_KEY_LENGTHS = [64, 128, 192, 256]
   63 
   64     ASYMMETRIC_KEY_GENERATION = "ASYMMETRIC_KEY_GENERATION"
   65     ASYMMETRIC_ALGORITHMS = ['rsa', 'dsa']
   66     ASYMMETRIC_KEY_LENGTHS = [1024, 2048, 4096]
   67 
   68 
   69 class KEKMetaDTO(object):
   70     """Key Encryption Key Meta DTO
   71 
   72     Key Encryption Keys (KEKs) in Barbican are intended to represent a
   73     distinct key that is used to perform encryption on secrets for a particular
   74     project.
   75 
   76     ``KEKMetaDTO`` objects are provided to cryptographic backends by Barbican
   77     to allow plugins to persist metadata related to the project's KEK.
   78 
   79     For example, a plugin that interfaces with a Hardware Security Module (HSM)
   80     may want to use a different encryption key for each project. Such a plugin
   81     could use the ``KEKMetaDTO`` object to save the key ID used for that
   82     project.  Barbican will persist the KEK metadata and ensure that it is
   83     provided to the plugin every time a request from that same project is
   84     processed.
   85 
   86     .. attribute:: plugin_name
   87 
   88         String attribute used by Barbican to identify the plugin that is bound
   89         to the KEK metadata.  Plugins should not change this attribute.
   90 
   91     .. attribute:: kek_label
   92 
   93         String attribute used to label the project's KEK by the plugin.
   94         The value of this attribute should be meaningful to the plugin.
   95         Barbican does not use this value.
   96 
   97     .. attribute:: algorithm
   98 
   99         String attribute used to identify the encryption algorithm used by the
  100         plugin. e.g. "AES", "3DES", etc.  This value should be meaningful to
  101         the plugin.  Barbican does not use this value.
  102 
  103     .. attribute:: mode
  104 
  105         String attribute used to identify the algorithm mode used by the
  106         plugin.  e.g. "CBC", "GCM", etc.  This value should be meaningful to
  107         the plugin.  Barbican does not use this value.
  108 
  109     .. attribute:: bit_length
  110 
  111         Integer attribute used to identify the bit length of the KEK by the
  112         plugin.  This value should be meaningful to the plugin.  Barbican does
  113         not use this value.
  114 
  115     .. attribute:: plugin_meta
  116 
  117        String attribute used to persist any additional metadata that does not
  118        fit in any other attribute.  The value of this attribute is defined by
  119        the plugin.  It could be used to store external system references, such
  120        as Key IDs in an HSM, URIs to an external service, or any other data
  121        that the plugin deems necessary to persist.  Because this is just a
  122        plain text field, a plug in may even choose to persist data such as key
  123        value pairs in a JSON object.
  124    """
  125 
  126     def __init__(self, kek_datum):
  127         """Plugins should not have to create their own instance of this class.
  128 
  129         kek_datum is typically a barbican.model.models.KEKDatum instance.
  130         """
  131         self.kek_label = kek_datum.kek_label
  132         self.plugin_name = kek_datum.plugin_name
  133         self.algorithm = kek_datum.algorithm
  134         self.bit_length = kek_datum.bit_length
  135         self.mode = kek_datum.mode
  136         self.plugin_meta = kek_datum.plugin_meta
  137 
  138 
  139 class GenerateDTO(object):
  140     """Secret Generation DTO
  141 
  142     Data Transfer Object used to pass all the necessary data for the plugin
  143     to generate a secret on behalf of the user.
  144 
  145     .. attribute:: generation_type
  146 
  147         String attribute used to identify the type of secret that should be
  148         generated. This will be either ``"symmetric"`` or ``"asymmetric"``.
  149 
  150     .. attribute:: algorithm
  151 
  152         String attribute used to specify what type of algorithm the secret will
  153         be used for.  e.g. ``"AES"`` for a ``"symmetric"`` type, or ``"RSA"``
  154         for ``"asymmetric"``.
  155 
  156     .. attribute:: mode
  157 
  158         String attribute used to specify what algorithm mode the secret will be
  159         used for.  e.g. ``"CBC"`` for ``"AES"`` algorithm.
  160 
  161     .. attribute:: bit_length
  162 
  163         Integer attribute used to specify the bit length of the secret.  For
  164         example, this attribute could specify the key length for an encryption
  165         key to be used in AES-CBC.
  166     """
  167 
  168     def __init__(self, algorithm, bit_length, mode, passphrase=None):
  169         self.algorithm = algorithm
  170         self.bit_length = bit_length
  171         self.mode = mode
  172         self.passphrase = passphrase
  173 
  174 
  175 class ResponseDTO(object):
  176     """Data transfer object for secret generation response.
  177 
  178     Barbican guarantees that both the ``cypher_text`` and
  179     ``kek_metadata_extended`` will be persisted and then given back to
  180     the plugin when requesting a decryption operation.
  181 
  182     ``kek_metadata_extended`` takes the idea of Key Encryption Key
  183     (KEK) metadata further by giving plugins the option to store
  184     secret-level KEK metadata.  One example of using secret-level KEK
  185     metadata would be plugins that want to use a unique KEK for every
  186     secret that is encrypted.  Such a plugin could use
  187     ``kek_metadata_extended`` to store the Key ID for the KEK used to
  188     encrypt this particular secret.
  189 
  190     :param cypher_text: Byte data resulting from the encryption of the
  191         secret data.
  192     :param kek_meta_extended: Optional String object to be persisted alongside
  193         the cyphertext.
  194     """
  195     def __init__(self, cypher_text, kek_meta_extended=None):
  196         self.cypher_text = cypher_text
  197         self.kek_meta_extended = kek_meta_extended
  198 
  199 
  200 class DecryptDTO(object):
  201     """Secret Decryption DTO
  202 
  203     Data Transfer Object used to pass all the necessary data for the plugin
  204     to perform decryption of a secret.
  205 
  206     Currently, this DTO only contains the data produced by the plugin during
  207     encryption, but in the future this DTO will contain more information, such
  208     as a transport key for secret wrapping back to the client.
  209 
  210     .. attribute:: encrypted
  211 
  212         The data that was produced by the plugin during encryption.  For some
  213         plugins this will be the actual bytes that need to be decrypted to
  214         produce the secret.  In other implementations, this may just be a
  215         reference to some external system that can produce the unencrypted
  216         secret.
  217     """
  218 
  219     def __init__(self, encrypted):
  220         self.encrypted = encrypted
  221 
  222 
  223 class EncryptDTO(object):
  224     """Secret Encryption DTO
  225 
  226     Data Transfer Object used to pass all the necessary data for the plugin
  227     to perform encryption of a secret.
  228 
  229     Currently, this DTO only contains the raw bytes to be encrypted by the
  230     plugin, but in the future this may contain more information.
  231 
  232     .. attribute:: unencrypted
  233 
  234         The secret data in Bytes to be encrypted by the plugin.
  235     """
  236 
  237     def __init__(self, unencrypted):
  238         self.unencrypted = unencrypted
  239 
  240 
  241 class CryptoPluginBase(object, metaclass=abc.ABCMeta):
  242     """Base class for all Crypto plugins.
  243 
  244     Barbican requests operations by invoking the methods on an instance of the
  245     implementing class.  Barbican's plugin manager handles the life-cycle of
  246     the Data Transfer Objects (DTOs) that are passed into these methods, and
  247     persist the data that is assigned to these DTOs by the plugin.
  248     """
  249 
  250     @abc.abstractmethod
  251     def get_plugin_name(self):
  252         """Gets user friendly plugin name.
  253 
  254         This plugin name is expected to be read from config file.
  255         There will be a default defined for plugin name which can be customized
  256         in specific deployment if needed.
  257 
  258         This name needs to be unique across a deployment.
  259         """
  260         raise NotImplementedError  # pragma: no cover
  261 
  262     @abc.abstractmethod
  263     def encrypt(self, encrypt_dto, kek_meta_dto, project_id):
  264         """Encryption handler function
  265 
  266         This method will be called by Barbican when requesting an encryption
  267         operation on a secret on behalf of a project.
  268 
  269         :param encrypt_dto: :class:`EncryptDTO` instance containing the raw
  270             secret byte data to be encrypted.
  271         :type encrypt_dto: :class:`EncryptDTO`
  272         :param kek_meta_dto: :class:`KEKMetaDTO` instance containing
  273             information about the project's Key Encryption Key (KEK) to be
  274             used for encryption.  Plugins may assume that binding via
  275             :meth:`bind_kek_metadata` has already taken place before this
  276             instance is passed in.
  277         :type kek_meta_dto: :class:`KEKMetaDTO`
  278         :param project_id: Project ID associated with the unencrypted data.
  279         :return: A response DTO containing the cyphertext and KEK information.
  280         :rtype: :class:`ResponseDTO`
  281         """
  282         raise NotImplementedError  # pragma: no cover
  283 
  284     @abc.abstractmethod
  285     def decrypt(self, decrypt_dto, kek_meta_dto, kek_meta_extended,
  286                 project_id):
  287         """Decrypt encrypted_datum in the context of the provided project.
  288 
  289         :param decrypt_dto: data transfer object containing the cyphertext
  290                to be decrypted.
  291         :param kek_meta_dto: Key encryption key metadata to use for decryption
  292         :param kek_meta_extended: Optional per-secret KEK metadata to use for
  293             decryption.
  294         :param project_id: Project ID associated with the encrypted datum.
  295         :returns: str -- unencrypted byte data
  296 
  297         """
  298         raise NotImplementedError  # pragma: no cover
  299 
  300     @abc.abstractmethod
  301     def bind_kek_metadata(self, kek_meta_dto):
  302         """Key Encryption Key Metadata binding function
  303 
  304         Bind a key encryption key (KEK) metadata to the sub-system
  305         handling encryption/decryption, updating information about the
  306         key encryption key (KEK) metadata in the supplied 'kek_metadata'
  307         data-transfer-object instance, and then returning this instance.
  308 
  309         This method is invoked prior to the encrypt() method above.
  310         Implementors should fill out the supplied 'kek_meta_dto' instance
  311         (an instance of KEKMetadata above) as needed to completely describe
  312         the kek metadata and to complete the binding process. Barbican will
  313         persist the contents of this instance once this method returns.
  314 
  315         :param kek_meta_dto: Key encryption key metadata to bind, with the
  316                'kek_label' attribute guaranteed to be unique, and the
  317                and 'plugin_name' attribute already configured.
  318         :returns: kek_meta_dto: Returns the specified DTO, after
  319                   modifications.
  320         """
  321         raise NotImplementedError  # pragma: no cover
  322 
  323     @abc.abstractmethod
  324     def generate_symmetric(self, generate_dto, kek_meta_dto, project_id):
  325         """Generate a new key.
  326 
  327         :param generate_dto: data transfer object for the record
  328                associated with this generation request.  Some relevant
  329                parameters can be extracted from this object, including
  330                bit_length, algorithm and mode
  331         :param kek_meta_dto: Key encryption key metadata to use for decryption
  332         :param project_id: Project ID associated with the data.
  333         :returns: An object of type ResponseDTO containing encrypted data and
  334             kek_meta_extended, the former the resultant cypher text, the latter
  335             being optional per-secret metadata needed to decrypt (over and
  336             above the per-project metadata managed outside of the plugins)
  337         """
  338         raise NotImplementedError  # pragma: no cover
  339 
  340     @abc.abstractmethod
  341     def generate_asymmetric(self, generate_dto, kek_meta_dto, project_id):
  342         """Create a new asymmetric key.
  343 
  344         :param generate_dto: data transfer object for the record
  345                associated with this generation request.  Some relevant
  346                parameters can be extracted from this object, including
  347                bit_length, algorithm and passphrase
  348         :param kek_meta_dto: Key encryption key metadata to use for decryption
  349         :param project_id: Project ID associated with the data.
  350         :returns: A tuple containing  objects for private_key, public_key and
  351             optionally one for passphrase. The objects will be of type
  352             ResponseDTO.
  353             Each object containing encrypted data and kek_meta_extended, the
  354             former the resultant cypher text, the latter being optional
  355             per-secret metadata needed to decrypt (over and above the
  356             per-project metadata managed outside of the plugins)
  357         """
  358         raise NotImplementedError  # pragma: no cover
  359 
  360     @abc.abstractmethod
  361     def supports(self, type_enum, algorithm=None, bit_length=None, mode=None):
  362         """Used to determine if the plugin supports the requested operation.
  363 
  364         :param type_enum: Enumeration from PluginSupportsType class
  365         :param algorithm: String algorithm name if needed
  366         """
  367         raise NotImplementedError  # pragma: no cover