Esempio n. 1
0
def verify_signature(public_key, scheme, signature, data):
  """
  <Purpose>
    Determine whether the private key corresponding to 'public_key' produced
    'signature'.  verify_signature() will use the public key, the 'scheme' and
    'sig', and 'data' arguments to complete the verification.

    >>> public, private = generate_public_and_private()
    >>> data = b'The quick brown fox jumps over the lazy dog'
    >>> scheme = 'ed25519'
    >>> signature, scheme = \
        create_signature(public, private, data, scheme)
    >>> verify_signature(public, scheme, signature, data)
    True
    >>> bad_data = b'The sly brown fox jumps over the lazy dog'
    >>> bad_signature, scheme = \
        create_signature(public, private, bad_data, scheme)
    >>> verify_signature(public, scheme, bad_signature, data)
    False

  <Arguments>
    public_key:
      The public key is a 32-byte string.

    scheme:
      'ed25519' signature scheme used by either the pure python
      implementation (i.e., ed25519.py) or PyNacl (i.e., 'nacl').

    signature:
      The signature is a 64-byte string.

    data:
      Data object used by securesystemslib.ed25519_keys.create_signature() to
      generate 'signature'.  'data' is needed here to verify the signature.

  <Exceptions>
    securesystemslib.exceptions.UnsupportedAlgorithmError.  Raised if the
    signature scheme 'scheme' is not one supported by
    securesystemslib.ed25519_keys.create_signature().

    securesystemslib.exceptions.FormatError. Raised if the arguments are
    improperly formatted.

  <Side Effects>
    nacl.signing.VerifyKey.verify() called if available, otherwise
    securesystemslib._vendor.ed25519.ed25519.checkvalid() called to do the
    verification.

  <Returns>
    Boolean.  True if the signature is valid, False otherwise.
  """

  # Does 'public_key' have the correct format?
  # This check will ensure 'public_key' conforms to
  # 'securesystemslib.formats.ED25519PUBLIC_SCHEMA', which must have length 32
  # bytes.  Raise 'securesystemslib.exceptions.FormatError' if the check fails.
  formats.ED25519PUBLIC_SCHEMA.check_match(public_key)

  # Is 'scheme' properly formatted?
  formats.ED25519_SIG_SCHEMA.check_match(scheme)

  # Is 'signature' properly formatted?
  formats.ED25519SIGNATURE_SCHEMA.check_match(signature)

  # Verify 'signature'.  Before returning the Boolean result, ensure 'ed25519'
  # was used as the signature scheme.
  public = public_key
  valid_signature = False

  if scheme in _SUPPORTED_ED25519_SIGNING_SCHEMES:
    if NACL:
      try:
        nacl_verify_key = VerifyKey(public)
        nacl_verify_key.verify(data, signature)
        valid_signature = True

      except nacl_exceptions.BadSignatureError:
        pass

    # Verify 'ed25519' signature with the pure Python implementation.
    else:
      try:
        python_ed25519.checkvalid(signature, data, public)
        valid_signature = True

      # The pure Python implementation raises 'Exception' if 'signature' is
      # invalid.
      except Exception:
        pass

  # This is a defensive check for a valid 'scheme', which should have already
  # been validated in the ED25519_SIG_SCHEMA.check_match(scheme) above.
  else: #pragma: no cover
    message = 'Unsupported ed25519 signature scheme: ' + repr(scheme) + '.\n' + \
      'Supported schemes: ' + repr(_SUPPORTED_ED25519_SIGNING_SCHEMES) + '.'
    raise exceptions.UnsupportedAlgorithmError(message)

  return valid_signature
