Repository: pyca/cryptography

Issue:
Empty subject or issuer in x.509 certificates throws Unknown OpenSSL error.
When trying to build a x509 certificate with an empty string as issuer or subject name, an unknown OpenSSL error is thrown. Maybe that should be handled differently.

**Tested on:**
```
Ubuntu 16.04.2 LTS
OpenSSL 1.0.2g  1 Mar 2016
cryptography 1.9
```
```
macOS Sierra 10.12.5
OpenSSL 0.9.8zh 14 Jan 2016
cryptography 1.9
```
**To reproduce:**
```
$ python openssl_error.py
```
```
Traceback (most recent call last):
  File "openssl_error.py", line 19, in <module>
    cert = builder.sign(private_key, hashes.SHA256(), default_backend())
  File "/home/ubuntu/.local/lib/python2.7/site-packages/cryptography/x509/base.py", line 564, in sign
    return backend.create_x509_certificate(self, private_key, algorithm)
  File "/home/ubuntu/.local/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 746, in create_x509_certificate
    x509_cert, _encode_name_gc(self, builder._subject_name)
  File "/home/ubuntu/.local/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py", line 103, in _encode_name_gc
    subject = _encode_name(backend, attributes)
  File "/home/ubuntu/.local/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py", line 97, in _encode_name
    backend.openssl_assert(res == 1)
  File "/home/ubuntu/.local/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 107, in openssl_assert
    return binding._openssl_assert(self._lib, ok)
  File "/home/ubuntu/.local/lib/python2.7/site-packages/cryptography/hazmat/bindings/openssl/binding.py", line 75, in _openssl_assert
    errors_with_text
cryptography.exceptions.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=218603672L, lib=13, func=122, reason=152, reason_text='error:0D07A098:asn1 encoding routines:ASN1_mbstring_ncopy:string too short')])
```

**openssl_error.py**
```
import six
import datetime
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes

builder = x509.CertificateBuilder()
builder = builder.serial_number(x509.random_serial_number())
builder = builder.not_valid_before(datetime.datetime.today())
builder = builder.not_valid_after(datetime.datetime.today())

# Empty strings here seems to make it crash.
builder = builder.subject_name(x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, six.u('')), ]))
builder = builder.issuer_name(x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, six.u('')), ]))

private_key = rsa.generate_private_key(65537, 2048, default_backend())
builder = builder.public_key(private_key.public_key())
cert = builder.sign(private_key, hashes.SHA256(), default_backend())
```


Discussion:
Indeed it should. Unknown OpenSSL error is always a bug. Thanks for the report!

Resolving patch:
diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py
--- a/src/cryptography/x509/name.py
+++ b/src/cryptography/x509/name.py
@@ -27,6 +27,9 @@ def __init__(self, oid, value):
                 "Country name must be a 2 character country code"
             )
 
+        if len(value) == 0:
+            raise ValueError("Value cannot be an empty string")
+
         self._oid = oid
         self._value = value
 


Test patch:
diff --git a/tests/test_x509.py b/tests/test_x509.py
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -3624,6 +3624,10 @@ def test_init_bad_country_code_value(self):
                 u'\U0001F37A\U0001F37A'
             )
 
+    def test_init_empty_value(self):
+        with pytest.raises(ValueError):
+            x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'')
+
     def test_eq(self):
         assert x509.NameAttribute(
             x509.ObjectIdentifier('2.999.1'), u'value'