diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/decode_asn1.py | 18 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/encode_asn1.py | 13 | ||||
-rw-r--r-- | src/cryptography/utils.py | 1 | ||||
-rw-r--r-- | src/cryptography/x509/general_name.py | 74 |
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 |