Esempio n. 2
0
def digest(algorithm=DEFAULT_HASH_ALGORITHM,
           hash_library=DEFAULT_HASH_LIBRARY):
    """
  <Purpose>
    Provide the caller with the ability to create digest objects without having
    to worry about crypto library availability or which library to use.  The
    caller also has the option of specifying which hash algorithm and/or
    library to use.

    # Creation of a digest object using defaults or by specifying hash
    # algorithm and library.
    digest_object = securesystemslib.hash.digest()
    digest_object = securesystemslib.hash.digest('sha384')
    digest_object = securesystemslib.hash.digest('sha256', 'hashlib')

    # The expected interface for digest objects.
    digest_object.digest_size
    digest_object.hexdigest()
    digest_object.update('data')
    digest_object.digest()

    # Added hash routines by this module.
    digest_object = securesystemslib.hash.digest_fileobject(file_object)
    digest_object = securesystemslib.hash.digest_filename(filename)

  <Arguments>
    algorithm:
      The hash algorithm (e.g., 'md5', 'sha1', 'sha256').

    hash_library:
      The crypto library to use for the given hash algorithm (e.g., 'hashlib').

  <Exceptions>
    securesystemslib.exceptions.FormatError, if the arguments are
    improperly formatted.

    securesystemslib.exceptions.UnsupportedAlgorithmError, if an unsupported
    hashing algorithm is specified, or digest could not be generated with given
    the algorithm.

    securesystemslib.exceptions.UnsupportedLibraryError, if an unsupported
    library was requested via 'hash_library'.

  <Side Effects>
    None.

  <Returns>
    Digest object

    e.g.
      hashlib.new(algorithm) or
      PycaDiggestWrapper object
  """

    # Are the arguments properly formatted?  If not, raise
    # 'securesystemslib.exceptions.FormatError'.
    formats.NAME_SCHEMA.check_match(algorithm)
    formats.NAME_SCHEMA.check_match(hash_library)

    # Was a hashlib digest object requested and is it supported?
    # If so, return the digest object.
    if hash_library == 'hashlib' and hash_library in SUPPORTED_LIBRARIES:
        try:
            if algorithm == 'blake2b-256':
                return hashlib.new('blake2b', digest_size=32)
            else:
                return hashlib.new(algorithm)

        except (ValueError, TypeError):
            # ValueError: the algorithm value was unknown
            # TypeError: unexpected argument digest_size (on old python)
            raise exceptions.UnsupportedAlgorithmError(algorithm)

    # Was a pyca_crypto digest object requested and is it supported?
    elif hash_library == 'pyca_crypto' and hash_library in SUPPORTED_LIBRARIES:
        try:
            hash_algorithm = PYCA_DIGEST_OBJECTS_CACHE[algorithm]()
            return PycaDiggestWrapper(
                _pyca_hashes.Hash(hash_algorithm, default_backend()))

        except KeyError:
            raise exceptions.UnsupportedAlgorithmError(algorithm)

    # The requested hash library is not supported.
    else:
        raise exceptions.UnsupportedLibraryError(
            'Unsupported'
            ' library requested.  Supported hash'
            ' libraries: ' + repr(SUPPORTED_LIBRARIES))
Esempio n. 3
0
def create_signature(public_key, private_key, data, scheme):
  """
  <Purpose>
    Return a (signature, scheme) tuple, where the signature scheme is 'ed25519'
    and is always generated by PyNaCl (i.e., 'nacl').  The signature returned
    conforms to 'securesystemslib.formats.ED25519SIGNATURE_SCHEMA', and has the
    form:

    '\xae\xd7\x9f\xaf\x95{bP\x9e\xa8YO Z\x86\x9d...'

    A signature is a 64-byte string.

    >>> public, private = generate_public_and_private()
    >>> data = b'The quick brown fox jumps over the lazy dog'
    >>> scheme = 'ed25519'
    >>> signature, scheme = \
        create_signature(public, private, data, scheme)
    >>> securesystemslib.formats.ED25519SIGNATURE_SCHEMA.matches(signature)
    True
    >>> scheme == 'ed25519'
    True
    >>> signature, scheme = \
        create_signature(public, private, data, scheme)
    >>> securesystemslib.formats.ED25519SIGNATURE_SCHEMA.matches(signature)
    True
    >>> scheme == 'ed25519'
    True

  <Arguments>
    public:
      The ed25519 public key, which is a 32-byte string.

    private:
      The ed25519 private key, which is a 32-byte string.

    data:
      Data object used by create_signature() to generate the signature.

    scheme:
      The signature scheme used to generate the signature.

  <Exceptions>
    securesystemslib.exceptions.FormatError, if the arguments are improperly
    formatted.

    securesystemslib.exceptions.CryptoError, if a signature cannot be created.

    securesystemslib.exceptions.UnsupportedLibraryError, if the PyNaCl ('nacl')
    module is unavailable.

  <Side Effects>
    nacl.signing.SigningKey.sign() called to generate the actual signature.

  <Returns>
    A signature dictionary conformat to
    'securesystemslib.format.SIGNATURE_SCHEMA'.  ed25519 signatures are 64
    bytes, however, the hexlified signature is stored in the dictionary
    returned.
  """

  if not NACL: # pragma: no cover
    raise exceptions.UnsupportedLibraryError(NO_NACL_MSG)

  # Does 'public_key' have the correct format?
  # This check will ensure 'public_key' conforms to
  # 'securesystemslib.formats.ED25519PUBLIC_SCHEMA', which must have length 32
  # bytes.  Raise 'securesystemslib.exceptions.FormatError' if the check fails.
  formats.ED25519PUBLIC_SCHEMA.check_match(public_key)

  # Is 'private_key' properly formatted?
  formats.ED25519SEED_SCHEMA.check_match(private_key)

  # Is 'scheme' properly formatted?
  formats.ED25519_SIG_SCHEMA.check_match(scheme)

  # Signing the 'data' object requires a seed and public key.
  # nacl.signing.SigningKey.sign() generates the signature.
  signature = None

  # An if-clause is not strictly needed here, since 'ed25519' is the only
  # currently supported scheme.  Nevertheless, include the conditional
  # statement to accommodate schemes that might be added in the future.
  if scheme == 'ed25519':
    try:
      nacl_key = SigningKey(private_key)
      nacl_sig = nacl_key.sign(data)
      signature = nacl_sig.signature

    except (ValueError, TypeError, nacl_exceptions.CryptoError) as e:
      raise exceptions.CryptoError('An "ed25519" signature'
          ' could not be created with PyNaCl.' + str(e))

  # This is a defensive check for a valid 'scheme', which should have already
  # been validated in the check_match() above.
  else: #pragma: no cover
    raise exceptions.UnsupportedAlgorithmError('Unsupported'
      ' signature scheme is specified: ' + repr(scheme))

  return signature, scheme
