internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: pyca/cryptography

Issue:
Rethink x509.KeyUsage repr()
Right now we use `N/A` for two fields if they're undefined, this is a bit non-conventional, so we should think if there's a better way to express this.



Discussion:
What about `None`?

That sounds like a solid improvement.


Resolving patch:
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -353,8 +353,8 @@ def __repr__(self):
             encipher_only = self.encipher_only
             decipher_only = self.decipher_only
         except ValueError:
-            encipher_only = "N/A"
-            decipher_only = "N/A"
+            encipher_only = None
+            decipher_only = None
 
         return ("<KeyUsage(digital_signature={0.digital_signature}, "
                 "content_commitment={0.content_commitment}, "


Test patch:
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -149,8 +149,8 @@ def test_repr_key_agreement_false(self):
         assert repr(ku) == (
             "<KeyUsage(digital_signature=True, content_commitment=True, key_en"
             "cipherment=False, data_encipherment=False, key_agreement=False, k"
-            "ey_cert_sign=True, crl_sign=False, encipher_only=N/A, decipher_on"
-            "ly=N/A)>"
+            "ey_cert_sign=True, crl_sign=False, encipher_only=None, decipher_o"
+            "nly=None)>"
         )
 
     def test_repr_key_agreement_true(self):
Repository: pyca/cryptography

Issue:
Update openssl bindings to allow server side OCSP stapling
This is the server side for #1863 

I could not find public docs

I found code in OpenSSL sample server

https://github.com/openssl/openssl/blob/master/apps/s_server.c#L2131

```
SSL_CTX_set_tlsext_status_cb(ctx, cert_status_cb);

# callback signature
static int cert_status_cb(SSL *s, void *arg);

# Set response in callback based on OCSP response
rspderlen = i2d_OCSP_RESPONSE(resp, &rspder);
SSL_set_tlsext_status_ocsp_resp(s, rspder, rspderlen);

```



Discussion:

Resolving patch:
diff --git a/src/cryptography/hazmat/bindings/openssl/ssl.py b/src/cryptography/hazmat/bindings/openssl/ssl.py
--- a/src/cryptography/hazmat/bindings/openssl/ssl.py
+++ b/src/cryptography/hazmat/bindings/openssl/ssl.py
@@ -20,6 +20,8 @@
 static const long Cryptography_HAS_TLSv1_2;
 static const long Cryptography_HAS_SECURE_RENEGOTIATION;
 static const long Cryptography_HAS_COMPRESSION;
+static const long Cryptography_HAS_TLSEXT_STATUS_REQ_CB;
+static const long Cryptography_HAS_STATUS_REQ_OCSP_RESP;
 
 /* Internally invented symbol to tell us if SNI is supported */
 static const long Cryptography_HAS_TLSEXT_HOSTNAME;
@@ -315,6 +317,12 @@
     SSL_CTX *,
     int (*)(const SSL *, int *, void *));
 
