diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 40a1d6d51..699df31de 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -46,7 +46,9 @@ Changelog :class:`~cryptography.hazmat.primitives.kdf.kbkdf.KBKDFCMAC` now support :attr:`~cryptography.hazmat.primitives.kdf.kbkdf.CounterLocation.MiddleFixed` counter location. - +* Fixed :rfc:`4514` name parsing to reverse the order of the RDNs according + to the section 2.1 of the RFC, affecting method :meth:`~cryptography.x509.Name.from_rfc4514_string` + .. _v37-0-4: 37.0.4 - 2022-07-05 diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index 076606c72..702fb4b21 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -414,13 +414,21 @@ class _RFC4514NameParser: return val def parse(self) -> Name: + """ + Parses the `data` string and converts it to a Name. + + According to RFC4514 section 2.1 the RDNSequence must be + reversed when converting to string representation. So, when + we parse it, we need to reverse again to get the RDNs on the + correct order. + """ rdns = [self._parse_rdn()] while self._has_data(): self._read_char(",") rdns.append(self._parse_rdn()) - return Name(rdns) + return Name(reversed(rdns)) def _parse_rdn(self) -> RelativeDistinguishedName: nas = [self._parse_na()] diff --git a/tests/x509/test_name.py b/tests/x509/test_name.py index f13f875f2..de47a7a1a 100644 --- a/tests/x509/test_name.py +++ b/tests/x509/test_name.py @@ -59,14 +59,7 @@ class TestRFC4514: Name( [ RelativeDistinguishedName( - [ - NameAttribute( - NameOID.ORGANIZATIONAL_UNIT_NAME, "Sales" - ), - NameAttribute( - NameOID.COMMON_NAME, "J. Smith" - ), - ] + [NameAttribute(NameOID.DOMAIN_COMPONENT, "net")] ), RelativeDistinguishedName( [ @@ -76,7 +69,14 @@ class TestRFC4514: ] ), RelativeDistinguishedName( - [NameAttribute(NameOID.DOMAIN_COMPONENT, "net")] + [ + NameAttribute( + NameOID.ORGANIZATIONAL_UNIT_NAME, "Sales" + ), + NameAttribute( + NameOID.COMMON_NAME, "J. Smith" + ), + ] ), ] ), @@ -85,11 +85,11 @@ class TestRFC4514: "CN=cryptography.io,O=PyCA,L=,ST=,C=US", Name( [ - NameAttribute(NameOID.COMMON_NAME, "cryptography.io"), - NameAttribute(NameOID.ORGANIZATION_NAME, "PyCA"), - NameAttribute(NameOID.LOCALITY_NAME, ""), - NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, ""), NameAttribute(NameOID.COUNTRY_NAME, "US"), + NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, ""), + NameAttribute(NameOID.LOCALITY_NAME, ""), + NameAttribute(NameOID.ORGANIZATION_NAME, "PyCA"), + NameAttribute(NameOID.COMMON_NAME, "cryptography.io"), ] ), ), @@ -97,9 +97,9 @@ class TestRFC4514: r"C=US,CN=Joe \, Smith,DC=example", Name( [ - NameAttribute(NameOID.COUNTRY_NAME, "US"), - NameAttribute(NameOID.COMMON_NAME, "Joe , Smith"), NameAttribute(NameOID.DOMAIN_COMPONENT, "example"), + NameAttribute(NameOID.COMMON_NAME, "Joe , Smith"), + NameAttribute(NameOID.COUNTRY_NAME, "US"), ] ), ), @@ -107,9 +107,9 @@ class TestRFC4514: r"C=US,CN=Jane \"J\,S\" Smith,DC=example", Name( [ - NameAttribute(NameOID.COUNTRY_NAME, "US"), - NameAttribute(NameOID.COMMON_NAME, 'Jane "J,S" Smith'), NameAttribute(NameOID.DOMAIN_COMPONENT, "example"), + NameAttribute(NameOID.COMMON_NAME, 'Jane "J,S" Smith'), + NameAttribute(NameOID.COUNTRY_NAME, "US"), ] ), ), @@ -117,9 +117,9 @@ class TestRFC4514: 'C=US,CN=\\"Jane J\\,S Smith\\",DC=example', Name( [ - NameAttribute(NameOID.COUNTRY_NAME, "US"), - NameAttribute(NameOID.COMMON_NAME, '"Jane J,S Smith"'), NameAttribute(NameOID.DOMAIN_COMPONENT, "example"), + NameAttribute(NameOID.COMMON_NAME, '"Jane J,S Smith"'), + NameAttribute(NameOID.COUNTRY_NAME, "US"), ] ), ), @@ -127,11 +127,11 @@ class TestRFC4514: 'C=US,CN=\\"Jane \\"J\\,S\\" Smith\\",DC=example', Name( [ - NameAttribute(NameOID.COUNTRY_NAME, "US"), + NameAttribute(NameOID.DOMAIN_COMPONENT, "example"), NameAttribute( NameOID.COMMON_NAME, '"Jane "J,S" Smith"' ), - NameAttribute(NameOID.DOMAIN_COMPONENT, "example"), + NameAttribute(NameOID.COUNTRY_NAME, "US"), ] ), ), @@ -139,9 +139,9 @@ class TestRFC4514: r"C=US,CN=Jane=Smith,DC=example", Name( [ - NameAttribute(NameOID.COUNTRY_NAME, "US"), - NameAttribute(NameOID.COMMON_NAME, "Jane=Smith"), NameAttribute(NameOID.DOMAIN_COMPONENT, "example"), + NameAttribute(NameOID.COMMON_NAME, "Jane=Smith"), + NameAttribute(NameOID.COUNTRY_NAME, "US"), ] ), ), @@ -170,8 +170,8 @@ class TestRFC4514: "CN=Santa Claus,E=santa@north.pole", {"E": NameOID.EMAIL_ADDRESS} ) == Name( [ - NameAttribute(NameOID.COMMON_NAME, "Santa Claus"), NameAttribute(NameOID.EMAIL_ADDRESS, "santa@north.pole"), + NameAttribute(NameOID.COMMON_NAME, "Santa Claus"), ] ) @@ -182,3 +182,24 @@ class TestRFC4514: NameAttribute(NameOID.EMAIL_ADDRESS, "Santa Claus"), ] ) + + def test_generate_parse(self): + name_value = Name( + [ + NameAttribute(NameOID.COMMON_NAME, "Common Name 1"), + NameAttribute(NameOID.LOCALITY_NAME, "City for Name 1"), + NameAttribute( + NameOID.ORGANIZATION_NAME, "Name 1 Organization" + ), + ] + ) + + assert ( + Name.from_rfc4514_string(name_value.rfc4514_string()) == name_value + ) + + name_string = "O=Organization,L=City,CN=Common Name" + assert ( + Name.from_rfc4514_string(name_string).rfc4514_string() + == name_string + )