Esempio n. 4
0
def generate_public_and_private(scheme='ecdsa-sha2-nistp256'):
    """
  <Purpose>
    Generate a pair of ECDSA public and private keys with one of the supported,
    external cryptography libraries.  The public and private keys returned
    conform to 'securesystemslib.formats.PEMECDSA_SCHEMA' and
    'securesystemslib.formats.PEMECDSA_SCHEMA', respectively.

    The public ECDSA public key has the PEM format:
    TODO: should we encrypt the private keys returned here?  Should the
    create_signature() accept encrypted keys?

    '-----BEGIN PUBLIC KEY-----

    ...

    '-----END PUBLIC KEY-----'



    The private ECDSA private key has the PEM format:

    '-----BEGIN EC PRIVATE KEY-----

    ...

    -----END EC PRIVATE KEY-----'

    >>> public, private = generate_public_and_private()
    >>> securesystemslib.formats.PEMECDSA_SCHEMA.matches(public)
    True
    >>> securesystemslib.formats.PEMECDSA_SCHEMA.matches(private)
    True

  <Arguments>
    scheme:
      A string indicating which algorithm to use for the generation of the
      public and private ECDSA keys.  'ecdsa-sha2-nistp256' is the only
      currently supported ECDSA algorithm, which is supported by OpenSSH and
      specified in RFC 5656 (https://tools.ietf.org/html/rfc5656).

  <Exceptions>
    securesystemslib.exceptions.FormatError, if 'algorithm' is improperly
    formatted.

    securesystemslib.exceptions.UnsupportedAlgorithmError, if 'scheme' is an
    unsupported algorithm.

    securesystemslib.exceptions.UnsupportedLibraryError, if the cryptography
    module is not available.

  <Side Effects>
    None.

  <Returns>
    A (public, private) tuple that conform to
    'securesystemslib.formats.PEMECDSA_SCHEMA' and
    'securesystemslib.formats.PEMECDSA_SCHEMA', respectively.
  """

    if not CRYPTO:  # pragma: no cover
        raise exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

    # Does 'scheme' have the correct format?
    # Verify that 'scheme' is of the correct type, and that it's one of the
    # supported ECDSA .  It must conform to
    # 'securesystemslib.formats.ECDSA_SCHEME_SCHEMA'.  Raise
    # 'securesystemslib.exceptions.FormatError' if the check fails.
    formats.ECDSA_SCHEME_SCHEMA.check_match(scheme)

    public_key = None
    private_key = None

    # An if-clause is strictly not needed, since 'ecdsa_sha2-nistp256' is the
    # only currently supported ECDSA signature scheme.  Nevertheness, include the
    # conditional statement to accomodate any schemes that might be added.
    if scheme == 'ecdsa-sha2-nistp256':
        private_key = ec.generate_private_key(ec.SECP256R1, default_backend())
        public_key = private_key.public_key()

    # The ECDSA_SCHEME_SCHEMA.check_match() above should have detected any
    # invalid 'scheme'.  This is a defensive check.
    else:  #pragma: no cover
        raise exceptions.UnsupportedAlgorithmError(
            'An unsupported'
            ' scheme specified: ' + repr(scheme) + '.\n  Supported'
            ' algorithms: ' + repr(_SUPPORTED_ECDSA_SCHEMES))

    private_pem = private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.TraditionalOpenSSL,
        encryption_algorithm=serialization.NoEncryption())

    public_pem = public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo)

    return public_pem.decode('utf-8'), private_pem.decode('utf-8')
Esempio n. 5
0
def create_signature(public_key,
                     private_key,
                     data,
                     scheme='ecdsa-sha2-nistp256'):
    """
  <Purpose>
    Return a (signature, scheme) tuple.

    >>> requested_scheme = 'ecdsa-sha2-nistp256'
    >>> public, private = generate_public_and_private(requested_scheme)
    >>> data = b'The quick brown fox jumps over the lazy dog'
    >>> signature, scheme = create_signature(public, private, data, requested_scheme)
    >>> securesystemslib.formats.ECDSASIGNATURE_SCHEMA.matches(signature)
    True
    >>> requested_scheme == scheme
    True

  <Arguments>
    public:
      The ECDSA public key in PEM format.

    private:
      The ECDSA private key in PEM format.

    data:
      Byte data used by create_signature() to generate the signature returned.

    scheme:
      The signature scheme used to generate the signature.  For example:
      'ecdsa-sha2-nistp256'.

  <Exceptions>
    securesystemslib.exceptions.FormatError, if the arguments are improperly
    formatted.

    securesystemslib.exceptions.CryptoError, if a signature cannot be created.

    securesystemslib.exceptions.UnsupportedAlgorithmError, if 'scheme' is not
    one of the supported signature schemes.

    securesystemslib.exceptions.UnsupportedLibraryError, if the cryptography
    module is not available.

  <Side Effects>
    None.

  <Returns>
    A signature dictionary conformat to
    'securesystemslib.format.SIGNATURE_SCHEMA'.  ECDSA signatures are XX bytes,
    however, the hexlified signature is stored in the dictionary returned.
  """

    if not CRYPTO:  # pragma: no cover
        raise exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

    # Do 'public_key' and 'private_key' have the correct format?
    # This check will ensure that the arguments conform to
    # 'securesystemslib.formats.PEMECDSA_SCHEMA'.  Raise
    # 'securesystemslib.exceptions.FormatError' if the check fails.
    formats.PEMECDSA_SCHEMA.check_match(public_key)

    # Is 'private_key' properly formatted?
    formats.PEMECDSA_SCHEMA.check_match(private_key)

    # Is 'scheme' properly formatted?
    formats.ECDSA_SCHEME_SCHEMA.check_match(scheme)

    # 'ecdsa-sha2-nistp256' is the only currently supported ECDSA scheme, so this
    # if-clause isn't strictly needed.  Nevertheless, the conditional statement
    # is included to accommodate multiple schemes that can potentially be added
    # in the future.
    if scheme == 'ecdsa-sha2-nistp256':
        try:
            private_key = load_pem_private_key(private_key.encode('utf-8'),
                                               password=None,
                                               backend=default_backend())

            signature = private_key.sign(data, ec.ECDSA(hashes.SHA256()))

        except TypeError as e:
            raise exceptions.CryptoError('Could not create'
                                         ' signature: ' + str(e))

    # A defensive check for an invalid 'scheme'.  The
    # ECDSA_SCHEME_SCHEMA.check_match() above should have already validated it.
    else:  #pragma: no cover
        raise exceptions.UnsupportedAlgorithmError(
            'Unsupported'
            ' signature scheme is specified: ' + repr(scheme))

    return signature, scheme
