Merge pull request #2807 from reaperhulk/110-patch-26

conditionally bind/remove the SSL_ST/TLS_ST state machine statuses
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 0bbbcde..1c11f02 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -14,6 +14,8 @@
   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/development/test-vectors.rst b/docs/development/test-vectors.rst
index e461892..73ddb97 100644
--- a/docs/development/test-vectors.rst
+++ b/docs/development/test-vectors.rst
@@ -113,6 +113,9 @@
 * ``department-of-state-root.pem`` - The intermediary CA for the Department of
   State, issued by the United States Federal Government's Common Policy CA.
   Notably has a ``critical`` policy constraints extensions.
+* ``e-trust.ru.der`` - A certificate from a `Russian CA`_ signed using the GOST
+  cipher and containing numerous unusual encodings such as NUMERICSTRING in
+  the subject DN.
 
 Custom X.509 Vectors
 ~~~~~~~~~~~~~~~~~~~~
@@ -450,3 +453,4 @@
 .. _`root data`: https://hg.mozilla.org/projects/nss/file/25b2922cc564/security/nss/lib/ckfw/builtins/certdata.txt#l2053
 .. _`asymmetric/public/PKCS1/dsa.pub.pem`: https://github.com/ruby/ruby/blob/4ccb387f3bc436a08fc6d72c4931994f5de95110/test/openssl/test_pkey_dsa.rb#L53
 .. _`Mozilla bug`: https://bugzilla.mozilla.org/show_bug.cgi?id=233586
+.. _`Russian CA`: http://e-trust.gosuslugi.ru/MainCA
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 67427dd..399d693 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -1541,6 +1541,13 @@
 
         .. 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 @@
             >>> 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/engine.py b/src/_cffi_src/openssl/engine.py
index 77c97fe..afdd54e 100644
--- a/src/_cffi_src/openssl/engine.py
+++ b/src/_cffi_src/openssl/engine.py
@@ -16,12 +16,10 @@
 typedef ... DSA_METHOD;
 typedef ... DH_METHOD;
 typedef struct {
-    void (*seed)(const void *, int);
     int (*bytes)(unsigned char *, int);
-    void (*cleanup)();
-    void (*add)(const void *, int, double);
     int (*pseudorand)(unsigned char *, int);
     int (*status)();
+    ...;
 } RAND_METHOD;
 typedef int (*ENGINE_GEN_INT_FUNC_PTR)(ENGINE *);
 typedef ... *ENGINE_CTRL_FUNC_PTR;
diff --git a/src/_cffi_src/openssl/evp.py b/src/_cffi_src/openssl/evp.py
index a91a966..5abc645 100644
--- a/src/_cffi_src/openssl/evp.py
+++ b/src/_cffi_src/openssl/evp.py
@@ -12,9 +12,7 @@
 typedef ... EVP_CIPHER;
 typedef ... EVP_CIPHER_CTX;
 typedef ... EVP_MD;
-typedef struct env_md_ctx_st {
-    ...;
-} EVP_MD_CTX;
+typedef struct { ...; } EVP_MD_CTX;
 
 typedef ... EVP_PKEY;
 typedef ... EVP_PKEY_CTX;
@@ -55,13 +53,11 @@
 void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *);
 int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *, int);
 
-EVP_MD_CTX *EVP_MD_CTX_create(void);
 int EVP_MD_CTX_copy_ex(EVP_MD_CTX *, const EVP_MD_CTX *);
 int EVP_DigestInit_ex(EVP_MD_CTX *, const EVP_MD *, ENGINE *);
 int EVP_DigestUpdate(EVP_MD_CTX *, const void *, size_t);
 int EVP_DigestFinal_ex(EVP_MD_CTX *, unsigned char *, unsigned int *);
 int EVP_MD_CTX_cleanup(EVP_MD_CTX *);
-void EVP_MD_CTX_destroy(EVP_MD_CTX *);
 const EVP_MD *EVP_get_digestbyname(const char *);
 
 EVP_PKEY *EVP_PKEY_new(void);
@@ -115,6 +111,12 @@
 EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *);
 
 int Cryptography_EVP_PKEY_id(const EVP_PKEY *);
+
+/* in 1.1.0 _create and _destroy were renamed to _new and _free. The following
+   two functions wrap both the old and new functions so we can call them
+   without worrying about what OpenSSL we're running against. */
+EVP_MD_CTX *Cryptography_EVP_MD_CTX_new(void);
+void Cryptography_EVP_MD_CTX_free(EVP_MD_CTX *);
 """
 
 MACROS = """
@@ -235,4 +237,18 @@
         return key->type;
     #endif
 }
