Repository: pyca/cryptography

Issue:
Name.public_bytes can throw InternalError
With cryptography 2.1.4 on OS X installed from wheel, Name.public_bytes can throw InternalError.

```python
x509.load_pem_x509_certificate(b"""
-----BEGIN CERTIFICATE-----
MIIDjjCCAnagAwIBAgILAQAAAAABJsKRJRIwDQYJKoZIhvcNAQEFBQAwYzELMAkG
A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExFjAUBgNVBAsTDVNl
cnZlclNpZ24gQ0ExITAfBgNVBAMTGEdsb2JhbFNpZ24gU2VydmVyU2lnbiBDQTAe
Fw0xMDAyMTIxMzM4MzVaFw0xMzAyMTIxMzM4MzVaMIGnMQswCQYDVQQGEwJUUjER
MA8GA1UECBMISXN0YW5idWwxETAPBgNVBAcTCElzdGFuYnVsMRswGQYDVQQKExJB
dml2YSBTaWdvcnRhIEEuUy4xIDAeBgNVBAsTF0UtQWdlbnQgLSBJVCBEZXBhcnRt
ZW50MTMwMQYDVQQDHioAKgAuAGEAdgBpAHYAYQBzAGkAZwBvAHIAdABhAC4AYwBv
AG0ALgB0AHIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALj2zdnQ+N6UCIFs
U/hFpqNOD0VxHfuAVSquaZMin9aUW6rgPWBI4S9sOdrmSuJCuct08v8tIttAin/j
O64xCt+tg6QNI0SZ3PRgVyaAwzsyN1b9IRKruedIV2cnDy+E5w1ZSypyZRbaobxH
suQVC10EV0UhJTpS8bPHJMjJu+MfAgMBAAGjgYEwfzARBglghkgBhvhCAQEEBAMC
BsAwDgYDVR0PAQH/BAQDAgTwMB8GA1UdIwQYMBaAFEi7qL9bhNJXSORh6ZEgkdgd
Jd9/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5uZXQv
U2VydmVyU2lnbi5jcmwwDQYJKoZIhvcNAQEFBQADggEBACKUZmR4IJdUSZfM3EQO
ejT7fiRAvVw3Midjn3QwyI5ddS/7t0jQFxnTD+7ybQo0pCxh+o12TIU6YGouyoA8
mJDWaqE2E0SOis7wdraBQzo9W4EbKqwtSHDmjTmwPJQdE6XLTUOuWDychykN0Ea7
c+sa9IflPHlya0ColfYd/+/rCMY9p3LY8Fx9RH0Jy9WiSjuF+HaquvUxiuzNsX6K
f6Mu6vatE+5t+XRdUnn8DPm+VQHGfdYSkmI3qCFQ6S2KbLd5k7HRxJzoZvAGwnDc
skuaLlIH4aRs+YlUzfoq6AUkn2lA5Isa0MrYLI6VjfW66M1gcimfIGJ8GXbu6SZe
pVg=
-----END CERTIFICATE-----
""", backend).subject.public_bytes(backend)
```

This throws:
`InternalError: ... ([_OpenSSLErrorWithText(code=218939606, lib=13, func=204, reason=214, reason_text=b'error:0D0CC0D6:asn1 encoding routines:asn1_ex_c2i:bmpstring is wrong length'), _OpenSSLErrorWithText(code=218640442, lib=13, func=131, reason=58, reason_text=b'error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error')])`

Another certificate that also gives `bmpstring is wrong length` is:
<details>