Esempio n. 6
0
def verify_rsa_signature(signature, signature_scheme, public_key, data):
    """
  <Purpose>
    Determine whether the corresponding private key of 'public_key' produced
    'signature'.  verify_signature() will use the public key, signature scheme,
    and 'data' to complete the verification.

    >>> public, private = generate_rsa_public_and_private(2048)
    >>> data = b'The quick brown fox jumps over the lazy dog'
    >>> scheme = 'rsassa-pss-sha256'
    >>> signature, scheme = create_rsa_signature(private, data, scheme)
    >>> verify_rsa_signature(signature, scheme, public, data)
    True
    >>> verify_rsa_signature(signature, scheme, public, b'bad_data')
    False

  <Arguments>
    signature:
      A signature, as a string.  This is the signature returned
      by create_rsa_signature().

    signature_scheme:
      A string that indicates the signature scheme used to generate
      'signature'.  Currently supported RSA signature schemes are defined in
      `securesystemslib.keys.RSA_SIGNATURE_SCHEMES`.

    public_key:
      The RSA public key, a string in PEM format.

    data:
      Data used by securesystemslib.keys.create_signature() to generate
      'signature'.  'data' (a string) is needed here to verify 'signature'.

  <Exceptions>
    securesystemslib.exceptions.FormatError, if 'signature',
    'signature_scheme', 'public_key', or 'data' are improperly formatted.

    securesystemslib.exceptions.UnsupportedAlgorithmError, if the signature
    scheme used by 'signature' is not one supported by
    securesystemslib.keys.create_signature().

    securesystemslib.exceptions.CryptoError, if the private key cannot be
    decoded or its key type is unsupported.

    securesystemslib.exceptions.UnsupportedLibraryError, if the cryptography
    module is not available.

  <Side Effects>
    pyca/cryptography's RSAPublicKey.verifier() called to do the actual
    verification.

   <Returns>
    Boolean.  True if the signature is valid, False otherwise.
  """

    if not CRYPTO:  # pragma: no cover
        raise exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

    # Does 'public_key' have the correct format?
    # This check will ensure 'public_key' conforms to
    # 'securesystemslib.formats.PEMRSA_SCHEMA'.  Raise
    # 'securesystemslib.exceptions.FormatError' if the check fails.
    formats.PEMRSA_SCHEMA.check_match(public_key)

    # Does 'signature_scheme' have the correct format?
    formats.RSA_SCHEME_SCHEMA.check_match(signature_scheme)

    # Does 'signature' have the correct format?
    formats.PYCACRYPTOSIGNATURE_SCHEMA.check_match(signature)

    # What about 'data'?
    formats.DATA_SCHEMA.check_match(data)

    # Verify the RSASSA-PSS signature with pyca/cryptography.
    try:
        public_key_object = serialization.load_pem_public_key(
            public_key.encode('utf-8'), backend=default_backend())

        digest_obj = digest_from_rsa_scheme(signature_scheme, 'pyca_crypto')

        # verify() raises 'cryptography.exceptions.InvalidSignature' if the
        # signature is invalid. 'salt_length' is set to the digest size of the
        # hashing algorithm.
        try:
            if signature_scheme.startswith('rsassa-pss'):
                public_key_object.verify(
                    signature, data,
                    padding.PSS(mgf=padding.MGF1(digest_obj.algorithm),
                                salt_length=digest_obj.algorithm.digest_size),
                    digest_obj.algorithm)

            elif signature_scheme.startswith('rsa-pkcs1v15'):
                public_key_object.verify(signature, data, padding.PKCS1v15(),
                                         digest_obj.algorithm)

            # The RSA_SCHEME_SCHEMA.check_match() above should have validated 'scheme'.
            # This is a defensive check check..
            else:  # pragma: no cover
                raise exceptions.UnsupportedAlgorithmError(
                    'Unsupported'
                    ' signature scheme is specified: ' +
                    repr(signature_scheme))

            return True

        except InvalidSignature:
            return False

    # Raised by load_pem_public_key().
    except (ValueError, UnsupportedAlgorithm) as e:
        raise exceptions.CryptoError(
            'The PEM could not be'
            ' decoded successfully, or contained an unsupported key type: ' +
            str(e))
