diff options
author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2015-07-12 14:59:37 -0500 |
---|---|---|
committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2015-07-12 15:20:15 -0500 |
commit | e28d6c47eb73ab3d3297745873a25e0f6c0eae8e (patch) | |
tree | 0faab703ed6dac2c109dbf88868098cabebf9ac4 | |
parent | 699616f4ed6ee7f2e92d87b038842864c517feaa (diff) | |
download | cryptography-e28d6c47eb73ab3d3297745873a25e0f6c0eae8e.tar.gz cryptography-e28d6c47eb73ab3d3297745873a25e0f6c0eae8e.tar.bz2 cryptography-e28d6c47eb73ab3d3297745873a25e0f6c0eae8e.zip |
expand UniformResourceIdentiier to parse and internally IDNA encode
-rw-r--r-- | src/cryptography/x509.py | 26 | ||||
-rw-r--r-- | tests/test_x509_ext.py | 32 |
2 files changed, 58 insertions, 0 deletions
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 8bed79e2..58e1a37c 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -13,6 +13,8 @@ import idna import six +from six.moves import urllib_parse + from cryptography import utils from cryptography.hazmat.primitives import hashes @@ -966,7 +968,31 @@ class UniformResourceIdentifier(object): if not isinstance(value, six.text_type): raise TypeError("value must be a unicode string") + parsed = urllib_parse.urlparse(value) + if not parsed.hostname: + netloc = "" + elif parsed.port: + netloc = ( + idna.encode(parsed.hostname) + + ":{0}".format(parsed.port).encode("ascii") + ).decode("ascii") + else: + netloc = idna.encode(parsed.hostname).decode("ascii") + + # 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 + )).encode("ascii") + self._value = value + self._encoded = uri value = utils.read_only_property("_value") diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index 84a40995..7b135828 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -1105,6 +1105,38 @@ class TestRFC822Name(object): assert gn._encoded == b"email@xn--eml-vla4c.com" +class TestUniformResourceIdentifier(object): + def test_no_parsed_hostname(self): + gn = x509.UniformResourceIdentifier(u"singlelabel") + assert gn.value == u"singlelabel" + + def test_with_port(self): + gn = x509.UniformResourceIdentifier(u"singlelabel:443/test") + assert gn.value == u"singlelabel:443/test" + + def test_idna_no_port(self): + gn = x509.UniformResourceIdentifier( + u"http://\u043f\u044b\u043a\u0430.cryptography" + ) + assert gn.value == u"http://\u043f\u044b\u043a\u0430.cryptography" + assert gn._encoded == b"http://xn--80ato2c.cryptography" + + def test_idna_with_port(self): + gn = x509.UniformResourceIdentifier( + u"gopher://\u043f\u044b\u043a\u0430.cryptography:70/some/path" + ) + assert gn.value == ( + u"gopher://\u043f\u044b\u043a\u0430.cryptography:70/some/path" + ) + assert gn._encoded == b"gopher://xn--80ato2c.cryptography:70/some/path" + + def test_query_and_fragment(self): + gn = x509.UniformResourceIdentifier( + u"ldap://cryptography:90/path?query=true#somedata" + ) + assert gn.value == u"ldap://cryptography:90/path?query=true#somedata" + + class TestRegisteredID(object): def test_not_oid(self): with pytest.raises(TypeError): |