```
-----BEGIN CERTIFICATE-----
MIIHqzCCBZOgAwIBAgICEhcwDQYJKoZIhvcNAQELBQAwgZ0xCzAJBgNVBAYTAkVT
MRQwEgYDVQQKDAtJWkVOUEUgUy5BLjE6MDgGA1UECwwxQVpaIFppdXJ0YWdpcmkg
cHVibGlrb2EgLSBDZXJ0aWZpY2FkbyBwdWJsaWNvIFNDQTE8MDoGA1UEAwwzRUFF
a28gSGVycmkgQWRtaW5pc3RyYXppb2VuIENBIC0gQ0EgQUFQUCBWYXNjYXMgKDIp
MB4XDTE1MDIxMzEyNDUwMVoXDTE4MDIxMzEyNDQ1OFowgZUxCzAJBgNVBAYTAkVT
MRAwDgYDVQQIEwdCaXprYWlhMQ4wDAYDVQQHEwVHZXR4bzEuMCwGA1UEChMlR0VU
WE9rbyBVREFMQSAtIEFZVU5UQU1JRU5UTyBkZSBHRVRYTzETMBEGA1UECxMKRVVE
QUxBIFdFQjEfMB0GA1UEAx4WACoALgBnAGUAdAB4AG8ALgBlAHUAczCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ7OdqcJZsDWaZuYzw85Lb5KCmVxEAFk
19fu4j7Wc9NAbTYwsKHLHQMrcjKO03g1nlhCfbleIObO1D+iQV6CHEPwHajiMKio
dKqT7IwS9B4Wd6hktA8Gi9PQQ6Y5S0WwpclTBV6UkjUQkQEvPmGZf59tU6dgK+7w
pUmYF5oIWoJNELqKXBMECWqrF4HRaUVgnbATbfMP2FNXdfZJTM5RPSsTgbde7da9
6GXih8rDJkH7gNL84WGgGf/LH9z1w4uYdS94fBxDL0mc6Cfs5NVd7P62r0ETG7oF
Aon+kWDrr4QuDF4GOo0P54KvQpB17Ajm4VQXzyPDNWsbUTFEYyEwxIMCAwEAAaOC
AvkwggL1MIHHBgNVHRIEgb8wgbyGFWh0dHA6Ly93d3cuaXplbnBlLmNvbYEPaW5m
b0BpemVucGUuY29tpIGRMIGOMUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBB
MDEzMzcyNjAtUk1lcmMuVml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEG
A1UECQw6QXZkYSBkZWwgTWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEw
IFZpdG9yaWEtR2FzdGVpejAWBgNVHREEDzANggsqLmdldHhvLmV1czAnBgNVHSUE
IDAeBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBS1Q6H0
j+dX000bMTMfprsdN726/jAfBgNVHSMEGDAWgBTAqUr3RyWH/7y1ponOgtJGqInr
ozCCATEGA1UdIASCASgwggEkMIIBFgYKKwYBBAHzOQECATCCAQYwLQYIKwYBBQUH
AgEWIWh0dHA6Ly93d3cuaXplbnBlLmNvbS9ycGFzZXJ2aWRvcjCB1AYIKwYBBQUH
AgIwgccagcRCZXJtZWVuIG11Z2FrIGV6YWd1dHpla28gd3d3Lml6ZW5wZS5jb20g
Wml1cnRhZ2lyaWFuIGtvbmZpYW50emEgaXphbiBhdXJyZXRpayBrb250cmF0dWEg
aXJha3VycmkuTGltaXRhY2lvbmVzIGRlIGdhcmFudGlhcyBlbiB3d3cuaXplbnBl
LmNvbSBDb25zdWx0ZSBlbCBjb250cmF0byBhbnRlcyBkZSBjb25maWFyIGVuIGVs
IGNlcnRpZmljYWRvMAgGBmeBDAECAjA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUH
MAGGG2h0dHA6Ly9vY3NwLml6ZW5wZS5jb206ODA5NDA6BgNVHR8EMzAxMC+gLaAr
hilodHRwOi8vY3JsLml6ZW5wZS5jb20vY2dpLWJpbi9jcmxpbnRlcm5hMjANBgkq
hkiG9w0BAQsFAAOCAgEAEpe/NnJkRhMmLWYEejpIWUtZirXTDDUipfSteZq5WOes
OZ+9MMNpneGz+KeinBhAjmPzn+mCCNx9i03d+x0uG09V3tFilnavC+hchK+2Si/U
ZJv/mZosQguNVvp8nZHnmbFm9hXwqEEZMzatm+yDj42fYHp7DTFiFtsIvif5iYkv
JcGBT/xhIMZ8TVD0+jU1bhx0y5mm97ixoyz1ezCRXsf2d2jKn5jM9/RpKJaWCwTM
rn5n8FjjqvV5hhwDEN+8aaZtFR8y3RZJFz197ebiViCJwl+4j4eSfeS0gUyiJF08
8HtV9V6wstX71PV+Oj1jzV0Fh0YvNmEYYeSbCLMlgBfbNPyBemUR6RIYIW2j+6aY
TvU69p6JOhXuoogRL/9a94x7nfsXmpTlb7o2ad1VE9xqWuVlFoRrbEkTq3/QtuuS
p0RhlJrsAGsO6wyUQsuhQ5j+LpI8xUHk1piWv/CXmnPF1z73XXtVeCVx9HyFyGo2
48Vos0ce/nEY0K3Uvxzdy0jeMPYiqJdoaE2S4O0HRCdVTlGZOCxBuGV9edb3A9VA
VfpbJQ2zJ+Cl3kbHZjk0yWwJ12eK/1RNRiBD/du+ymVN7E/H7zKXSI1Te5Qk1+ux
seaEv0mNm4CPGa6JnEVnmO3kUrbHMiQYo8mPTdQPluRrF4HSoW2gxYfEvoeXfLI=
-----END CERTIFICATE-----
```

</details>


Discussion:
Can you include the full stack trace please?
Yep, sorry:

<details>
<summary>Stack trace</summary>

