From 87b2749c52e688c809f1861e55d958c64147493c Mon Sep 17 00:00:00 2001 From: Andrea De Pasquale <447065+adepasquale@users.noreply.github.com> Date: Thu, 19 Mar 2020 20:23:35 +0100 Subject: Allow NameAttribute.value to be an empty string (#5109) * Allow NameAttribute.value to be an empty string RFC 4514 https://tools.ietf.org/html/rfc4514 does not mention that "AttributeValue" can not be an empty (zero-length) string. Fixes #5106 * reverse order to match fix from another PR Co-authored-by: Paul Kehrer --- src/cryptography/x509/name.py | 6 +++--- tests/x509/test_x509.py | 22 ++++++++++++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index 922cab5a..6816e063 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -54,6 +54,9 @@ _NAMEOID_TO_NAME = { def _escape_dn_value(val): """Escape special characters in RFC4514 Distinguished Name value.""" + if not val: + return '' + # See https://tools.ietf.org/html/rfc4514#section-2.4 val = val.replace('\\', '\\\\') val = val.replace('"', '\\"') @@ -93,9 +96,6 @@ class NameAttribute(object): "Country name must be a 2 character country code" ) - if len(value) == 0: - raise ValueError("Value cannot be an empty string") - # The appropriate ASN1 string type varies by OID and is defined across # multiple RFCs including 2459, 3280, and 5280. In general UTF8String # is preferred (2459), but 3280 and 5280 specify several OIDs with diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index fb0c96ab..7c45660f 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -4281,6 +4281,10 @@ class TestNameAttribute(object): b'bytes' ) + def test_init_none_value(self): + with pytest.raises(TypeError): + x509.NameAttribute(NameOID.ORGANIZATION_NAME, None) + def test_init_bad_country_code_value(self): with pytest.raises(ValueError): x509.NameAttribute( @@ -4295,10 +4299,6 @@ class TestNameAttribute(object): u'\U0001F37A\U0001F37A' ) - def test_init_empty_value(self): - with pytest.raises(ValueError): - x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'') - def test_invalid_type(self): with pytest.raises(TypeError): x509.NameAttribute(NameOID.COMMON_NAME, u"common", "notanenum") @@ -4350,6 +4350,10 @@ class TestNameAttribute(object): assert (na.rfc4514_string() == '1.2.840.113549.1.9.1=somebody@example.com') + def test_empty_value(self): + na = x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u'') + assert na.rfc4514_string() == r'ST=' + class TestRelativeDistinguishedName(object): def test_init_empty(self): @@ -4569,6 +4573,16 @@ class TestName(object): assert (n.rfc4514_string() == 'OU=Sales+CN=J. Smith,DC=example,DC=net') + def test_rfc4514_string_empty_values(self): + n = x509.Name([ + x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'), + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u''), + x509.NameAttribute(NameOID.LOCALITY_NAME, u''), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'PyCA'), + x509.NameAttribute(NameOID.COMMON_NAME, u'cryptography.io'), + ]) + assert (n.rfc4514_string() == 'CN=cryptography.io,O=PyCA,L=,ST=,C=US') + def test_not_nameattribute(self): with pytest.raises(TypeError): x509.Name(["not-a-NameAttribute"]) -- cgit v1.2.3