aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/x509.rst7
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py28
-rw-r--r--tests/test_x509_ext.py21
3 files changed, 55 insertions, 1 deletions
diff --git a/docs/x509.rst b/docs/x509.rst
index 035fa87f..5f36a921 100644
--- a/docs/x509.rst
+++ b/docs/x509.rst
@@ -452,7 +452,12 @@ General Name Classes
.. versionadded:: 0.9
This corresponds to a uniform resource identifier. For example,
- ``https://cryptography.io``.
+ ``https://cryptography.io``. The URI is parsed and IDNA decoded (see
+ :rfc:`5895`).
+
+ .. note::
+
+ URIs that do not contain ``://`` in them will not be decoded.
.. attribute:: value
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index c21aeeb1..3a660d81 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -17,6 +17,10 @@ import datetime
import idna
+import six
+
+from six.moves import urllib_parse
+
from cryptography import utils, x509
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.primitives import hashes
@@ -63,6 +67,30 @@ def _build_general_name(backend, gn):
if gn.type == backend._lib.GEN_DNS:
data = backend._ffi.buffer(gn.d.dNSName.data, gn.d.dNSName.length)[:]
return x509.DNSName(idna.decode(data))
+ elif gn.type == backend._lib.GEN_URI:
+ data = backend._ffi.buffer(
+ gn.d.uniformResourceIdentifier.data,
+ gn.d.uniformResourceIdentifier.length
+ )[:].decode("ascii")
+ parsed = urllib_parse.urlparse(data)
+ hostname = idna.decode(parsed.hostname)
+ if parsed.port:
+ netloc = hostname + u":" + six.text_type(parsed.port)
+ else:
+ netloc = hostname
+
+ # Note that building a URL in this fashion means it should be
+ # semantically indistinguishable from the original but is not
+ # guaranteed to be exactly the same.
+ uri = urllib_parse.urlunparse((
+ parsed.scheme,
+ netloc,
+ parsed.path,
+ parsed.params,
+ parsed.query,
+ parsed.fragment
+ ))
+ return x509.UniformResourceIdentifier(uri)
elif gn.type == backend._lib.GEN_RID:
oid = _obj2txt(backend, gn.d.registeredID)
return x509.RegisteredID(x509.ObjectIdentifier(oid))
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
index bce6781f..820e96b9 100644
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -788,3 +788,24 @@ class TestRSASubjectAlternativeNameExtension(object):
san = ext.value
rid = san.get_values_for_type(x509.RegisteredID)
assert rid == [x509.ObjectIdentifier("1.2.3.4")]
+
+ def test_uri(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509", "custom", "san_uri_with_port.pem"
+ ),
+ x509.load_pem_x509_certificate,
+ backend
+ )
+ ext = cert.extensions.get_extension_for_oid(
+ x509.OID_SUBJECT_ALTERNATIVE_NAME
+ )
+ assert ext is not None
+ uri = ext.value.get_values_for_type(
+ x509.UniformResourceIdentifier
+ )
+ assert uri == [
+ u"gopher://\u043f\u044b\u043a\u0430.cryptography:70/path?q=s#hel"
+ u"lo",
+ u"http://someregulardomain.com",
+ ]