Example #1
0
    def generate(cls):
        from cryptography.hazmat.backends.openssl.backend import backend
        if not backend.ed25519_supported():
            raise UnsupportedAlgorithm(
                "ed25519 is not supported by this version of OpenSSL.",
                _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)

        return backend.ed25519_generate_key()
Example #2
0
    def from_private_bytes(cls, data):
        from cryptography.hazmat.backends.openssl.backend import backend
        if not backend.ed25519_supported():
            raise UnsupportedAlgorithm(
                "ed25519 is not supported by this version of OpenSSL.",
                _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)

        return backend.ed25519_load_private_bytes(data)
Example #3
0
    def from_private_bytes(cls, data):
        from cryptography.hazmat.backends.openssl.backend import backend
        if not backend.ed25519_supported():
            raise UnsupportedAlgorithm(
                "ed25519 is not supported by this version of OpenSSL.",
                _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
            )

        return backend.ed25519_load_private_bytes(data)
Example #4
0
    def generate(cls):
        from cryptography.hazmat.backends.openssl.backend import backend
        if not backend.ed25519_supported():
            raise UnsupportedAlgorithm(
                "ed25519 is not supported by this version of OpenSSL.",
                _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
            )

        return backend.ed25519_generate_key()
Example #5
0
def _is_crypto_ed25519_supported():
    """
  Checks if ed25519 is supported by current versions of the cryptography
  package and OpenSSL. This is used for verifying ed25519 certificates in relay
  descriptor signatures.

  :returns: **True** if ed25519 is supported and **False** otherwise
  """

    if not is_crypto_available():
        return False

    from stem.util import log
    from cryptography.hazmat.backends.openssl.backend import backend

    if hasattr(backend, 'ed25519_supported') and backend.ed25519_supported():
        return True
    else:
        log.log_once('stem.prereq._is_crypto_ed25519_supported', log.INFO,
                     ED25519_UNSUPPORTED)
        return False
Example #6
0
def is_crypto_available(ed25519 = False):
  """
  Checks if the cryptography functions we use are available. This is used for
  verifying relay descriptor signatures.

  :param bool ed25519: check for `ed25519 support
    <https://cryptography.io/en/latest/hazmat/primitives/asymmetric/ed25519/>`_,
    which requires both cryptography version 2.6 and OpenSSL support

  :returns: **True** if we can use the cryptography module and **False**
    otherwise
  """

  from stem.util import log

  try:
    from cryptography.utils import int_from_bytes, int_to_bytes
    from cryptography.hazmat.backends import default_backend
    from cryptography.hazmat.backends.openssl.backend import backend
    from cryptography.hazmat.primitives.asymmetric import rsa
    from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
    from cryptography.hazmat.primitives.serialization import load_der_public_key

    if not hasattr(rsa.RSAPrivateKey, 'sign'):
      raise ImportError()

    if ed25519:
      # The following import confirms cryptography support (ie. version 2.6+),
      # whereas ed25519_supported() checks for OpenSSL bindings.

      from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey

      if not hasattr(backend, 'ed25519_supported') or not backend.ed25519_supported():
        log.log_once('stem.prereq._is_crypto_ed25519_supported', log.INFO, ED25519_UNSUPPORTED)
        return False

    return True
  except ImportError:
    log.log_once('stem.prereq.is_crypto_available', log.INFO, CRYPTO_UNAVAILABLE)
    return False
