Make RelativeDistinguishedName preserve attribtue order (#4306)

Duplicate attributes now raise an error instead of silently discarding
duplicates.
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index c3a415c..70be052 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -16,6 +16,9 @@
   ``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 3fc6507..64097bf 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -1117,7 +1117,7 @@
     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 @@
     .. 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 0daa8bb..5548eda 100644
--- a/src/cryptography/x509/name.py
+++ b/src/cryptography/x509/name.py
@@ -101,13 +101,18 @@
 
 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 @@
         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 335a0fb..7f9f183 100644
--- a/tests/x509/test_x509.py
+++ b/tests/x509/test_x509.py
@@ -3886,11 +3886,11 @@
             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 @@
         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