+EVP_MD_CTX *Cryptography_EVP_MD_CTX_new(void) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+    return EVP_MD_CTX_create();
+#else
+    return EVP_MD_CTX_new();
+#endif
+}
+void Cryptography_EVP_MD_CTX_free(EVP_MD_CTX *ctx) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+    EVP_MD_CTX_destroy(ctx);
+#else
+    EVP_MD_CTX_free(ctx);
+#endif
+}
 """
diff --git a/src/_cffi_src/openssl/hmac.py b/src/_cffi_src/openssl/hmac.py
index 7178e57..bcc8a86 100644
--- a/src/_cffi_src/openssl/hmac.py
+++ b/src/_cffi_src/openssl/hmac.py
@@ -9,18 +9,17 @@
 """
 
 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 @@
         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/cryptography/hazmat/backends/multibackend.py b/src/cryptography/hazmat/backends/multibackend.py
index 65f1853..48bc7d0 100644
--- a/src/cryptography/hazmat/backends/multibackend.py
+++ b/src/cryptography/hazmat/backends/multibackend.py
@@ -28,6 +28,13 @@
     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/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index e47f747..064f9ad 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -1003,11 +1003,14 @@
             x509_revoked, serial_number
         )
         self.openssl_assert(res == 1)
-        res = self._lib.ASN1_TIME_set(
-            x509_revoked.revocationDate,
+        rev_date = self._lib.ASN1_TIME_set(
+            self._ffi.NULL,
             calendar.timegm(builder._revocation_date.timetuple())
         )
-        self.openssl_assert(res != self._ffi.NULL)
+        self.openssl_assert(rev_date != self._ffi.NULL)
+        rev_date = self._ffi.gc(rev_date, self._lib.ASN1_TIME_free)
+        res = self._lib.X509_REVOKED_set_revocationDate(x509_revoked, rev_date)
+        self.openssl_assert(res == 1)
         # add CRL entry extensions
         self._create_x509_extensions(
             extensions=builder._extensions,
diff --git a/src/cryptography/hazmat/backends/openssl/hashes.py b/src/cryptography/hazmat/backends/openssl/hashes.py
index 02ce5f0..2c8fce1 100644
--- a/src/cryptography/hazmat/backends/openssl/hashes.py
+++ b/src/cryptography/hazmat/backends/openssl/hashes.py
@@ -18,9 +18,10 @@
         self._backend = backend
 
         if ctx is None:
-            ctx = self._backend._lib.EVP_MD_CTX_create()
-            ctx = self._backend._ffi.gc(ctx,
-                                        self._backend._lib.EVP_MD_CTX_destroy)
+            ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
+            ctx = self._backend._ffi.gc(
+                ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
+            )
             evp_md = self._backend._lib.EVP_get_digestbyname(
                 algorithm.name.encode("ascii"))
             if evp_md == self._backend._ffi.NULL:
@@ -38,9 +39,9 @@
     algorithm = utils.read_only_property("_algorithm")
 
     def copy(self):
-        copied_ctx = self._backend._lib.EVP_MD_CTX_create()
+        copied_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
         copied_ctx = self._backend._ffi.gc(
-            copied_ctx, self._backend._lib.EVP_MD_CTX_destroy
+            copied_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
         )
         res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx)
         self._backend.openssl_assert(res != 0)
@@ -57,6 +58,4 @@
         res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen)
         self._backend.openssl_assert(res != 0)
         self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size)
-        res = self._backend._lib.EVP_MD_CTX_cleanup(self._ctx)
-        self._backend.openssl_assert(res == 1)
         return self._backend._ffi.buffer(buf)[:outlen[0]]
diff --git a/src/cryptography/hazmat/backends/openssl/hmac.py b/src/cryptography/hazmat/backends/openssl/hmac.py
index dcf2fba..ab1ad46 100644
--- a/src/cryptography/hazmat/backends/openssl/hmac.py
+++ b/src/cryptography/hazmat/backends/openssl/hmac.py
@@ -20,10 +20,10 @@
         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 @@
     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 @@
         )
         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/x509/extensions.py b/src/cryptography/x509/extensions.py
index 0aa6721..87d2de1 100644
--- a/src/cryptography/x509/extensions.py
+++ b/src/cryptography/x509/extensions.py
@@ -191,6 +191,14 @@
             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 7483571..bf54d5c 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 ...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 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 @@
 
         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 @@
         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 @@
         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 @@
         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 @@
         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 d85b4bb..28ddab8 100644
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -2634,6 +2634,28 @@
         )
         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):
diff --git a/vectors/cryptography_vectors/x509/e-trust.ru.der b/vectors/cryptography_vectors/x509/e-trust.ru.der
new file mode 100644
index 0000000..72b581f
--- /dev/null
+++ b/vectors/cryptography_vectors/x509/e-trust.ru.der
Binary files differ