aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst3
-rw-r--r--docs/x509/reference.rst5
-rw-r--r--src/cryptography/x509/name.py11
-rw-r--r--tests/x509/test_x509.py15
4 files changed, 23 insertions, 11 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index c3a415c3..70be0520 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -16,6 +16,9 @@ Changelog
``cryptography`` release.
* Fixed multiple issues preventing ``cryptography`` from compiling against
LibreSSL 2.7.x.
+* The :class:`~cryptography.x509.RelativeDistinguishedName` class now
+ preserves the order of attributes. Duplicate attributes now raise an error
+ instead of silently discarding duplicates.
.. _v2-2-2:
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 3fc6507e..64097bf2 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -1117,7 +1117,7 @@ X.509 CSR (Certificate Signing Request) Builder Object
Technically, a Name is a list of *sets* of attributes, called *Relative
Distinguished Names* or *RDNs*, although multi-valued RDNs are rarely
encountered. The iteration order of values within a multi-valued RDN is
- undefined. If you need to handle multi-valued RDNs, the ``rdns`` property
+ preserved. If you need to handle multi-valued RDNs, the ``rdns`` property
gives access to an ordered list of :class:`RelativeDistinguishedName`
objects.
@@ -1203,7 +1203,8 @@ X.509 CSR (Certificate Signing Request) Builder Object
.. versionadded:: 1.6
A relative distinguished name is a non-empty set of name attributes. The
- object is iterable to get every attribute.
+ object is iterable to get every attribute, preserving the original order.
+ Passing duplicate attributes to the constructor raises ``ValueError``.
.. method:: get_attributes_for_oid(oid)
diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py
index 0daa8bbd..5548eda8 100644
--- a/src/cryptography/x509/name.py
+++ b/src/cryptography/x509/name.py
@@ -101,13 +101,18 @@ class NameAttribute(object):
class RelativeDistinguishedName(object):
def __init__(self, attributes):
- attributes = frozenset(attributes)
+ attributes = list(attributes)
if not attributes:
raise ValueError("a relative distinguished name cannot be empty")
if not all(isinstance(x, NameAttribute) for x in attributes):
raise TypeError("attributes must be an iterable of NameAttribute")
+ # Keep list and frozenset to preserve attribute order where it matters
self._attributes = attributes
+ self._attribute_set = frozenset(attributes)
+
+ if len(self._attribute_set) != len(attributes):
+ raise ValueError("duplicate attributes are not allowed")
def get_attributes_for_oid(self, oid):
return [i for i in self if i.oid == oid]
@@ -116,13 +121,13 @@ class RelativeDistinguishedName(object):
if not isinstance(other, RelativeDistinguishedName):
return NotImplemented
- return self._attributes == other._attributes
+ return self._attribute_set == other._attribute_set
def __ne__(self, other):
return not self == other
def __hash__(self):
- return hash(self._attributes)
+ return hash(self._attribute_set)
def __iter__(self):
return iter(self._attributes)
diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py
index 335a0fbf..7f9f1830 100644
--- a/tests/x509/test_x509.py
+++ b/tests/x509/test_x509.py
@@ -3886,11 +3886,11 @@ class TestRelativeDistinguishedName(object):
x509.RelativeDistinguishedName(["not-a-NameAttribute"])
def test_init_duplicate_attribute(self):
- rdn = x509.RelativeDistinguishedName([
- x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
- x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
- ])
- assert len(rdn) == 1
+ with pytest.raises(ValueError):
+ x509.RelativeDistinguishedName([
+ x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'val1'),
+ x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'val1'),
+ ])
def test_hash(self):
rdn1 = x509.RelativeDistinguishedName([
@@ -3932,8 +3932,11 @@ class TestRelativeDistinguishedName(object):
assert rdn1 != object()
def test_iter_input(self):
+ # Order must be preserved too
attrs = [
- x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1')
+ x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
+ x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value2'),
+ x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value3')
]
rdn = x509.RelativeDistinguishedName(iter(attrs))
assert list(rdn) == attrs