We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
X.509 OID 2.5.4.45 cannot be read because it's a bit string, not text
\_\_repr\_\_ of the certificate object for the attached X.509 certificate fails with the exception
      ValueError: Unsupported ASN1 string type. Type: 3

I tracked it down to OID 2.5.4.45, which is of type "BIT STRING (64 bit)", according to https://lapo.it/asn1js/, which is the correct type for the OID if we are to believe http://www.alvestrand.no/objectid/2.5.4.45.html.

It looks like 'cryptography' is insisting name attributes must be text, and using decode_asn._asn1_string_to_utf8 accordingly, but in this case there is no text conversion and decode_asn1._asn1_string_to_bytes should have been used instead.

Attached, [sup_ds.zip](https://github.com/pyca/cryptography/files/1004488/sup_ds.zip) containing:
sup_ds.crt: A sample offending certificate.
sup_ds.py: Reproducing code.
sup_ds.out: Traceback when run against cryptography 1.8.1, openssl 1.1.0e.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/cryptography/x509/name.py`
Content:
```
1 # This file is dual licensed under the terms of the Apache License, Version
2 # 2.0, and the BSD License. See the LICENSE file in the root of this repository
3 # for complete details.
4 
5 import typing
6 import warnings
7 
8 from cryptography import utils
9 from cryptography.hazmat.bindings._rust import (
10     x509 as rust_x509,
11 )
12 from cryptography.x509.oid import NameOID, ObjectIdentifier
13 
14 
15 class _ASN1Type(utils.Enum):
16     UTF8String = 12
17     NumericString = 18
18     PrintableString = 19
19     T61String = 20
20     IA5String = 22
21     UTCTime = 23
22     GeneralizedTime = 24
23     VisibleString = 26
24     UniversalString = 28
25     BMPString = 30
26 
27 
28 _ASN1_TYPE_TO_ENUM = {i.value: i for i in _ASN1Type}
29 _SENTINEL = object()
30 _NAMEOID_DEFAULT_TYPE = {
31     NameOID.COUNTRY_NAME: _ASN1Type.PrintableString,
32     NameOID.JURISDICTION_COUNTRY_NAME: _ASN1Type.PrintableString,
33     NameOID.SERIAL_NUMBER: _ASN1Type.PrintableString,
34     NameOID.DN_QUALIFIER: _ASN1Type.PrintableString,
35     NameOID.EMAIL_ADDRESS: _ASN1Type.IA5String,
36     NameOID.DOMAIN_COMPONENT: _ASN1Type.IA5String,
37 }
38 
39 # Type alias
40 _OidNameMap = typing.Mapping[ObjectIdentifier, str]
41 
42 #: Short attribute names from RFC 4514:
43 #: https://tools.ietf.org/html/rfc4514#page-7
44 _NAMEOID_TO_NAME: _OidNameMap = {
45     NameOID.COMMON_NAME: "CN",
46     NameOID.LOCALITY_NAME: "L",
47     NameOID.STATE_OR_PROVINCE_NAME: "ST",
48     NameOID.ORGANIZATION_NAME: "O",
49     NameOID.ORGANIZATIONAL_UNIT_NAME: "OU",
50     NameOID.COUNTRY_NAME: "C",
51     NameOID.STREET_ADDRESS: "STREET",
52     NameOID.DOMAIN_COMPONENT: "DC",
53     NameOID.USER_ID: "UID",
54 }
55 
56 
57 def _escape_dn_value(val: str) -> str:
58     """Escape special characters in RFC4514 Distinguished Name value."""
59 
60     if not val:
61         return ""
62 
63     # See https://tools.ietf.org/html/rfc4514#section-2.4
64     val = val.replace("\\", "\\\\")
65     val = val.replace('"', '\\"')
66     val = val.replace("+", "\\+")
67     val = val.replace(",", "\\,")
68     val = val.replace(";", "\\;")
69     val = val.replace("<", "\\<")
70     val = val.replace(">", "\\>")
71     val = val.replace("\0", "\\00")
72 
73     if val[0] in ("#", " "):
74         val = "\\" + val
75     if val[-1] == " ":
76         val = val[:-1] + "\\ "
77 
78     return val
79 
80 
81 class NameAttribute(object):
82     def __init__(
83         self,
84         oid: ObjectIdentifier,
85         value: str,
86         _type=_SENTINEL,
87         *,
88         _validate=True,
89     ) -> None:
90         if not isinstance(oid, ObjectIdentifier):
91             raise TypeError(
92                 "oid argument must be an ObjectIdentifier instance."
93             )
94 
95         if not isinstance(value, str):
96             raise TypeError("value argument must be a str.")
97 
98         if (
99             oid == NameOID.COUNTRY_NAME
100             or oid == NameOID.JURISDICTION_COUNTRY_NAME
101         ):
102             c_len = len(value.encode("utf8"))
103             if c_len != 2 and _validate is True:
104                 raise ValueError(
105                     "Country name must be a 2 character country code"
106                 )
107             elif c_len != 2:
108                 warnings.warn(
109                     "Country names should be two characters, but the "
110                     "attribute is {} characters in length.".format(c_len),
111                     stacklevel=2,
112                 )
113 
114         # The appropriate ASN1 string type varies by OID and is defined across
115         # multiple RFCs including 2459, 3280, and 5280. In general UTF8String
116         # is preferred (2459), but 3280 and 5280 specify several OIDs with
117         # alternate types. This means when we see the sentinel value we need
118         # to look up whether the OID has a non-UTF8 type. If it does, set it
119         # to that. Otherwise, UTF8!
120         if _type == _SENTINEL:
121             _type = _NAMEOID_DEFAULT_TYPE.get(oid, _ASN1Type.UTF8String)
122 
123         if not isinstance(_type, _ASN1Type):
124             raise TypeError("_type must be from the _ASN1Type enum")
125 
126         self._oid = oid
127         self._value = value
128         self._type = _type
129 
130     @property
131     def oid(self) -> ObjectIdentifier:
132         return self._oid
133 
134     @property
135     def value(self) -> str:
136         return self._value
137 
138     @property
139     def rfc4514_attribute_name(self) -> str:
140         """
141         The short attribute name (for example "CN") if available,
142         otherwise the OID dotted string.
143         """
144         return _NAMEOID_TO_NAME.get(self.oid, self.oid.dotted_string)
145 
146     def rfc4514_string(
147         self, attr_name_overrides: typing.Optional[_OidNameMap] = None
148     ) -> str:
149         """
150         Format as RFC4514 Distinguished Name string.
151 
152         Use short attribute name if available, otherwise fall back to OID
153         dotted string.
154         """
155         attr_name = (
156             attr_name_overrides.get(self.oid) if attr_name_overrides else None
157         )
158         if attr_name is None:
159             attr_name = self.rfc4514_attribute_name
160 
161         return "%s=%s" % (attr_name, _escape_dn_value(self.value))
162 
163     def __eq__(self, other: object) -> bool:
164         if not isinstance(other, NameAttribute):
165             return NotImplemented
166 
167         return self.oid == other.oid and self.value == other.value
168 
169     def __ne__(self, other: object) -> bool:
170         return not self == other
171 
172     def __hash__(self) -> int:
173         return hash((self.oid, self.value))
174 
175     def __repr__(self) -> str:
176         return "<NameAttribute(oid={0.oid}, value={0.value!r})>".format(self)
177 
178 
179 class RelativeDistinguishedName(object):
180     def __init__(self, attributes: typing.Iterable[NameAttribute]):
181         attributes = list(attributes)
182         if not attributes:
183             raise ValueError("a relative distinguished name cannot be empty")
184         if not all(isinstance(x, NameAttribute) for x in attributes):
185             raise TypeError("attributes must be an iterable of NameAttribute")
186 
187         # Keep list and frozenset to preserve attribute order where it matters
188         self._attributes = attributes
189         self._attribute_set = frozenset(attributes)
190 
191         if len(self._attribute_set) != len(attributes):
192             raise ValueError("duplicate attributes are not allowed")
193 
194     def get_attributes_for_oid(
195         self, oid: ObjectIdentifier
196     ) -> typing.List[NameAttribute]:
197         return [i for i in self if i.oid == oid]
198 
199     def rfc4514_string(
200         self, attr_name_overrides: typing.Optional[_OidNameMap] = None
201     ) -> str:
202         """
203         Format as RFC4514 Distinguished Name string.
204 
205         Within each RDN, attributes are joined by '+', although that is rarely
206         used in certificates.
207         """
208         return "+".join(
209             attr.rfc4514_string(attr_name_overrides)
210             for attr in self._attributes
211         )
212 
213     def __eq__(self, other: object) -> bool:
214         if not isinstance(other, RelativeDistinguishedName):
215             return NotImplemented
216 
217         return self._attribute_set == other._attribute_set
218 
219     def __ne__(self, other: object) -> bool:
220         return not self == other
221 
222     def __hash__(self) -> int:
223         return hash(self._attribute_set)
224 
225     def __iter__(self) -> typing.Iterator[NameAttribute]:
226         return iter(self._attributes)
227 
228     def __len__(self) -> int:
229         return len(self._attributes)
230 
231     def __repr__(self) -> str:
232         return "<RelativeDistinguishedName({})>".format(self.rfc4514_string())
233 
234 
235 class Name(object):
236     @typing.overload
237     def __init__(self, attributes: typing.Iterable[NameAttribute]) -> None:
238         ...
239 
240     @typing.overload
241     def __init__(
242         self, attributes: typing.Iterable[RelativeDistinguishedName]
243     ) -> None:
244         ...
245 
246     def __init__(
247         self,
248         attributes: typing.Iterable[
249             typing.Union[NameAttribute, RelativeDistinguishedName]
250         ],
251     ) -> None:
252         attributes = list(attributes)
253         if all(isinstance(x, NameAttribute) for x in attributes):
254             self._attributes = [
255                 RelativeDistinguishedName([typing.cast(NameAttribute, x)])
256                 for x in attributes
257             ]
258         elif all(isinstance(x, RelativeDistinguishedName) for x in attributes):
259             self._attributes = typing.cast(
260                 typing.List[RelativeDistinguishedName], attributes
261             )
262         else:
263             raise TypeError(
264                 "attributes must be a list of NameAttribute"
265                 " or a list RelativeDistinguishedName"
266             )
267 
268     def rfc4514_string(
269         self, attr_name_overrides: typing.Optional[_OidNameMap] = None
270     ) -> str:
271         """
272         Format as RFC4514 Distinguished Name string.
273         For example 'CN=foobar.com,O=Foo Corp,C=US'
274 
275         An X.509 name is a two-level structure: a list of sets of attributes.
276         Each list element is separated by ',' and within each list element, set
277         elements are separated by '+'. The latter is almost never used in
278         real world certificates. According to RFC4514 section 2.1 the
279         RDNSequence must be reversed when converting to string representation.
280         """
281         return ",".join(
282             attr.rfc4514_string(attr_name_overrides)
283             for attr in reversed(self._attributes)
284         )
285 
286     def get_attributes_for_oid(
287         self, oid: ObjectIdentifier
288     ) -> typing.List[NameAttribute]:
289         return [i for i in self if i.oid == oid]
290 
291     @property
292     def rdns(self) -> typing.List[RelativeDistinguishedName]:
293         return self._attributes
294 
295     def public_bytes(self, backend: typing.Any = None) -> bytes:
296         return rust_x509.encode_name_bytes(self)
297 
298     def __eq__(self, other: object) -> bool:
299         if not isinstance(other, Name):
300             return NotImplemented
301 
302         return self._attributes == other._attributes
303 
304     def __ne__(self, other: object) -> bool:
305         return not self == other
306 
307     def __hash__(self) -> int:
308         # TODO: this is relatively expensive, if this looks like a bottleneck
309         # for you, consider optimizing!
310         return hash(tuple(self._attributes))
311 
312     def __iter__(self) -> typing.Iterator[NameAttribute]:
313         for rdn in self._attributes:
314             for ava in rdn:
315                 yield ava
316 
317     def __len__(self) -> int:
318         return sum(len(rdn) for rdn in self._attributes)
319 
320     def __repr__(self) -> str:
321         rdns = ",".join(attr.rfc4514_string() for attr in self._attributes)
322         return "<Name({})>".format(rdns)
323
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py
--- a/src/cryptography/x509/name.py
+++ b/src/cryptography/x509/name.py
@@ -2,6 +2,7 @@
 # 2.0, and the BSD License. See the LICENSE file in the root of this repository
 # for complete details.
 
+import binascii
 import typing
 import warnings
 
@@ -13,6 +14,7 @@
 
 
 class _ASN1Type(utils.Enum):
+    BitString = 3
     UTF8String = 12
     NumericString = 18
     PrintableString = 19
@@ -54,12 +56,17 @@
 }
 
 