+/* These were added in OpenSSL 0.9.8h, but since version testing in OpenSSL
+   is fraught with peril thanks to OS distributions we check some constants
+   to determine if they are supported or not */
+long SSL_set_tlsext_status_ocsp_resp(SSL *, unsigned char *, int);
+long SSL_CTX_set_tlsext_status_cb(SSL_CTX *, int(*)(SSL *, void *));
+
 long SSL_session_reused(SSL *);
 
 /* The following were macros in 0.9.8e. Once we drop support for RHEL/CentOS 5
@@ -410,6 +418,20 @@
     int (*)(const SSL *, int *, void *)) = NULL;
 #endif
 
+#ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB
+static const long Cryptography_HAS_TLSEXT_STATUS_REQ_CB = 1;
+#else
+static const long Cryptography_HAS_TLSEXT_STATUS_REQ_CB = 0;
+long (*SSL_CTX_set_tlsext_status_cb)(SSL_CTX *, int(*)(SSL *, void *)) = NULL;
+#endif
+
+#ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP
+static const long Cryptography_HAS_STATUS_REQ_OCSP_RESP = 1;
+#else
+static const long Cryptography_HAS_STATUS_REQ_OCSP_RESP = 0;
+long (*SSL_set_tlsext_status_ocsp_resp)(SSL *, unsigned char *, int) = NULL;
+#endif
+
 #ifdef SSL_MODE_RELEASE_BUFFERS
 static const long Cryptography_HAS_RELEASE_BUFFERS = 1;
 #else
@@ -588,6 +610,14 @@
         "SSL_CTX_set_tlsext_servername_callback",
     ],
 
+    "Cryptography_HAS_TLSEXT_STATUS_REQ_CB": [
+        "SSL_CTX_set_tlsext_status_cb",
+    ],
+
+    "Cryptography_HAS_STATUS_REQ_OCSP_RESP": [
+        "SSL_set_tlsext_status_ocsp_resp",
+    ],
+
     "Cryptography_HAS_RELEASE_BUFFERS": [
         "SSL_MODE_RELEASE_BUFFERS",
     ],


Test patch:
Repository: pyca/cryptography

Issue:
License Header Bug
https://github.com/pyca/cryptography/blob/master/src/cryptography/hazmat/backends/openssl/x509.py has the Apache license header when it should have the dual license header we use now.



Discussion:

Resolving patch:
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -1,15 +1,6 @@
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
 
 from __future__ import absolute_import, division, print_function
 


Test patch:
Repository: pyca/cryptography

Issue:
* not allowed in general names
If you attempt to parse a DNS name from a certificate SAN that contains a wildcard (e.g. `*.cryptography.io`) you get an IDNA InvalidCodePoint when it should successfully parse.



Discussion:
I'm not entirely sure how to resolve this short of just excluding a name from the IDNA decode if there's a \* in it. Ideas?

Presumaebly in `*.cryptgography.io` the `cryptography.io` portion should still be IDNA decoded?

Yeah, I think so.

This isn't actually fixed, we just added a vector.


Resolving patch:
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -82,7 +82,17 @@ def _decode_general_names(backend, gns):
 def _decode_general_name(backend, gn):
     if gn.type == backend._lib.GEN_DNS:
         data = backend._ffi.buffer(gn.d.dNSName.data, gn.d.dNSName.length)[:]
-        return x509.DNSName(idna.decode(data))
+        if data.startswith(b"*."):
+            # This is a wildcard name. We need to remove the leading wildcard,
+            # IDNA decode, then re-add the wildcard. Wildcard characters should
+            # always be left-most (RFC 2595 section 2.4).
+            data = u"*." + idna.decode(data[2:])
+        else:
+            # Not a wildcard, decode away. If the string has a * in it anywhere
+            # invalid this will raise an InvalidCodePoint
+            data = idna.decode(data)
+
+        return x509.DNSName(data)
     elif gn.type == backend._lib.GEN_URI:
         data = backend._ffi.buffer(
             gn.d.uniformResourceIdentifier.data,


Test patch:
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -1351,6 +1351,37 @@ def test_dns_name(self, backend):
         dns = san.get_values_for_type(x509.DNSName)
         assert dns == [u"www.cryptography.io", u"cryptography.io"]
 
+    def test_wildcard_dns_name(self, backend):
+        cert = _load_cert(
+            os.path.join("x509", "wildcard_san.pem"),
+            x509.load_pem_x509_certificate,
+            backend
+        )
+        ext = cert.extensions.get_extension_for_oid(
+            x509.OID_SUBJECT_ALTERNATIVE_NAME
+        )
+
+        dns = ext.value.get_values_for_type(x509.DNSName)
+        assert dns == [
+            u'*.langui.sh',
+            u'langui.sh',
+            u'*.saseliminator.com',
+            u'saseliminator.com'
+        ]
+
+    def test_san_wildcard_idna_dns_name(self, backend):
+        cert = _load_cert(
+            os.path.join("x509", "custom", "san_wildcard_idna.pem"),
+            x509.load_pem_x509_certificate,
+            backend
+        )
+        ext = cert.extensions.get_extension_for_oid(
+            x509.OID_SUBJECT_ALTERNATIVE_NAME
+        )
+
+        dns = ext.value.get_values_for_type(x509.DNSName)
+        assert dns == [u'*.\u043f\u044b\u043a\u0430.cryptography']
+
     def test_unsupported_other_name(self, backend):
         cert = _load_cert(
             os.path.join(
Repository: pyca/cryptography

Issue:
Add tests for what happens when x509.CertificateSignignRequestBuilder.sign is called before subject_name()
Right now on OpenSSL it fails with a random TypeError



Discussion:

Resolving patch:
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -833,7 +833,7 @@ def create_x509_csr(self, builder, private_key, algorithm):
 
         # Set subject name.
         res = self._lib.X509_REQ_set_subject_name(
-            x509_req, _encode_name(self, list(builder._subject_name))
+            x509_req, _encode_name(self, builder._subject_name)
         )
         assert res == 1
 
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -1486,4 +1486,6 @@ def sign(self, private_key, algorithm, backend):
         """
         Signs the request using the requestor's private key.
         """
+        if self._subject_name is None:
+            raise ValueError("A CertificateSigningRequest must have a subject")
         return backend.create_x509_csr(self, private_key, algorithm)


Test patch:
diff --git a/tests/test_x509.py b/tests/test_x509.py
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -687,10 +687,20 @@ class TestCertificateSigningRequestBuilder(object):
     def test_sign_invalid_hash_algorithm(self, backend):
         private_key = RSA_KEY_2048.private_key(backend)
 
-        builder = x509.CertificateSigningRequestBuilder()
+        builder = x509.CertificateSigningRequestBuilder().subject_name(
+            x509.Name([])
+        )
         with pytest.raises(TypeError):
             builder.sign(private_key, 'NotAHash', backend)
 
+    @pytest.mark.requires_backend_interface(interface=RSABackend)
+    def test_no_subject_name(self, backend):
+        private_key = RSA_KEY_2048.private_key(backend)
+
+        builder = x509.CertificateSigningRequestBuilder()
+        with pytest.raises(ValueError):
+            builder.sign(private_key, hashes.SHA256(), backend)
+
     @pytest.mark.requires_backend_interface(interface=RSABackend)
     def test_build_ca_request_with_rsa(self, backend):
         private_key = RSA_KEY_2048.private_key(backend)
Repository: pyca/cryptography

Issue:
``_encode_basic_constraints`` appears to leak a BASIC_CONSTRAINT *



Discussion:

Resolving patch:
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -119,6 +119,9 @@ def _encode_basic_constraints(backend, basic_constraints, critical):
     obj = _txt2obj(backend, x509.OID_BASIC_CONSTRAINTS.dotted_string)
     assert obj is not None
     constraints = backend._lib.BASIC_CONSTRAINTS_new()
+    constraints = backend._ffi.gc(
+        constraints, backend._lib.BASIC_CONSTRAINTS_free
+    )
     constraints.ca = 255 if basic_constraints.ca else 0
     if basic_constraints.ca:
         constraints.pathlen = _encode_asn1_int(


Test patch:
Repository: pyca/cryptography

Issue:
RFE: EC support, add more interfaces
Could the devs consider exposing the interfaces:

EC_KEY_new
EC_GROUP_set_asn1_flag
EC_GROUP_set_point_conversion_form

These are needed to create a named curve key pair (similar to how OpenSSL apps/ecparam.c).
If you only use EC_KEY_new_by_curve_name the curve is stored explicitly. 

Exampe use case: in pyOpenSSL
1. Create an EC key pair with named curve:
Hypothetical upgrade to  PKey.generate_key() for EC:
    ## generate EC key pair with named curve
    ec = _lib.EC_KEY_new()
    ## this is how openssl/apps/ecparam.c generates named curve key pairs
    egrp = _lib.EC_GROUP_new_by_curve_name(_lib.NID_secp521r1)
    _lib.EC_GROUP_set_asn1_flag(egrp, 1) ## sets named curve 
    _lib.EC_GROUP_set_point_conversion _form(egrp, 4) ## UNCOMPRESSED
    _lib.EC_KEY_set_group(ec, egrp)
    _lib.EC_KEY_generate_key(ec)
    _lib.EVP_PKEY_assign_EC_KEY(self._pkey, ec)

etc etc



Discussion:

Resolving patch:
diff --git a/src/_cffi_src/openssl/ec.py b/src/_cffi_src/openssl/ec.py
--- a/src/_cffi_src/openssl/ec.py
+++ b/src/_cffi_src/openssl/ec.py
@@ -56,6 +56,8 @@
     const EC_GROUP *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *);
 
 int EC_GROUP_get_degree(const EC_GROUP *);
+void EC_GROUP_set_asn1_flag(EC_GROUP *, int);
+void EC_GROUP_set_point_conversion_form(EC_GROUP *, point_conversion_form_t);
 
 const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *);
 const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *);
@@ -63,6 +65,7 @@
 
 size_t EC_get_builtin_curves(EC_builtin_curve *, size_t);
 
+EC_KEY *EC_KEY_new(void);
 void EC_KEY_free(EC_KEY *);
 
 int EC_KEY_get_flags(const EC_KEY *);
@@ -210,6 +213,7 @@
 static const int OPENSSL_EC_NAMED_CURVE = 0;
 
 void (*EC_KEY_free)(EC_KEY *) = NULL;
+EC_KEY *(*EC_KEY_new)(void) = NULL;
 size_t (*EC_get_builtin_curves)(EC_builtin_curve *, size_t) = NULL;
 EC_KEY *(*EC_KEY_new_by_curve_name)(int) = NULL;
 EC_KEY *(*EC_KEY_copy)(EC_KEY *, const EC_KEY *) = NULL;
@@ -218,6 +222,9 @@
 const EC_GROUP *(*EC_KEY_get0_group)(const EC_KEY *) = NULL;
 int (*EC_GROUP_get_order)(const EC_GROUP *, BIGNUM *, BN_CTX *) = NULL;
 int (*EC_KEY_set_group)(EC_KEY *, const EC_GROUP *) = NULL;
+void (*EC_GROUP_set_asn1_flag)(EC_GROUP *, int) = NULL;
+void (*EC_GROUP_set_point_conversion_form)(EC_GROUP *,
+                                           point_conversion_form_t) = NULL;
 const BIGNUM *(*EC_KEY_get0_private_key)(const EC_KEY *) = NULL;
 int (*EC_KEY_set_private_key)(EC_KEY *, const BIGNUM *) = NULL;
 const EC_POINT *(*EC_KEY_get0_public_key)(const EC_KEY *) = NULL;
@@ -412,6 +419,9 @@
         "EC_GROUP_get0_generator",
         "EC_GROUP_get_curve_name",
         "EC_GROUP_get_degree",
+        "EC_GROUP_set_asn1_flag",
+        "EC_GROUP_set_point_conversion_form",
+        "EC_KEY_new",
         "EC_KEY_free",
         "EC_get_builtin_curves",
         "EC_KEY_new_by_curve_name",


Test patch:
Repository: pyca/cryptography

Issue:
x509.CSR missing __hash__
Follow up to #2121 and #2120.



Discussion:
thanks


Resolving patch:
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -709,6 +709,9 @@ def __eq__(self, other):
     def __ne__(self, other):
         return not self == other
 
+    def __hash__(self):
+        return hash(self.public_bytes(serialization.Encoding.DER))
+
     def public_key(self):
         pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req)
         assert pkey != self._backend._ffi.NULL
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -1409,6 +1409,12 @@ def __ne__(self, other):
         Checks not equal.
         """
 
+    @abc.abstractmethod
+    def __hash__(self):
+        """
+        Computes a hash.
+        """
+
     @abc.abstractmethod
     def public_key(self):
         """


Test patch:
diff --git a/tests/test_x509.py b/tests/test_x509.py
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -746,6 +746,26 @@ def test_ne(self, backend):
         assert request1 != request2
         assert request1 != object()
 
+    def test_hash(self, backend):
+        request1 = _load_cert(
+            os.path.join("x509", "requests", "rsa_sha1.pem"),
+            x509.load_pem_x509_csr,
+            backend
+        )
+        request2 = _load_cert(
+            os.path.join("x509", "requests", "rsa_sha1.pem"),
+            x509.load_pem_x509_csr,
+            backend
+        )
+        request3 = _load_cert(
+            os.path.join("x509", "requests", "san_rsa_sha1.pem"),
+            x509.load_pem_x509_csr,
+            backend
+        )
+
+        assert hash(request1) == hash(request2)
+        assert hash(request1) != hash(request3)
+
 
 @pytest.mark.requires_backend_interface(interface=X509Backend)
 class TestCertificateSigningRequestBuilder(object):
Repository: pyca/cryptography

Issue:
Implement __hash__ for RSAPrivateNumbers and RSAPublicNumbers
For the record, `__eq__` is already implemented "sensibly", i.e. `assert key.private_numbers() == key.private_numbers()`, same for `public_numbers`.



Discussion:
Tested on 548e85ed63964c38fd450a4ee8753a5be2c956d5 and 0.9.3


Resolving patch:
diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py
--- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py
+++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -307,6 +307,17 @@ def __eq__(self, other):
     def __ne__(self, other):
         return not self == other
 
+    def __hash__(self):
+        return hash((
+            self.p,
+            self.q,
+            self.d,
+            self.dmp1,
+            self.dmq1,
+            self.iqmp,
+            self.public_numbers,
+        ))
+
 
 class RSAPublicNumbers(object):
     def __init__(self, e, n):
@@ -336,3 +347,6 @@ def __eq__(self, other):
 
     def __ne__(self, other):
         return not self == other
+
+    def __hash__(self):
+        return hash((self.e, self.n))


Test patch:
diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py
--- a/tests/hazmat/primitives/test_rsa.py
+++ b/tests/hazmat/primitives/test_rsa.py
@@ -1705,6 +1705,22 @@ def test_private_numbers_ne(self):
         )
         assert num != object()
 
+    def test_public_numbers_hash(self):
+        pub1 = RSAPublicNumbers(3, 17)
+        pub2 = RSAPublicNumbers(3, 17)
+        pub3 = RSAPublicNumbers(7, 21)
+
+        assert hash(pub1) == hash(pub2)
+        assert hash(pub1) != hash(pub3)
+
+    def test_private_numbers_hash(self):
+        priv1 = RSAPrivateNumbers(1, 2, 3, 4, 5, 6, RSAPublicNumbers(1, 2))
+        priv2 = RSAPrivateNumbers(1, 2, 3, 4, 5, 6, RSAPublicNumbers(1, 2))
+        priv3 = RSAPrivateNumbers(1, 2, 3, 4, 5, 6, RSAPublicNumbers(1, 3))
+
+        assert hash(priv1) == hash(priv2)
+        assert hash(priv1) != hash(priv3)
+
 
 class TestRSAPrimeFactorRecovery(object):
     @pytest.mark.parametrize(
Repository: pyca/cryptography

Issue:
Update Windows linking code
We should remove the environment variable based linking and document that if you want to build it dynamic vs static then you should build the OpenSSL libs in your preferred fashion. The zip files we create in our jenkins job build them statically.



Discussion:

Resolving patch:
diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py
--- a/src/_cffi_src/build_openssl.py
+++ b/src/_cffi_src/build_openssl.py
@@ -4,7 +4,6 @@
 
 from __future__ import absolute_import, division, print_function
 
-import os
 import sys
 
 from _cffi_src.utils import build_ffi_for_binding, extra_link_args
@@ -19,20 +18,8 @@ def _get_openssl_libraries(platform):
         # (http://marc.info/?l=openssl-users&m=135361825921871)
         return ["ssl", "crypto"]
     else:
-        link_type = os.environ.get("PYCA_WINDOWS_LINK_TYPE", "static")
-        return _get_openssl_windows_libraries(link_type)
-
-
-def _get_openssl_windows_libraries(link_type):
-    if link_type == "dynamic":
-        return ["libeay32", "ssleay32", "advapi32"]
-    elif link_type == "static" or link_type == "":
-        return ["libeay32mt", "ssleay32mt", "advapi32",
+        return ["libeay32", "ssleay32", "advapi32",
                 "crypt32", "gdi32", "user32", "ws2_32"]
-    else:
-        raise ValueError(
-            "PYCA_WINDOWS_LINK_TYPE must be 'static' or 'dynamic'"
-        )
 
 
 _OSX_PRE_INCLUDE = """


Test patch:
Repository: pyca/cryptography

Issue:
Use utf-8 strings in generated certs
Currently when adding unicode string to cert it end up as t61string or bmpstring.
Those are really ancient formats that are annoying to support in new code.

With some digging I would following workaround:

```
from cryptography.hazmat.backends.openssl import backend
backend._lib.ASN1_STRING_set_default_mask_asc(b"utf8only")
```

As the comment says:

>  utf8only : only use UTF8Strings (RFC2459 recommendation for 2004)

Please make it default.  There are already bunch of root certs using this setting, so it's safe to enable for private certs too, at 2015...



Discussion:
@markokr could you provide some code to reproduce? We should already be using MBSTRING_UTF8 types everywhere, but this is definitely a bug if we missed a spot. Changing the global default is also an option and is what we've done in PyOpenSSL but I'd like to fully understand what's going on here before making any changes.

MBSTRING_UTF8 simply says that _incoming_ string is utf8.  But then OpenSSL goes on to decide what the outgoing string will be:  https://github.com/openssl/openssl/blob/master/crypto/asn1/a_mbstr.c#L77

Thats what the set-default does - to tell what the outgoing should be.

@markokr understood, but can you provide a reproducer that demonstrates a case where it chooses T61 or BMP? I've been testing on 0.9.8zg and 1.0.2d and all our current unicode test cases create utf8string ASN.1 output, so I'd like to add a test case to confirm the improper behavior.

https://github.com/markokr/libusual/blob/master/test/ssl/mkcerts.py

remove the utf8only setting, then the complex1 cert will have L= as t61, and ST= as bmp.

Ubuntu 12.04, OpenSSL 1.0.1, cryptography 1.0

Okay I see the problem. Modern OpenSSLs (even the 0.9.8 series) actually set this mask by default while ubuntu 12.04's 1.0.1 does not.

So we'll go ahead and add it to our backend initialization (although since it's a global arguably binding might make sense). Thanks for the report @markokr!


Resolving patch:
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -521,6 +521,12 @@ def __init__(self):
         self._ffi = self._binding.ffi
         self._lib = self._binding.lib
 
+        # Set the default string mask for encoding ASN1 strings to UTF8. This
+        # is the default for newer OpenSSLs for several years and is
+        # recommended in RFC 2459.
+        res = self._lib.ASN1_STRING_set_default_mask_asc(b"utf8only")
+        assert res == 1
+
         self._binding.init_static_locks()
 
         # adds all ciphers/digests for EVP


Test patch: