Make DistributionPoint relative_name a set of NameAttribute (#3210)

* Add RelativeDistinguishedName class

* Make relative_name a RelativeDistinguishedName

DistributionPoint relative_name is currently a Name but RFC 5280
defines it as RelativeDistinguishedName, i.e. a non-empty SET OF
name attributes.  Change the DistributionPoint relative_name
attribute to be a RelativeDistinguishedName.
diff --git a/tests/test_x509.py b/tests/test_x509.py
index d3b24ec..67df30c 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -1895,7 +1895,7 @@
             x509.CRLDistributionPoints([
                 x509.DistributionPoint(
                     full_name=None,
-                    relative_name=x509.Name([
+                    relative_name=x509.RelativeDistinguishedName([
                         x509.NameAttribute(
                             NameOID.COMMON_NAME,
                             u"indirect CRL for indirectCRL CA3"
@@ -3604,6 +3604,77 @@
             )
 
 
+class TestRelativeDistinguishedName(object):
+    def test_init_empty(self):
+        with pytest.raises(ValueError):
+            x509.RelativeDistinguishedName([])
+
+    def test_init_not_nameattribute(self):
+        with pytest.raises(TypeError):
+            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
+
+    def test_hash(self):
+        rdn1 = x509.RelativeDistinguishedName([
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2'),
+        ])
+        rdn2 = x509.RelativeDistinguishedName([
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
+        ])
+        rdn3 = x509.RelativeDistinguishedName([
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value3'),
+        ])
+        assert hash(rdn1) == hash(rdn2)
+        assert hash(rdn1) != hash(rdn3)
+
+    def test_eq(self):
+        rdn1 = x509.RelativeDistinguishedName([
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2'),
+        ])
+        rdn2 = x509.RelativeDistinguishedName([
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
+        ])
+        assert rdn1 == rdn2
+
+    def test_ne(self):
+        rdn1 = x509.RelativeDistinguishedName([
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2'),
+        ])
+        rdn2 = x509.RelativeDistinguishedName([
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value3'),
+        ])
+        assert rdn1 != rdn2
+        assert rdn1 != object()
+
+    def test_iter_input(self):
+        attrs = [
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1')
+        ]
+        rdn = x509.RelativeDistinguishedName(iter(attrs))
+        assert list(rdn) == attrs
+        assert list(rdn) == attrs
+
+    def test_get_attributes_for_oid(self):
+        oid = x509.ObjectIdentifier('2.999.1')
+        attr = x509.NameAttribute(oid, u'value1')
+        rdn = x509.RelativeDistinguishedName([attr])
+        assert rdn.get_attributes_for_oid(oid) == [attr]
+        assert rdn.get_attributes_for_oid(x509.ObjectIdentifier('1.2.3')) == []
+
+
 class TestObjectIdentifier(object):
     def test_eq(self):
         oid1 = x509.ObjectIdentifier('2.999.1')
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
index 749e52f..7104121 100644
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -3003,6 +3003,17 @@
         with pytest.raises(ValueError):
             x509.DistributionPoint("data", "notname", None, None)
 
+    def test_relative_name_name_value_deprecated(self):
+        with pytest.deprecated_call():
+            x509.DistributionPoint(
+                None,
+                x509.Name([
+                    x509.NameAttribute(NameOID.COMMON_NAME, u"myCN")
+                ]),
+                None,
+                None
+            )
+
     def test_crl_issuer_not_general_names(self):
         with pytest.raises(TypeError):
             x509.DistributionPoint(None, None, None, ["notgn"])
@@ -3127,7 +3138,7 @@
     def test_repr(self):
         dp = x509.DistributionPoint(
             None,
-            x509.Name([
+            x509.RelativeDistinguishedName([
                 x509.NameAttribute(NameOID.COMMON_NAME, u"myCN")
             ]),
             frozenset([x509.ReasonFlags.ca_compromise]),
@@ -3143,21 +3154,23 @@
         )
         if six.PY3:
             assert repr(dp) == (
-                "<DistributionPoint(full_name=None, relative_name=<Name([<Name"
-                "Attribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)"
-                ">, value='myCN')>])>, reasons=frozenset({<ReasonFlags.ca_comp"
-                "romise: 'cACompromise'>}), crl_issuer=[<DirectoryName(value=<"
-                "Name([<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name="
-                "commonName)>, value='Important CA')>])>)>])>"
+                "<DistributionPoint(full_name=None, relative_name=<RelativeDis"
+                "tinguishedName([<NameAttribute(oid=<ObjectIdentifier(oid=2.5."
+                "4.3, name=commonName)>, value='myCN')>])>, reasons=frozenset("
+                "{<ReasonFlags.ca_compromise: 'cACompromise'>}), crl_issuer=[<"
+                "DirectoryName(value=<Name([<NameAttribute(oid=<ObjectIdentifi"
+                "er(oid=2.5.4.3, name=commonName)>, value='Important CA')>])>)"
+                ">])>"
             )
         else:
             assert repr(dp) == (
-                "<DistributionPoint(full_name=None, relative_name=<Name([<Name"
-                "Attribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)"
-                ">, value=u'myCN')>])>, reasons=frozenset([<ReasonFlags.ca_com"
-                "promise: 'cACompromise'>]), crl_issuer=[<DirectoryName(value="
-                "<Name([<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name"
-                "=commonName)>, value=u'Important CA')>])>)>])>"
+                "<DistributionPoint(full_name=None, relative_name=<RelativeDis"
+                "tinguishedName([<NameAttribute(oid=<ObjectIdentifier(oid=2.5."
+                "4.3, name=commonName)>, value=u'myCN')>])>, reasons=frozenset"
+                "([<ReasonFlags.ca_compromise: 'cACompromise'>]), crl_issuer=["
+                "<DirectoryName(value=<Name([<NameAttribute(oid=<ObjectIdentif"
+                "ier(oid=2.5.4.3, name=commonName)>, value=u'Important CA')>])"
+                ">)>])>"
             )
 
 
@@ -3407,7 +3420,7 @@
         assert cdps == x509.CRLDistributionPoints([
             x509.DistributionPoint(
                 full_name=None,
-                relative_name=x509.Name([
+                relative_name=x509.RelativeDistinguishedName([
                     x509.NameAttribute(
                         NameOID.COMMON_NAME,
                         u"indirect CRL for indirectCRL CA3"