```
InternalError                             Traceback (most recent call last)
<ipython-input-33-57425e86ea22> in <module>()
----> 1 problem_certs[1].subject.public_bytes(backend)

~/.virtualenvs/ct/lib/python3.6/site-packages/cryptography/x509/name.py in public_bytes(self, backend)
    150 
    151     def public_bytes(self, backend):
--> 152         return backend.x509_name_bytes(self)
    153 
    154     def __eq__(self, other):

~/.virtualenvs/ct/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/backend.py in x509_name_bytes(self, name)
   1877 
   1878     def x509_name_bytes(self, name):
-> 1879         x509_name = _encode_name_gc(self, name)
   1880         pp = self._ffi.new("unsigned char **")
   1881         res = self._lib.i2d_X509_NAME(x509_name, pp)

~/.virtualenvs/ct/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py in _encode_name_gc(backend, attributes)
     99 
    100 def _encode_name_gc(backend, attributes):
--> 101     subject = _encode_name(backend, attributes)
    102     subject = backend._ffi.gc(subject, backend._lib.X509_NAME_free)
    103     return subject

~/.virtualenvs/ct/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py in _encode_name(backend, name)
     93             res = backend._lib.X509_NAME_add_entry(
     94                 subject, name_entry, -1, set_flag)
---> 95             backend.openssl_assert(res == 1)
     96             set_flag = -1
     97     return subject

~/.virtualenvs/ct/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/backend.py in openssl_assert(self, ok)
    104 
    105     def openssl_assert(self, ok):
--> 106         return binding._openssl_assert(self._lib, ok)
    107 
    108     def activate_builtin_random(self):

~/.virtualenvs/ct/lib/python3.6/site-packages/cryptography/hazmat/bindings/openssl/binding.py in _openssl_assert(lib, ok)
     73             "issues with information on how to reproduce "
     74             "this. ({0!r})".format(errors_with_text),
---> 75             errors_with_text
     76         )
     77 

InternalError: Unknown OpenSSL error. This error is commonly encountered when another library is not cleaning up the OpenSSL error stack. If you are using cryptography with another library that uses OpenSSL try disabling it before reporting a bug. Otherwise please file an issue at https://github.com/pyca/cryptography/issues with information on how to reproduce this. ([_OpenSSLErrorWithText(code=218939606, lib=13, func=204, reason=214, reason_text=b'error:0D0CC0D6:asn1 encoding routines:asn1_ex_c2i:bmpstring is wrong length'), _OpenSSLErrorWithText(code=218640442, lib=13, func=131, reason=58, reason_text=b'error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error')])
```

</details>

Resolving patch:
diff --git a/src/cryptography/hazmat/backends/openssl/encode_asn1.py b/src/cryptography/hazmat/backends/openssl/encode_asn1.py
--- a/src/cryptography/hazmat/backends/openssl/encode_asn1.py
+++ b/src/cryptography/hazmat/backends/openssl/encode_asn1.py
@@ -14,6 +14,7 @@
     _CRL_ENTRY_REASON_ENUM_TO_CODE, _DISTPOINT_TYPE_FULLNAME,
     _DISTPOINT_TYPE_RELATIVENAME
 )
+from cryptography.x509.name import _ASN1Type
 from cryptography.x509.oid import CRLEntryExtensionOID, ExtensionOID
 
 
@@ -116,11 +117,15 @@ def _encode_sk_name_entry(backend, attributes):
 
 
 def _encode_name_entry(backend, attribute):
-    value = attribute.value.encode('utf8')
+    if attribute._type is _ASN1Type.BMPString:
+        value = attribute.value.encode('utf_16_be')
+    else:
+        value = attribute.value.encode('utf8')
+
     obj = _txt2obj_gc(backend, attribute.oid.dotted_string)
 
     name_entry = backend._lib.X509_NAME_ENTRY_create_by_OBJ(
-        backend._ffi.NULL, obj, attribute._type.value, value, -1
+        backend._ffi.NULL, obj, attribute._type.value, value, len(value)
     )
     return name_entry
 


Test patch:
diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py
--- a/tests/x509/test_x509.py
+++ b/tests/x509/test_x509.py
@@ -4089,6 +4089,24 @@ def test_bytes(self, backend):
             b"b060355040a0c0450794341"
         )
 
+    @pytest.mark.requires_backend_interface(interface=X509Backend)
+    def test_bmpstring_bytes(self, backend):
+        # For this test we need an odd length string. BMPString is UCS-2
+        # encoded so it will always be even length and OpenSSL will error if
+        # you pass an odd length string without encoding it properly first.
+        name = x509.Name([
+            x509.NameAttribute(
+                NameOID.COMMON_NAME,
+                u'cryptography.io',
+                _ASN1Type.BMPString
+            ),
+            x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'PyCA'),
+        ])
+        assert name.public_bytes(backend) == binascii.unhexlify(
+            b"30383127302506035504031e1e00630072007900700074006f00670072006100"
+            b"7000680079002e0069006f310d300b060355040a0c0450794341"
+        )
+
 
 def test_random_serial_number(monkeypatch):
     sample_data = os.urandom(20)