Example #7
0
class TestOCSPEdDSA(object):
    @pytest.mark.supported(
        only_if=lambda backend: backend.ed25519_supported(),
        skip_message="Requires OpenSSL with Ed25519 support / OCSP",
    )
    def test_invalid_algorithm(self, backend):
        builder = ocsp.OCSPResponseBuilder()
        cert, issuer = _cert_and_issuer()
        private_key = ed25519.Ed25519PrivateKey.generate()
        root_cert, _ = _generate_root(private_key, None)
        current_time = datetime.datetime.utcnow().replace(microsecond=0)
        this_update = current_time - datetime.timedelta(days=1)
        next_update = this_update + datetime.timedelta(days=7)
        revoked_date = this_update - datetime.timedelta(days=300)
        builder = builder.responder_id(ocsp.OCSPResponderEncoding.NAME,
                                       root_cert).add_response(
                                           cert,
                                           issuer,
                                           hashes.SHA1(),
                                           ocsp.OCSPCertStatus.REVOKED,
                                           this_update,
                                           next_update,
                                           revoked_date,
                                           x509.ReasonFlags.key_compromise,
                                       )
        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.SHA256())

    @pytest.mark.supported(
        only_if=lambda backend: backend.ed25519_supported(),
        skip_message="Requires OpenSSL with Ed25519 support / OCSP",
    )
    def test_sign_ed25519(self, backend):
        builder = ocsp.OCSPResponseBuilder()
        cert, issuer = _cert_and_issuer()
        private_key = ed25519.Ed25519PrivateKey.generate()
        root_cert, _ = _generate_root(private_key, None)
        current_time = datetime.datetime.utcnow().replace(microsecond=0)
        this_update = current_time - datetime.timedelta(days=1)
        next_update = this_update + datetime.timedelta(days=7)
        revoked_date = this_update - datetime.timedelta(days=300)
        builder = builder.responder_id(ocsp.OCSPResponderEncoding.NAME,
                                       root_cert).add_response(
                                           cert,
                                           issuer,
                                           hashes.SHA1(),
                                           ocsp.OCSPCertStatus.REVOKED,
                                           this_update,
                                           next_update,
                                           revoked_date,
                                           x509.ReasonFlags.key_compromise,
                                       )
        resp = builder.sign(private_key, None)
        assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED
        assert resp.revocation_time == revoked_date
        assert resp.revocation_reason is x509.ReasonFlags.key_compromise
        assert resp.this_update == this_update
        assert resp.next_update == next_update
        assert resp.signature_hash_algorithm is None
        assert (
            resp.signature_algorithm_oid == x509.SignatureAlgorithmOID.ED25519)
        private_key.public_key().verify(resp.signature,
                                        resp.tbs_response_bytes)

    @pytest.mark.supported(
        only_if=lambda backend: backend.ed448_supported(),
        skip_message="Requires OpenSSL with Ed448 support / OCSP",
    )
    def test_sign_ed448(self, backend):
        builder = ocsp.OCSPResponseBuilder()
        cert, issuer = _cert_and_issuer()
        private_key = ed448.Ed448PrivateKey.generate()
        root_cert, _ = _generate_root(private_key, None)
        current_time = datetime.datetime.utcnow().replace(microsecond=0)
        this_update = current_time - datetime.timedelta(days=1)
        next_update = this_update + datetime.timedelta(days=7)
        revoked_date = this_update - datetime.timedelta(days=300)
        builder = builder.responder_id(ocsp.OCSPResponderEncoding.NAME,
                                       root_cert).add_response(
                                           cert,
                                           issuer,
                                           hashes.SHA1(),
                                           ocsp.OCSPCertStatus.REVOKED,
                                           this_update,
                                           next_update,
                                           revoked_date,
                                           x509.ReasonFlags.key_compromise,
                                       )
        resp = builder.sign(private_key, None)
        assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED
        assert resp.revocation_time == revoked_date
        assert resp.revocation_reason is x509.ReasonFlags.key_compromise
        assert resp.this_update == this_update
        assert resp.next_update == next_update
        assert resp.signature_hash_algorithm is None
        assert resp.signature_algorithm_oid == x509.SignatureAlgorithmOID.ED448
        private_key.public_key().verify(resp.signature,
                                        resp.tbs_response_bytes)
Example #8
0
import stem.util.system
import stem.version
import test
import test.runner

try:
    from cryptography.utils import int_from_bytes, int_to_bytes
    from cryptography.hazmat.backends import default_backend
    from cryptography.hazmat.backends.openssl.backend import backend
    from cryptography.hazmat.primitives.asymmetric import rsa
    from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
    from cryptography.hazmat.primitives.serialization import load_der_public_key
    from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey

    if not hasattr(rsa.RSAPrivateKey, 'sign') or not hasattr(
            backend, 'ed25519_supported') or not backend.ed25519_supported():
        raise ImportError()

    CRYPTOGRAPHY_AVAILABLE = True
except ImportError:
    CRYPTOGRAPHY_AVAILABLE = False

RAN_TESTS = []


def only_run_once(func):
    """
  Skips the test if it has ran before. If it hasn't then flags it as being ran.
  This is useful to prevent lengthy tests that are independent of integ targets
  from being run repeatedly with ``RUN_ALL``.
  """