-def _escape_dn_value(val: str) -> str:
+def _escape_dn_value(val: typing.Union[str, bytes]) -> str:
     """Escape special characters in RFC4514 Distinguished Name value."""
 
     if not val:
         return ""
 
+    # RFC 4514 Section 2.4 defines the value as being the # (U+0023) character
+    # followed by the hexadecimal encoding of the octets.
+    if isinstance(val, bytes):
+        return "#" + binascii.hexlify(val).decode("utf8")
+
     # See https://tools.ietf.org/html/rfc4514#section-2.4
     val = val.replace("\\", "\\\\")
     val = val.replace('"', '\\"')
@@ -82,7 +89,7 @@
     def __init__(
         self,
         oid: ObjectIdentifier,
-        value: str,
+        value: typing.Union[str, bytes],
         _type=_SENTINEL,
         *,
         _validate=True,
@@ -91,14 +98,22 @@
             raise TypeError(
                 "oid argument must be an ObjectIdentifier instance."
             )
-
-        if not isinstance(value, str):
-            raise TypeError("value argument must be a str.")
+        if _type == _ASN1Type.BitString:
+            if oid != NameOID.X500_UNIQUE_IDENTIFIER:
+                raise TypeError(
+                    "oid must be X500_UNIQUE_IDENTIFIER for BitString type."
+                )
+            if not isinstance(value, bytes):
+                raise TypeError("value must be bytes for BitString")
+        else:
+            if not isinstance(value, str):
+                raise TypeError("value argument must be a str")
 
         if (
             oid == NameOID.COUNTRY_NAME
             or oid == NameOID.JURISDICTION_COUNTRY_NAME
         ):
+            assert isinstance(value, str)
             c_len = len(value.encode("utf8"))
             if c_len != 2 and _validate is True:
                 raise ValueError(
@@ -132,7 +147,7 @@
         return self._oid
 
     @property
-    def value(self) -> str:
+    def value(self) -> typing.Union[str, bytes]:
         return self._value
 
     @property

{"golden_diff": "diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py\n--- a/src/cryptography/x509/name.py\n+++ b/src/cryptography/x509/name.py\n@@ -2,6 +2,7 @@\n # 2.0, and the BSD License. See the LICENSE file in the root of this repository\n # for complete details.\n \n+import binascii\n import typing\n import warnings\n \n@@ -13,6 +14,7 @@\n \n \n class _ASN1Type(utils.Enum):\n+    BitString = 3\n     UTF8String = 12\n     NumericString = 18\n     PrintableString = 19\n@@ -54,12 +56,17 @@\n }\n \n \n-def _escape_dn_value(val: str) -> str:\n+def _escape_dn_value(val: typing.Union[str, bytes]) -> str:\n     \"\"\"Escape special characters in RFC4514 Distinguished Name value.\"\"\"\n \n     if not val:\n         return \"\"\n \n+    # RFC 4514 Section 2.4 defines the value as being the # (U+0023) character\n+    # followed by the hexadecimal encoding of the octets.\n+    if isinstance(val, bytes):\n+        return \"#\" + binascii.hexlify(val).decode(\"utf8\")\n+\n     # See https://tools.ietf.org/html/rfc4514#section-2.4\n     val = val.replace(\"\\\\\", \"\\\\\\\\\")\n     val = val.replace('\"', '\\\\\"')\n@@ -82,7 +89,7 @@\n     def __init__(\n         self,\n         oid: ObjectIdentifier,\n-        value: str,\n+        value: typing.Union[str, bytes],\n         _type=_SENTINEL,\n         *,\n         _validate=True,\n@@ -91,14 +98,22 @@\n             raise TypeError(\n                 \"oid argument must be an ObjectIdentifier instance.\"\n             )\n-\n-        if not isinstance(value, str):\n-            raise TypeError(\"value argument must be a str.\")\n+        if _type == _ASN1Type.BitString:\n+            if oid != NameOID.X500_UNIQUE_IDENTIFIER:\n+                raise TypeError(\n+                    \"oid must be X500_UNIQUE_IDENTIFIER for BitString type.\"\n+                )\n+            if not isinstance(value, bytes):\n+                raise TypeError(\"value must be bytes for BitString\")\n+        else:\n+            if not isinstance(value, str):\n+                raise TypeError(\"value argument must be a str\")\n \n         if (\n             oid == NameOID.COUNTRY_NAME\n             or oid == NameOID.JURISDICTION_COUNTRY_NAME\n         ):\n+            assert isinstance(value, str)\n             c_len = len(value.encode(\"utf8\"))\n             if c_len != 2 and _validate is True:\n                 raise ValueError(\n@@ -132,7 +147,7 @@\n         return self._oid\n \n     @property\n-    def value(self) -> str:\n+    def value(self) -> typing.Union[str, bytes]:\n         return self._value\n \n     @property\n", "issue": "X.509 OID 2.5.4.45 cannot be read because it's a bit string, not text\n\\_\\_repr\\_\\_ of the certificate object for the attached X.509 certificate fails with the exception\r\n      ValueError: Unsupported ASN1 string type. Type: 3\r\n\r\nI tracked it down to OID 2.5.4.45, which is of type \"BIT STRING (64 bit)\", according to https://lapo.it/asn1js/, which is the correct type for the OID if we are to believe http://www.alvestrand.no/objectid/2.5.4.45.html.\r\n\r\nIt looks like 'cryptography' is insisting name attributes must be text, and using decode_asn._asn1_string_to_utf8 accordingly, but in this case there is no text conversion and decode_asn1._asn1_string_to_bytes should have been used instead.\r\n\r\nAttached, [sup_ds.zip](https://github.com/pyca/cryptography/files/1004488/sup_ds.zip) containing:\r\nsup_ds.crt: A sample offending certificate.\r\nsup_ds.py: Reproducing code.\r\nsup_ds.out: Traceback when run against cryptography 1.8.1, openssl 1.1.0e.\n", "before_files": [{"content": "# This file is dual licensed under the terms of the Apache License, Version\n# 2.0, and the BSD License. See the LICENSE file in the root of this repository\n# for complete details.\n\nimport typing\nimport warnings\n\nfrom cryptography import utils\nfrom cryptography.hazmat.bindings._rust import (\n    x509 as rust_x509,\n)\nfrom cryptography.x509.oid import NameOID, ObjectIdentifier\n\n\nclass _ASN1Type(utils.Enum):\n    UTF8String = 12\n    NumericString = 18\n    PrintableString = 19\n    T61String = 20\n    IA5String = 22\n    UTCTime = 23\n    GeneralizedTime = 24\n    VisibleString = 26\n    UniversalString = 28\n    BMPString = 30\n\n\n_ASN1_TYPE_TO_ENUM = {i.value: i for i in _ASN1Type}\n_SENTINEL = object()\n_NAMEOID_DEFAULT_TYPE = {\n    NameOID.COUNTRY_NAME: _ASN1Type.PrintableString,\n    NameOID.JURISDICTION_COUNTRY_NAME: _ASN1Type.PrintableString,\n    NameOID.SERIAL_NUMBER: _ASN1Type.PrintableString,\n    NameOID.DN_QUALIFIER: _ASN1Type.PrintableString,\n    NameOID.EMAIL_ADDRESS: _ASN1Type.IA5String,\n    NameOID.DOMAIN_COMPONENT: _ASN1Type.IA5String,\n}\n\n# Type alias\n_OidNameMap = typing.Mapping[ObjectIdentifier, str]\n\n#: Short attribute names from RFC 4514:\n#: https://tools.ietf.org/html/rfc4514#page-7\n_NAMEOID_TO_NAME: _OidNameMap = {\n    NameOID.COMMON_NAME: \"CN\",\n    NameOID.LOCALITY_NAME: \"L\",\n    NameOID.STATE_OR_PROVINCE_NAME: \"ST\",\n    NameOID.ORGANIZATION_NAME: \"O\",\n    NameOID.ORGANIZATIONAL_UNIT_NAME: \"OU\",\n    NameOID.COUNTRY_NAME: \"C\",\n    NameOID.STREET_ADDRESS: \"STREET\",\n    NameOID.DOMAIN_COMPONENT: \"DC\",\n    NameOID.USER_ID: \"UID\",\n}\n\n\ndef _escape_dn_value(val: str) -> str:\n    \"\"\"Escape special characters in RFC4514 Distinguished Name value.\"\"\"\n\n    if not val:\n        return \"\"\n\n    # See https://tools.ietf.org/html/rfc4514#section-2.4\n    val = val.replace(\"\\\\\", \"\\\\\\\\\")\n    val = val.replace('\"', '\\\\\"')\n    val = val.replace(\"+\", \"\\\\+\")\n    val = val.replace(\",\", \"\\\\,\")\n    val = val.replace(\";\", \"\\\\;\")\n    val = val.replace(\"<\", \"\\\\<\")\n    val = val.replace(\">\", \"\\\\>\")\n    val = val.replace(\"\\0\", \"\\\\00\")\n\n    if val[0] in (\"#\", \" \"):\n        val = \"\\\\\" + val\n    if val[-1] == \" \":\n        val = val[:-1] + \"\\\\ \"\n\n    return val\n\n\nclass NameAttribute(object):\n    def __init__(\n        self,\n        oid: ObjectIdentifier,\n        value: str,\n        _type=_SENTINEL,\n        *,\n        _validate=True,\n    ) -> None:\n        if not isinstance(oid, ObjectIdentifier):\n            raise TypeError(\n                \"oid argument must be an ObjectIdentifier instance.\"\n            )\n\n        if not isinstance(value, str):\n            raise TypeError(\"value argument must be a str.\")\n\n        if (\n            oid == NameOID.COUNTRY_NAME\n            or oid == NameOID.JURISDICTION_COUNTRY_NAME\n        ):\n            c_len = len(value.encode(\"utf8\"))\n            if c_len != 2 and _validate is True:\n                raise ValueError(\n                    \"Country name must be a 2 character country code\"\n                )\n            elif c_len != 2:\n                warnings.warn(\n                    \"Country names should be two characters, but the \"\n                    \"attribute is {} characters in length.\".format(c_len),\n                    stacklevel=2,\n                )\n\n        # The appropriate ASN1 string type varies by OID and is defined across\n        # multiple RFCs including 2459, 3280, and 5280. In general UTF8String\n        # is preferred (2459), but 3280 and 5280 specify several OIDs with\n        # alternate types. This means when we see the sentinel value we need\n        # to look up whether the OID has a non-UTF8 type. If it does, set it\n        # to that. Otherwise, UTF8!\n        if _type == _SENTINEL:\n            _type = _NAMEOID_DEFAULT_TYPE.get(oid, _ASN1Type.UTF8String)\n\n        if not isinstance(_type, _ASN1Type):\n            raise TypeError(\"_type must be from the _ASN1Type enum\")\n\n        self._oid = oid\n        self._value = value\n        self._type = _type\n\n    @property\n    def oid(self) -> ObjectIdentifier:\n        return self._oid\n\n    @property\n    def value(self) -> str:\n        return self._value\n\n    @property\n    def rfc4514_attribute_name(self) -> str:\n        \"\"\"\n        The short attribute name (for example \"CN\") if available,\n        otherwise the OID dotted string.\n        \"\"\"\n        return _NAMEOID_TO_NAME.get(self.oid, self.oid.dotted_string)\n\n    def rfc4514_string(\n        self, attr_name_overrides: typing.Optional[_OidNameMap] = None\n    ) -> str:\n        \"\"\"\n        Format as RFC4514 Distinguished Name string.\n\n        Use short attribute name if available, otherwise fall back to OID\n        dotted string.\n        \"\"\"\n        attr_name = (\n            attr_name_overrides.get(self.oid) if attr_name_overrides else None\n        )\n        if attr_name is None:\n            attr_name = self.rfc4514_attribute_name\n\n        return \"%s=%s\" % (attr_name, _escape_dn_value(self.value))\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, NameAttribute):\n            return NotImplemented\n\n        return self.oid == other.oid and self.value == other.value\n\n    def __ne__(self, other: object) -> bool:\n        return not self == other\n\n    def __hash__(self) -> int:\n        return hash((self.oid, self.value))\n\n    def __repr__(self) -> str:\n        return \"<NameAttribute(oid={0.oid}, value={0.value!r})>\".format(self)\n\n\nclass RelativeDistinguishedName(object):\n    def __init__(self, attributes: typing.Iterable[NameAttribute]):\n        attributes = list(attributes)\n        if not attributes:\n            raise ValueError(\"a relative distinguished name cannot be empty\")\n        if not all(isinstance(x, NameAttribute) for x in attributes):\n            raise TypeError(\"attributes must be an iterable of NameAttribute\")\n\n        # Keep list and frozenset to preserve attribute order where it matters\n        self._attributes = attributes\n        self._attribute_set = frozenset(attributes)\n\n        if len(self._attribute_set) != len(attributes):\n            raise ValueError(\"duplicate attributes are not allowed\")\n\n    def get_attributes_for_oid(\n        self, oid: ObjectIdentifier\n    ) -> typing.List[NameAttribute]:\n        return [i for i in self if i.oid == oid]\n\n    def rfc4514_string(\n        self, attr_name_overrides: typing.Optional[_OidNameMap] = None\n    ) -> str:\n        \"\"\"\n        Format as RFC4514 Distinguished Name string.\n\n        Within each RDN, attributes are joined by '+', although that is rarely\n        used in certificates.\n        \"\"\"\n        return \"+\".join(\n            attr.rfc4514_string(attr_name_overrides)\n            for attr in self._attributes\n        )\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, RelativeDistinguishedName):\n            return NotImplemented\n\n        return self._attribute_set == other._attribute_set\n\n    def __ne__(self, other: object) -> bool:\n        return not self == other\n\n    def __hash__(self) -> int:\n        return hash(self._attribute_set)\n\n    def __iter__(self) -> typing.Iterator[NameAttribute]:\n        return iter(self._attributes)\n\n    def __len__(self) -> int:\n        return len(self._attributes)\n\n    def __repr__(self) -> str:\n        return \"<RelativeDistinguishedName({})>\".format(self.rfc4514_string())\n\n\nclass Name(object):\n    @typing.overload\n    def __init__(self, attributes: typing.Iterable[NameAttribute]) -> None:\n        ...\n\n    @typing.overload\n    def __init__(\n        self, attributes: typing.Iterable[RelativeDistinguishedName]\n    ) -> None:\n        ...\n\n    def __init__(\n        self,\n        attributes: typing.Iterable[\n            typing.Union[NameAttribute, RelativeDistinguishedName]\n        ],\n    ) -> None:\n        attributes = list(attributes)\n        if all(isinstance(x, NameAttribute) for x in attributes):\n            self._attributes = [\n                RelativeDistinguishedName([typing.cast(NameAttribute, x)])\n                for x in attributes\n            ]\n        elif all(isinstance(x, RelativeDistinguishedName) for x in attributes):\n            self._attributes = typing.cast(\n                typing.List[RelativeDistinguishedName], attributes\n            )\n        else:\n            raise TypeError(\n                \"attributes must be a list of NameAttribute\"\n                \" or a list RelativeDistinguishedName\"\n            )\n\n    def rfc4514_string(\n        self, attr_name_overrides: typing.Optional[_OidNameMap] = None\n    ) -> str:\n        \"\"\"\n        Format as RFC4514 Distinguished Name string.\n        For example 'CN=foobar.com,O=Foo Corp,C=US'\n\n        An X.509 name is a two-level structure: a list of sets of attributes.\n        Each list element is separated by ',' and within each list element, set\n        elements are separated by '+'. The latter is almost never used in\n        real world certificates. According to RFC4514 section 2.1 the\n        RDNSequence must be reversed when converting to string representation.\n        \"\"\"\n        return \",\".join(\n            attr.rfc4514_string(attr_name_overrides)\n            for attr in reversed(self._attributes)\n        )\n\n    def get_attributes_for_oid(\n        self, oid: ObjectIdentifier\n    ) -> typing.List[NameAttribute]:\n        return [i for i in self if i.oid == oid]\n\n    @property\n    def rdns(self) -> typing.List[RelativeDistinguishedName]:\n        return self._attributes\n\n    def public_bytes(self, backend: typing.Any = None) -> bytes:\n        return rust_x509.encode_name_bytes(self)\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, Name):\n            return NotImplemented\n\n        return self._attributes == other._attributes\n\n    def __ne__(self, other: object) -> bool:\n        return not self == other\n\n    def __hash__(self) -> int:\n        # TODO: this is relatively expensive, if this looks like a bottleneck\n        # for you, consider optimizing!\n        return hash(tuple(self._attributes))\n\n    def __iter__(self) -> typing.Iterator[NameAttribute]:\n        for rdn in self._attributes:\n            for ava in rdn:\n                yield ava\n\n    def __len__(self) -> int:\n        return sum(len(rdn) for rdn in self._attributes)\n\n    def __repr__(self) -> str:\n        rdns = \",\".join(attr.rfc4514_string() for attr in self._attributes)\n        return \"<Name({})>\".format(rdns)\n", "path": "src/cryptography/x509/name.py"}], "after_files": [{"content": "# This file is dual licensed under the terms of the Apache License, Version\n# 2.0, and the BSD License. See the LICENSE file in the root of this repository\n# for complete details.\n\nimport binascii\nimport typing\nimport warnings\n\nfrom cryptography import utils\nfrom cryptography.hazmat.bindings._rust import (\n    x509 as rust_x509,\n)\nfrom cryptography.x509.oid import NameOID, ObjectIdentifier\n\n\nclass _ASN1Type(utils.Enum):\n    BitString = 3\n    UTF8String = 12\n    NumericString = 18\n    PrintableString = 19\n    T61String = 20\n    IA5String = 22\n    UTCTime = 23\n    GeneralizedTime = 24\n    VisibleString = 26\n    UniversalString = 28\n    BMPString = 30\n\n\n_ASN1_TYPE_TO_ENUM = {i.value: i for i in _ASN1Type}\n_SENTINEL = object()\n_NAMEOID_DEFAULT_TYPE = {\n    NameOID.COUNTRY_NAME: _ASN1Type.PrintableString,\n    NameOID.JURISDICTION_COUNTRY_NAME: _ASN1Type.PrintableString,\n    NameOID.SERIAL_NUMBER: _ASN1Type.PrintableString,\n    NameOID.DN_QUALIFIER: _ASN1Type.PrintableString,\n    NameOID.EMAIL_ADDRESS: _ASN1Type.IA5String,\n    NameOID.DOMAIN_COMPONENT: _ASN1Type.IA5String,\n}\n\n# Type alias\n_OidNameMap = typing.Mapping[ObjectIdentifier, str]\n\n#: Short attribute names from RFC 4514:\n#: https://tools.ietf.org/html/rfc4514#page-7\n_NAMEOID_TO_NAME: _OidNameMap = {\n    NameOID.COMMON_NAME: \"CN\",\n    NameOID.LOCALITY_NAME: \"L\",\n    NameOID.STATE_OR_PROVINCE_NAME: \"ST\",\n    NameOID.ORGANIZATION_NAME: \"O\",\n    NameOID.ORGANIZATIONAL_UNIT_NAME: \"OU\",\n    NameOID.COUNTRY_NAME: \"C\",\n    NameOID.STREET_ADDRESS: \"STREET\",\n    NameOID.DOMAIN_COMPONENT: \"DC\",\n    NameOID.USER_ID: \"UID\",\n}\n\n\ndef _escape_dn_value(val: typing.Union[str, bytes]) -> str:\n    \"\"\"Escape special characters in RFC4514 Distinguished Name value.\"\"\"\n\n    if not val:\n        return \"\"\n\n    # RFC 4514 Section 2.4 defines the value as being the # (U+0023) character\n    # followed by the hexadecimal encoding of the octets.\n    if isinstance(val, bytes):\n        return \"#\" + binascii.hexlify(val).decode(\"utf8\")\n\n    # See https://tools.ietf.org/html/rfc4514#section-2.4\n    val = val.replace(\"\\\\\", \"\\\\\\\\\")\n    val = val.replace('\"', '\\\\\"')\n    val = val.replace(\"+\", \"\\\\+\")\n    val = val.replace(\",\", \"\\\\,\")\n    val = val.replace(\";\", \"\\\\;\")\n    val = val.replace(\"<\", \"\\\\<\")\n    val = val.replace(\">\", \"\\\\>\")\n    val = val.replace(\"\\0\", \"\\\\00\")\n\n    if val[0] in (\"#\", \" \"):\n        val = \"\\\\\" + val\n    if val[-1] == \" \":\n        val = val[:-1] + \"\\\\ \"\n\n    return val\n\n\nclass NameAttribute(object):\n    def __init__(\n        self,\n        oid: ObjectIdentifier,\n        value: typing.Union[str, bytes],\n        _type=_SENTINEL,\n        *,\n        _validate=True,\n    ) -> None:\n        if not isinstance(oid, ObjectIdentifier):\n            raise TypeError(\n                \"oid argument must be an ObjectIdentifier instance.\"\n            )\n        if _type == _ASN1Type.BitString:\n            if oid != NameOID.X500_UNIQUE_IDENTIFIER:\n                raise TypeError(\n                    \"oid must be X500_UNIQUE_IDENTIFIER for BitString type.\"\n                )\n            if not isinstance(value, bytes):\n                raise TypeError(\"value must be bytes for BitString\")\n        else:\n            if not isinstance(value, str):\n                raise TypeError(\"value argument must be a str\")\n\n        if (\n            oid == NameOID.COUNTRY_NAME\n            or oid == NameOID.JURISDICTION_COUNTRY_NAME\n        ):\n            assert isinstance(value, str)\n            c_len = len(value.encode(\"utf8\"))\n            if c_len != 2 and _validate is True:\n                raise ValueError(\n                    \"Country name must be a 2 character country code\"\n                )\n            elif c_len != 2:\n                warnings.warn(\n                    \"Country names should be two characters, but the \"\n                    \"attribute is {} characters in length.\".format(c_len),\n                    stacklevel=2,\n                )\n\n        # The appropriate ASN1 string type varies by OID and is defined across\n        # multiple RFCs including 2459, 3280, and 5280. In general UTF8String\n        # is preferred (2459), but 3280 and 5280 specify several OIDs with\n        # alternate types. This means when we see the sentinel value we need\n        # to look up whether the OID has a non-UTF8 type. If it does, set it\n        # to that. Otherwise, UTF8!\n        if _type == _SENTINEL:\n            _type = _NAMEOID_DEFAULT_TYPE.get(oid, _ASN1Type.UTF8String)\n\n        if not isinstance(_type, _ASN1Type):\n            raise TypeError(\"_type must be from the _ASN1Type enum\")\n\n        self._oid = oid\n        self._value = value\n        self._type = _type\n\n    @property\n    def oid(self) -> ObjectIdentifier:\n        return self._oid\n\n    @property\n    def value(self) -> typing.Union[str, bytes]:\n        return self._value\n\n    @property\n    def rfc4514_attribute_name(self) -> str:\n        \"\"\"\n        The short attribute name (for example \"CN\") if available,\n        otherwise the OID dotted string.\n        \"\"\"\n        return _NAMEOID_TO_NAME.get(self.oid, self.oid.dotted_string)\n\n    def rfc4514_string(\n        self, attr_name_overrides: typing.Optional[_OidNameMap] = None\n    ) -> str:\n        \"\"\"\n        Format as RFC4514 Distinguished Name string.\n\n        Use short attribute name if available, otherwise fall back to OID\n        dotted string.\n        \"\"\"\n        attr_name = (\n            attr_name_overrides.get(self.oid) if attr_name_overrides else None\n        )\n        if attr_name is None:\n            attr_name = self.rfc4514_attribute_name\n\n        return \"%s=%s\" % (attr_name, _escape_dn_value(self.value))\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, NameAttribute):\n            return NotImplemented\n\n        return self.oid == other.oid and self.value == other.value\n\n    def __ne__(self, other: object) -> bool:\n        return not self == other\n\n    def __hash__(self) -> int:\n        return hash((self.oid, self.value))\n\n    def __repr__(self) -> str:\n        return \"<NameAttribute(oid={0.oid}, value={0.value!r})>\".format(self)\n\n\nclass RelativeDistinguishedName(object):\n    def __init__(self, attributes: typing.Iterable[NameAttribute]):\n        attributes = list(attributes)\n        if not attributes:\n            raise ValueError(\"a relative distinguished name cannot be empty\")\n        if not all(isinstance(x, NameAttribute) for x in attributes):\n            raise TypeError(\"attributes must be an iterable of NameAttribute\")\n\n        # Keep list and frozenset to preserve attribute order where it matters\n        self._attributes = attributes\n        self._attribute_set = frozenset(attributes)\n\n        if len(self._attribute_set) != len(attributes):\n            raise ValueError(\"duplicate attributes are not allowed\")\n\n    def get_attributes_for_oid(\n        self, oid: ObjectIdentifier\n    ) -> typing.List[NameAttribute]:\n        return [i for i in self if i.oid == oid]\n\n    def rfc4514_string(\n        self, attr_name_overrides: typing.Optional[_OidNameMap] = None\n    ) -> str:\n        \"\"\"\n        Format as RFC4514 Distinguished Name string.\n\n        Within each RDN, attributes are joined by '+', although that is rarely\n        used in certificates.\n        \"\"\"\n        return \"+\".join(\n            attr.rfc4514_string(attr_name_overrides)\n            for attr in self._attributes\n        )\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, RelativeDistinguishedName):\n            return NotImplemented\n\n        return self._attribute_set == other._attribute_set\n\n    def __ne__(self, other: object) -> bool:\n        return not self == other\n\n    def __hash__(self) -> int:\n        return hash(self._attribute_set)\n\n    def __iter__(self) -> typing.Iterator[NameAttribute]:\n        return iter(self._attributes)\n\n    def __len__(self) -> int:\n        return len(self._attributes)\n\n    def __repr__(self) -> str:\n        return \"<RelativeDistinguishedName({})>\".format(self.rfc4514_string())\n\n\nclass Name(object):\n    @typing.overload\n    def __init__(self, attributes: typing.Iterable[NameAttribute]) -> None:\n        ...\n\n    @typing.overload\n    def __init__(\n        self, attributes: typing.Iterable[RelativeDistinguishedName]\n    ) -> None:\n        ...\n\n    def __init__(\n        self,\n        attributes: typing.Iterable[\n            typing.Union[NameAttribute, RelativeDistinguishedName]\n        ],\n    ) -> None:\n        attributes = list(attributes)\n        if all(isinstance(x, NameAttribute) for x in attributes):\n            self._attributes = [\n                RelativeDistinguishedName([typing.cast(NameAttribute, x)])\n                for x in attributes\n            ]\n        elif all(isinstance(x, RelativeDistinguishedName) for x in attributes):\n            self._attributes = typing.cast(\n                typing.List[RelativeDistinguishedName], attributes\n            )\n        else:\n            raise TypeError(\n                \"attributes must be a list of NameAttribute\"\n                \" or a list RelativeDistinguishedName\"\n            )\n\n    def rfc4514_string(\n        self, attr_name_overrides: typing.Optional[_OidNameMap] = None\n    ) -> str:\n        \"\"\"\n        Format as RFC4514 Distinguished Name string.\n        For example 'CN=foobar.com,O=Foo Corp,C=US'\n\n        An X.509 name is a two-level structure: a list of sets of attributes.\n        Each list element is separated by ',' and within each list element, set\n        elements are separated by '+'. The latter is almost never used in\n        real world certificates. According to RFC4514 section 2.1 the\n        RDNSequence must be reversed when converting to string representation.\n        \"\"\"\n        return \",\".join(\n            attr.rfc4514_string(attr_name_overrides)\n            for attr in reversed(self._attributes)\n        )\n\n    def get_attributes_for_oid(\n        self, oid: ObjectIdentifier\n    ) -> typing.List[NameAttribute]:\n        return [i for i in self if i.oid == oid]\n\n    @property\n    def rdns(self) -> typing.List[RelativeDistinguishedName]:\n        return self._attributes\n\n    def public_bytes(self, backend: typing.Any = None) -> bytes:\n        return rust_x509.encode_name_bytes(self)\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, Name):\n            return NotImplemented\n\n        return self._attributes == other._attributes\n\n    def __ne__(self, other: object) -> bool:\n        return not self == other\n\n    def __hash__(self) -> int:\n        # TODO: this is relatively expensive, if this looks like a bottleneck\n        # for you, consider optimizing!\n        return hash(tuple(self._attributes))\n\n    def __iter__(self) -> typing.Iterator[NameAttribute]:\n        for rdn in self._attributes:\n            for ava in rdn:\n                yield ava\n\n    def __len__(self) -> int:\n        return sum(len(rdn) for rdn in self._attributes)\n\n    def __repr__(self) -> str:\n        rdns = \",\".join(attr.rfc4514_string() for attr in self._attributes)\n        return \"<Name({})>\".format(rdns)\n", "path": "src/cryptography/x509/name.py"}]}