diff options
-rw-r--r-- | CHANGELOG.rst | 2 | ||||
-rw-r--r-- | docs/faq.rst | 19 | ||||
-rw-r--r-- | docs/x509/reference.rst | 38 | ||||
-rw-r--r-- | src/_cffi_src/openssl/hmac.py | 31 | ||||
-rw-r--r-- | src/_cffi_src/openssl/ssl.py | 25 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/multibackend.py | 7 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/hmac.py | 13 | ||||
-rw-r--r-- | src/cryptography/hazmat/bindings/openssl/_conditional.py | 10 | ||||
-rw-r--r-- | src/cryptography/x509/extensions.py | 8 | ||||
-rw-r--r-- | tests/hazmat/backends/test_multibackend.py | 20 | ||||
-rw-r--r-- | tests/test_x509_ext.py | 22 |
11 files changed, 176 insertions, 19 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0bbbcde1..1c11f028 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,8 @@ Changelog to :class:`~cryptography.x509.CertificateSigningRequest`. * Fixed an intermittent ``AssertionError`` when performing an RSA decryption on an invalid ciphertext, ``ValueError`` is now correctly raised in all cases. +* Added + :meth:`~cryptography.x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier`. 1.2.3 - 2016-03-01 ~~~~~~~~~~~~~~~~~~ diff --git a/docs/faq.rst b/docs/faq.rst index 363a350f..3456ba97 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -23,5 +23,24 @@ OpenSSL. You're seeing this error because your copy of pip is too old to find our wheel files. Upgrade your copy of pip with ``pip install -U pip`` and then try install ``cryptography`` again. +Starting ``cryptography`` using ``mod_wsgi`` produces an ``InternalError`` during a call in ``_register_osrandom_engine`` +------------------------------------------------------------------------------------------------------------------------- + +This happens because ``mod_wsgi`` uses sub-interpreters, which can cause a +problem during initialization of the OpenSSL backend. To resolve this set the +`WSGIApplicationGroup`_ to ``%{GLOBAL}`` in the ``mod_wsgi`` configuration. + +``cryptography`` raised an ``InternalError`` and I'm not sure what to do? +------------------------------------------------------------------------- + +Frequently ``InternalError`` is raised when there are errors on the OpenSSL +error stack that were placed there by other libraries that are also using +OpenSSL. Try removing the other libraries and see if the problem persists. +If you have no other libraries using OpenSSL in your process, or they do not +appear to be at fault, it's possible that this is a bug in ``cryptography``. +Please file an `issue`_ with instructions on how to reproduce it. + .. _`NaCl`: https://nacl.cr.yp.to/ .. _`PyNaCl`: https://pynacl.readthedocs.org +.. _`WSGIApplicationGroup`: https://modwsgi.readthedocs.org/en/develop/configuration-directives/WSGIApplicationGroup.html +.. _`issue`: https://github.com/pyca/cryptography/issues diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index 67427ddb..399d693a 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -1541,6 +1541,13 @@ X.509 Extensions .. versionadded:: 1.0 + .. note:: + + This method should be used if the issuer certificate does not + contain a :class:`~cryptography.x509.SubjectKeyIdentifier`. + Otherwise, use + :meth:`~cryptography.x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier`. + Creates a new AuthorityKeyIdentifier instance using the public key provided to generate the appropriate digest. This should be the **issuer's public key**. The resulting object will contain @@ -1568,6 +1575,37 @@ X.509 Extensions >>> x509.AuthorityKeyIdentifier.from_issuer_public_key(issuer_cert.public_key()) <AuthorityKeyIdentifier(key_identifier='X\x01\x84$\x1b\xbc+R\x94J=\xa5\x10r\x14Q\xf5\xaf:\xc9', authority_cert_issuer=None, authority_cert_serial_number=None)> + .. classmethod:: from_issuer_subject_key_identifier(ski) + + .. versionadded:: 1.3 + + .. note:: + This method should be used if the issuer certificate contains a + :class:`~cryptography.x509.SubjectKeyIdentifier`. Otherwise, use + :meth:`~cryptography.x509.AuthorityKeyIdentifier.from_issuer_public_key`. + + Creates a new AuthorityKeyIdentifier instance using the + SubjectKeyIdentifier from the issuer certificate. The resulting object + will contain + :attr:`~cryptography.x509.AuthorityKeyIdentifier.key_identifier`, but + :attr:`~cryptography.x509.AuthorityKeyIdentifier.authority_cert_issuer` + and + :attr:`~cryptography.x509.AuthorityKeyIdentifier.authority_cert_serial_number` + will be None. + + :param ski: The + :class:`~cryptography.x509.SubjectKeyIdentifier` from the issuer + certificate. + + .. doctest:: + + >>> from cryptography import x509 + >>> from cryptography.hazmat.backends import default_backend + >>> issuer_cert = x509.load_pem_x509_certificate(pem_data, default_backend()) + >>> ski = issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier) + >>> x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(ski) + <AuthorityKeyIdentifier(key_identifier='X\x01\x84$\x1b\xbc+R\x94J=\xa5\x10r\x14Q\xf5\xaf:\xc9', authority_cert_issuer=None, authority_cert_serial_number=None)> + .. class:: SubjectKeyIdentifier(digest) .. versionadded:: 0.9 diff --git a/src/_cffi_src/openssl/hmac.py b/src/_cffi_src/openssl/hmac.py index 7178e573..bcc8a861 100644 --- a/src/_cffi_src/openssl/hmac.py +++ b/src/_cffi_src/openssl/hmac.py @@ -9,18 +9,17 @@ INCLUDES = """ """ TYPES = """ -typedef struct { ...; } HMAC_CTX; +typedef ... HMAC_CTX; """ FUNCTIONS = """ -void HMAC_CTX_init(HMAC_CTX *); -void HMAC_CTX_cleanup(HMAC_CTX *); - int Cryptography_HMAC_Init_ex(HMAC_CTX *, const void *, int, const EVP_MD *, ENGINE *); int Cryptography_HMAC_Update(HMAC_CTX *, const unsigned char *, size_t); int Cryptography_HMAC_Final(HMAC_CTX *, unsigned char *, unsigned int *); int Cryptography_HMAC_CTX_copy(HMAC_CTX *, HMAC_CTX *); +HMAC_CTX *Cryptography_HMAC_CTX_new(void); +void Cryptography_HMAC_CTX_free(HMAC_CTX *ctx); """ MACROS = """ @@ -80,4 +79,28 @@ int Cryptography_HMAC_CTX_copy(HMAC_CTX *dst_ctx, HMAC_CTX *src_ctx) { return 0; #endif } + +HMAC_CTX *Cryptography_HMAC_CTX_new(void) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) + return HMAC_CTX_new(); +#else + /* This uses OPENSSL_zalloc in 1.1.0, which is malloc + memset */ + HMAC_CTX *ctx = (HMAC_CTX *)OPENSSL_malloc(sizeof(HMAC_CTX)); + memset(ctx, 0, sizeof(HMAC_CTX)); + return ctx; +#endif +} + + + +void Cryptography_HMAC_CTX_free(HMAC_CTX *ctx) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) + return HMAC_CTX_free(ctx); +#else + if (ctx != NULL) { + HMAC_CTX_cleanup(ctx); + OPENSSL_free(ctx); + } +#endif +} """ diff --git a/src/_cffi_src/openssl/ssl.py b/src/_cffi_src/openssl/ssl.py index e97a1d7d..2fc86a31 100644 --- a/src/_cffi_src/openssl/ssl.py +++ b/src/_cffi_src/openssl/ssl.py @@ -11,9 +11,8 @@ typedef STACK_OF(SSL_CIPHER) Cryptography_STACK_OF_SSL_CIPHER; """ TYPES = """ -/* - * Internally invented symbols to tell which versions of SSL/TLS are supported. -*/ +static const long Cryptography_HAS_SSL_ST; +static const long Cryptography_HAS_TLS_ST; static const long Cryptography_HAS_SSL2; static const long Cryptography_HAS_SSL3_METHOD; static const long Cryptography_HAS_TLSv1_1; @@ -126,6 +125,8 @@ static const long SSL_MODE_ENABLE_PARTIAL_WRITE; static const long SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; static const long SSL_MODE_AUTO_RETRY; static const long SSL3_RANDOM_SIZE; +static const long TLS_ST_BEFORE; +static const long TLS_ST_OK; typedef ... SSL_METHOD; typedef ... SSL_CTX; @@ -657,4 +658,22 @@ static const long Cryptography_HAS_SSL_CTX_SET_CLIENT_CERT_ENGINE = 0; static const long Cryptography_HAS_SSL_CTX_SET_CLIENT_CERT_ENGINE = 1; #endif +/* in OpenSSL 1.1.0 the SSL_ST values were renamed to TLS_ST and several were + removed */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +static const long Cryptography_HAS_SSL_ST = 1; +#else +static const long Cryptography_HAS_SSL_ST = 0; +static const long SSL_ST_BEFORE = 0; +static const long SSL_ST_OK = 0; +static const long SSL_ST_INIT = 0; +static const long SSL_ST_RENEGOTIATE = 0; +#endif +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) +static const long Cryptography_HAS_TLS_ST = 1; +#else +static const long Cryptography_HAS_TLS_ST = 0; +static const long TLS_ST_BEFORE = 0; +static const long TLS_ST_OK = 0; +#endif """ diff --git a/src/cryptography/hazmat/backends/multibackend.py b/src/cryptography/hazmat/backends/multibackend.py index 65f18531..48bc7d08 100644 --- a/src/cryptography/hazmat/backends/multibackend.py +++ b/src/cryptography/hazmat/backends/multibackend.py @@ -28,6 +28,13 @@ class MultiBackend(object): name = "multibackend" def __init__(self, backends): + if len(backends) == 0: + raise ValueError( + "Multibackend cannot be initialized with no backends. If you " + "are seeing this error when trying to use default_backend() " + "please try uninstalling and reinstalling cryptography." + ) + self._backends = backends def _filtered_backends(self, interface): diff --git a/src/cryptography/hazmat/backends/openssl/hmac.py b/src/cryptography/hazmat/backends/openssl/hmac.py index dcf2fbaf..ab1ad46f 100644 --- a/src/cryptography/hazmat/backends/openssl/hmac.py +++ b/src/cryptography/hazmat/backends/openssl/hmac.py @@ -20,10 +20,10 @@ class _HMACContext(object): self._backend = backend if ctx is None: - ctx = self._backend._ffi.new("HMAC_CTX *") - self._backend._lib.HMAC_CTX_init(ctx) + ctx = self._backend._lib.Cryptography_HMAC_CTX_new() + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) ctx = self._backend._ffi.gc( - ctx, self._backend._lib.HMAC_CTX_cleanup + ctx, self._backend._lib.Cryptography_HMAC_CTX_free ) evp_md = self._backend._lib.EVP_get_digestbyname( algorithm.name.encode('ascii')) @@ -44,10 +44,10 @@ class _HMACContext(object): algorithm = utils.read_only_property("_algorithm") def copy(self): - copied_ctx = self._backend._ffi.new("HMAC_CTX *") - self._backend._lib.HMAC_CTX_init(copied_ctx) + copied_ctx = self._backend._lib.Cryptography_HMAC_CTX_new() + self._backend.openssl_assert(copied_ctx != self._backend._ffi.NULL) copied_ctx = self._backend._ffi.gc( - copied_ctx, self._backend._lib.HMAC_CTX_cleanup + copied_ctx, self._backend._lib.Cryptography_HMAC_CTX_free ) res = self._backend._lib.Cryptography_HMAC_CTX_copy( copied_ctx, self._ctx @@ -72,7 +72,6 @@ class _HMACContext(object): ) self._backend.openssl_assert(res != 0) self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size) - self._backend._lib.HMAC_CTX_cleanup(self._ctx) return self._backend._ffi.buffer(buf)[:outlen[0]] def verify(self, signature): diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py index f5999312..8b918995 100644 --- a/src/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py @@ -404,4 +404,14 @@ CONDITIONAL_NAMES = { "Cryptography_HAS_AES_CTR128_ENCRYPT": [ "AES_ctr128_encrypt", ], + "Cryptography_HAS_SSL_ST": [ + "SSL_ST_BEFORE", + "SSL_ST_OK", + "SSL_ST_INIT", + "SSL_ST_RENEGOTIATE", + ], + "Cryptography_HAS_TLS_ST": [ + "TLS_ST_BEFORE", + "TLS_ST_OK", + ], } diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 0aa67212..87d2de1c 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -191,6 +191,14 @@ class AuthorityKeyIdentifier(object): authority_cert_serial_number=None ) + @classmethod + def from_issuer_subject_key_identifier(cls, ski): + return cls( + key_identifier=ski.value.digest, + authority_cert_issuer=None, + authority_cert_serial_number=None + ) + def __repr__(self): return ( "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, " diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index 74835716..bf54d5ce 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -4,6 +4,8 @@ from __future__ import absolute_import, division, print_function +import pytest + from cryptography import utils from cryptography.exceptions import ( UnsupportedAlgorithm, _Reasons @@ -21,6 +23,10 @@ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from ...utils import raises_unsupported_algorithm +class DummyBackend(object): + pass + + @utils.register_interface(CipherBackend) class DummyCipherBackend(object): def __init__(self, supported_ciphers): @@ -226,6 +232,10 @@ class DummyX509Backend(object): class TestMultiBackend(object): + def test_raises_error_with_empty_list(self): + with pytest.raises(ValueError): + MultiBackend([]) + def test_ciphers(self): backend = MultiBackend([ DummyHashBackend([]), @@ -310,7 +320,7 @@ class TestMultiBackend(object): backend.load_rsa_public_numbers("public_numbers") - backend = MultiBackend([]) + backend = MultiBackend([DummyBackend()]) with raises_unsupported_algorithm( _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM ): @@ -353,7 +363,7 @@ class TestMultiBackend(object): backend.load_dsa_public_numbers("numbers") backend.load_dsa_parameter_numbers("numbers") - backend = MultiBackend([]) + backend = MultiBackend([DummyBackend()]) with raises_unsupported_algorithm( _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM ): @@ -491,7 +501,7 @@ class TestMultiBackend(object): backend.load_pem_private_key(b"keydata", None) backend.load_pem_public_key(b"keydata") - backend = MultiBackend([]) + backend = MultiBackend([DummyBackend()]) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): backend.load_pem_private_key(b"keydata", None) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): @@ -503,7 +513,7 @@ class TestMultiBackend(object): backend.load_der_private_key(b"keydata", None) backend.load_der_public_key(b"keydata") - backend = MultiBackend([]) + backend = MultiBackend([DummyBackend()]) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): backend.load_der_private_key(b"keydata", None) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): @@ -523,7 +533,7 @@ class TestMultiBackend(object): backend.create_x509_crl(object(), b"privatekey", hashes.SHA1()) backend.create_x509_revoked_certificate(object()) - backend = MultiBackend([]) + backend = MultiBackend([DummyBackend()]) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): backend.load_pem_x509_certificate(b"certdata") with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index d85b4bbc..28ddab87 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -2634,6 +2634,28 @@ class TestAuthorityKeyIdentifierExtension(object): ) assert ext.value == aki + def test_from_issuer_subject_key_identifier(self, backend): + issuer_cert = _load_cert( + os.path.join("x509", "rapidssl_sha256_ca_g3.pem"), + x509.load_pem_x509_certificate, + backend + ) + cert = _load_cert( + os.path.join("x509", "cryptography.io.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.AUTHORITY_KEY_IDENTIFIER + ) + ski = issuer_cert.extensions.get_extension_for_class( + x509.SubjectKeyIdentifier + ) + aki = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier( + ski + ) + assert ext.value == aki + class TestNameConstraints(object): def test_ipaddress_wrong_type(self): |