Esempio n. 7
0
def create_rsa_signature(private_key, data, scheme='rsassa-pss-sha256'):
    """
  <Purpose>
    Generate a 'scheme' signature.  The signature, and the signature scheme
    used, is returned as a (signature, scheme) tuple.

    The signing process will use 'private_key' to generate the signature of
    'data'.

    RFC3447 - RSASSA-PSS
    http://www.ietf.org/rfc/rfc3447.txt

    >>> public, private = generate_rsa_public_and_private(2048)
    >>> data = 'The quick brown fox jumps over the lazy dog'.encode('utf-8')
    >>> scheme = 'rsassa-pss-sha256'
    >>> signature, scheme = create_rsa_signature(private, data, scheme)
    >>> securesystemslib.formats.NAME_SCHEMA.matches(scheme)
    True
    >>> scheme == 'rsassa-pss-sha256'
    True
    >>> securesystemslib.formats.PYCACRYPTOSIGNATURE_SCHEMA.matches(signature)
    True

  <Arguments>
    private_key:
      The private RSA key, a string in PEM format.

    data:
      Data (string) used by create_rsa_signature() to generate the signature.

    scheme:
      The signature scheme used to generate the signature.

  <Exceptions>
    securesystemslib.exceptions.FormatError, if 'private_key' is improperly
    formatted.

    ValueError, if 'private_key' is unset.

    securesystemslib.exceptions.CryptoError, if the signature cannot be
    generated.

    securesystemslib.exceptions.UnsupportedLibraryError, if the cryptography
    module is not available.

  <Side Effects>
    pyca/cryptography's 'RSAPrivateKey.signer()' called to generate the
    signature.

  <Returns>
    A (signature, scheme) tuple, where the signature is a string and the scheme
    is one of the supported RSA signature schemes. For example:
    'rsassa-pss-sha256'.
  """

    if not CRYPTO:  # pragma: no cover
        raise exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

    # Does the arguments have the correct format?
    # If not, raise 'securesystemslib.exceptions.FormatError' if any of the
    # checks fail.
    formats.PEMRSA_SCHEMA.check_match(private_key)
    formats.DATA_SCHEMA.check_match(data)
    formats.RSA_SCHEME_SCHEMA.check_match(scheme)

    # Signing 'data' requires a private key. Currently supported RSA signature
    # schemes are defined in `securesystemslib.keys.RSA_SIGNATURE_SCHEMES`.
    signature = None

    # Verify the signature, but only if the private key has been set.  The
    # private key is a NULL string if unset.  Although it may be clearer to
    # explicitly check that 'private_key' is not '', we can/should check for a
    # value and not compare identities with the 'is' keyword.  Up to this point
    # 'private_key' has variable size and can be an empty string.
    if not len(private_key):
        raise ValueError('The required private key is unset.')

    try:
        # 'private_key' (in PEM format) must first be converted to a
        # pyca/cryptography private key object before a signature can be
        # generated.
        private_key_object = load_pem_private_key(private_key.encode('utf-8'),
                                                  password=None,
                                                  backend=default_backend())

        digest_obj = digest_from_rsa_scheme(scheme, 'pyca_crypto')

        if scheme.startswith('rsassa-pss'):
            # Generate an RSSA-PSS signature.  Raise
            # 'securesystemslib.exceptions.CryptoError' for any of the expected
            # exceptions raised by pyca/cryptography.
            signature = private_key_object.sign(
                data,
                padding.PSS(mgf=padding.MGF1(digest_obj.algorithm),
                            salt_length=digest_obj.algorithm.digest_size),
                digest_obj.algorithm)

        elif scheme.startswith('rsa-pkcs1v15'):
            # Generate an RSA-PKCS1v15 signature.  Raise
            # 'securesystemslib.exceptions.CryptoError' for any of the expected
            # exceptions raised by pyca/cryptography.
            signature = private_key_object.sign(data, padding.PKCS1v15(),
                                                digest_obj.algorithm)

        # The RSA_SCHEME_SCHEMA.check_match() above should have validated 'scheme'.
        # This is a defensive check check..
        else:  # pragma: no cover
            raise exceptions.UnsupportedAlgorithmError(
                'Unsupported'
                ' signature scheme is specified: ' + repr(scheme))

    # If the PEM data could not be decrypted, or if its structure could not
    # be decoded successfully.
    except ValueError:
        raise exceptions.CryptoError(
            'The private key'
            ' (in PEM format) could not be deserialized.')

    # 'TypeError' is raised if a password was given and the private key was
    # not encrypted, or if the key was encrypted but no password was
    # supplied.  Note: A passphrase or password is not used when generating
    # 'private_key', since it should not be encrypted.
    except TypeError:
        raise exceptions.CryptoError('The private key was'
                                     ' unexpectedly encrypted.')

    # 'cryptography.exceptions.UnsupportedAlgorithm' is raised if the
    # serialized key is of a type that is not supported by the backend, or if
    # the key is encrypted with a symmetric cipher that is not supported by
    # the backend.
    except UnsupportedAlgorithm:  # pragma: no cover
        raise exceptions.CryptoError(
            'The private key is'
            ' encrypted with an unsupported algorithm.')

    return signature, scheme