aboutsummaryrefslogtreecommitdiffstats
path: root/src/cryptography
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2017-07-30 13:08:51 -0400
committerPaul Kehrer <paul.l.kehrer@gmail.com>2017-07-30 12:08:51 -0500
commitcdaf3ff72f6fd562c275c04836cfaa230aabcdf4 (patch)
tree8f1587293f9232d2d6ebbbfebd65f700ea93966b /src/cryptography
parent2131b962c03c8787c8918f0672707cce3dca06f8 (diff)
downloadcryptography-cdaf3ff72f6fd562c275c04836cfaa230aabcdf4.tar.gz
cryptography-cdaf3ff72f6fd562c275c04836cfaa230aabcdf4.tar.bz2
cryptography-cdaf3ff72f6fd562c275c04836cfaa230aabcdf4.zip
Begin the deprecation of auto-idna for x509.DNSName (#3830)
* Begin the deprecation of auto-idna for x509.DNSName Refs #3357 * fix warning * py3k fixes * fix docs * sigh * flake8 * these are words * words * tests for coverage * another test * do idna things * more idna things
Diffstat (limited to 'src/cryptography')
-rw-r--r--src/cryptography/hazmat/backends/openssl/decode_asn1.py18
-rw-r--r--src/cryptography/hazmat/backends/openssl/encode_asn1.py13
-rw-r--r--src/cryptography/utils.py1
-rw-r--r--src/cryptography/x509/general_name.py74
4 files changed, 69 insertions, 37 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py
index a55b5880..a66f65f6 100644
--- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py
+++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py
@@ -88,23 +88,7 @@ def _decode_general_names(backend, gns):
def _decode_general_name(backend, gn):
if gn.type == backend._lib.GEN_DNS:
data = _asn1_string_to_bytes(backend, gn.d.dNSName)
- if not data:
- decoded = u""
- elif data.startswith(b"*."):
- # This is a wildcard name. We need to remove the leading wildcard,
- # IDNA decode, then re-add the wildcard. Wildcard characters should
- # always be left-most (RFC 2595 section 2.4).
- decoded = u"*." + idna.decode(data[2:])
- else:
- # Not a wildcard, decode away. If the string has a * in it anywhere
- # invalid this will raise an InvalidCodePoint
- decoded = idna.decode(data)
- if data.startswith(b"."):
- # idna strips leading periods. Name constraints can have that
- # so we need to re-add it. Sigh.
- decoded = u"." + decoded
-
- return x509.DNSName(decoded)
+ return x509.DNSName(data)
elif gn.type == backend._lib.GEN_URI:
data = _asn1_string_to_ascii(backend, gn.d.uniformResourceIdentifier)
parsed = urllib_parse.urlparse(data)
diff --git a/src/cryptography/hazmat/backends/openssl/encode_asn1.py b/src/cryptography/hazmat/backends/openssl/encode_asn1.py
index 399000a4..77d22127 100644
--- a/src/cryptography/hazmat/backends/openssl/encode_asn1.py
+++ b/src/cryptography/hazmat/backends/openssl/encode_asn1.py
@@ -7,8 +7,6 @@ from __future__ import absolute_import, division, print_function
import calendar
import ipaddress
-import idna
-
import six
from cryptography import utils, x509
@@ -370,15 +368,6 @@ def _encode_subject_key_identifier(backend, ski):
return _encode_asn1_str_gc(backend, ski.digest, len(ski.digest))
-def _idna_encode(value):
- # Retain prefixes '*.' for common/alt names and '.' for name constraints
- for prefix in ['*.', '.']:
- if value.startswith(prefix):
- value = value[len(prefix):]
- return prefix.encode('ascii') + idna.encode(value)
- return idna.encode(value)
-
-
def _encode_general_name(backend, name):
if isinstance(name, x509.DNSName):
gn = backend._lib.GENERAL_NAME_new()
@@ -387,7 +376,7 @@ def _encode_general_name(backend, name):
ia5 = backend._lib.ASN1_IA5STRING_new()
backend.openssl_assert(ia5 != backend._ffi.NULL)
- value = _idna_encode(name.value)
+ value = name.bytes_value
res = backend._lib.ASN1_STRING_set(ia5, value, len(value))
backend.openssl_assert(res == 1)
diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py
index efb12e21..02857c06 100644
--- a/src/cryptography/utils.py
+++ b/src/cryptography/utils.py
@@ -16,6 +16,7 @@ import warnings
# cycle ends.
PersistentlyDeprecated = DeprecationWarning
DeprecatedIn19 = DeprecationWarning
+DeprecatedIn21 = PendingDeprecationWarning
def _check_bytes(name, value):
diff --git a/src/cryptography/x509/general_name.py b/src/cryptography/x509/general_name.py
index 6745243a..9ea1cff6 100644
--- a/src/cryptography/x509/general_name.py
+++ b/src/cryptography/x509/general_name.py
@@ -6,6 +6,7 @@ from __future__ import absolute_import, division, print_function
import abc
import ipaddress
+import warnings
from email.utils import parseaddr
import idna
@@ -89,24 +90,81 @@ class RFC822Name(object):
return hash(self.value)
+def _idna_encode(value):
+ # Retain prefixes '*.' for common/alt names and '.' for name constraints
+ for prefix in ['*.', '.']:
+ if value.startswith(prefix):
+ value = value[len(prefix):]
+ return prefix.encode('ascii') + idna.encode(value)
+ return idna.encode(value)
+
+
@utils.register_interface(GeneralName)
class DNSName(object):
def __init__(self, value):
- if not isinstance(value, six.text_type):
- raise TypeError("value must be a unicode string")
-
- self._value = value
-
- value = utils.read_only_property("_value")
+ if isinstance(value, six.text_type):
+ try:
+ value = value.encode("ascii")
+ except UnicodeEncodeError:
+ value = _idna_encode(value)
+ warnings.warn(
+ "DNSName values should be passed as idna-encoded bytes, "
+ "not strings. Support for passing unicode strings will be "
+ "removed in a future version.",
+ utils.DeprecatedIn21,
+ stacklevel=2,
+ )
+ else:
+ warnings.warn(
+ "DNSName values should be passed as bytes, not strings. "
+ "Support for passing unicode strings will be removed in a "
+ "future version.",
+ utils.DeprecatedIn21,
+ stacklevel=2,
+ )
+ elif not isinstance(value, bytes):
+ raise TypeError("value must be bytes")
+
+ self._bytes_value = value
+
+ bytes_value = utils.read_only_property("_bytes_value")
+
+ @property
+ def value(self):
+ warnings.warn(
+ "DNSName.bytes_value should be used instead of DNSName.value; it "
+ "contains the DNS name as raw bytes, instead of as an idna-decoded"
+ " unicode string. DNSName.value will be removed in a future "
+ "version.",
+ utils.DeprecatedIn21,
+ stacklevel=2
+ )
+ data = self._bytes_value
+ if not data:
+ decoded = u""
+ elif data.startswith(b"*."):
+ # This is a wildcard name. We need to remove the leading wildcard,
+ # IDNA decode, then re-add the wildcard. Wildcard characters should
+ # always be left-most (RFC 2595 section 2.4).
+ decoded = u"*." + idna.decode(data[2:])
+ else:
+ # Not a wildcard, decode away. If the string has a * in it anywhere
+ # invalid this will raise an InvalidCodePoint
+ decoded = idna.decode(data)
+ if data.startswith(b"."):
+ # idna strips leading periods. Name constraints can have that
+ # so we need to re-add it. Sigh.
+ decoded = u"." + decoded
+ return decoded
def __repr__(self):
- return "<DNSName(value={0})>".format(self.value)
+ return "<DNSName(bytes_value={0!r})>".format(self.bytes_value)
def __eq__(self, other):
if not isinstance(other, DNSName):
return NotImplemented
- return self.value == other.value
+ return self.bytes_value == other.bytes_value
def __ne__(self, other):
return not self == other