diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/encode_asn1.py | 2 | ||||
-rw-r--r-- | src/cryptography/x509/general_name.py | 64 |
2 files changed, 51 insertions, 15 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/encode_asn1.py b/src/cryptography/hazmat/backends/openssl/encode_asn1.py index 78ae21a2..6d9f9567 100644 --- a/src/cryptography/hazmat/backends/openssl/encode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/encode_asn1.py @@ -441,7 +441,7 @@ def _encode_general_name(backend, name): gn = backend._lib.GENERAL_NAME_new() backend.openssl_assert(gn != backend._ffi.NULL) asn1_str = _encode_asn1_str( - backend, name._encoded, len(name._encoded) + backend, name.bytes_value, len(name.bytes_value) ) gn.type = backend._lib.GEN_EMAIL gn.d.rfc822Name = asn1_str diff --git a/src/cryptography/x509/general_name.py b/src/cryptography/x509/general_name.py index 40525a01..114b43ae 100644 --- a/src/cryptography/x509/general_name.py +++ b/src/cryptography/x509/general_name.py @@ -51,31 +51,67 @@ class GeneralName(object): @utils.register_interface(GeneralName) class RFC822Name(object): def __init__(self, value): - if not isinstance(value, six.text_type): - raise TypeError("value must be a unicode string") + if isinstance(value, six.text_type): + try: + value = value.encode("ascii") + except UnicodeEncodeError: + value = self._idna_encode(value) + warnings.warn( + "RFC822Name values should be passed as bytes, not strings." + " Support for passing unicode strings will be removed in a" + " future version.", + utils.DeprecatedIn21, + stacklevel=2, + ) + else: + warnings.warn( + "RFC822Name 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") - name, address = parseaddr(value) - parts = address.split(u"@") + name, address = parseaddr(value.decode("ascii")) if name or not address: # parseaddr has found a name (e.g. Name <email>) or the entire # value is an empty string. raise ValueError("Invalid rfc822name value") - elif len(parts) == 1: + + self._bytes_value = value + + bytes_value = utils.read_only_property("_bytes_value") + + def _idna_encode(self, value): + _, address = parseaddr(value) + parts = address.split(u"@") + return parts[0].encode("ascii") + b"@" + idna.encode(parts[1]) + + @property + def value(self): + warnings.warn( + "RFC822Name.bytes_value should be used instead of RFC822Name.value" + "; it contains the name as raw bytes, instead of as an idna-" + "decoded unicode string. RFC822Name.value will be removed in a " + "future version.", + utils.DeprecatedIn21, + stacklevel=2 + ) + _, address = parseaddr(self.bytes_value.decode("ascii")) + parts = address.split(u"@") + if len(parts) == 1: # Single label email name. This is valid for local delivery. - # No IDNA encoding needed since there is no domain component. - encoded = address.encode("ascii") + # No IDNA decoding needed since there is no domain component. + return address else: # A normal email of the form user@domain.com. Let's attempt to # encode the domain component and reconstruct the address. - encoded = parts[0].encode("ascii") + b"@" + idna.encode(parts[1]) - - self._value = value - self._encoded = encoded - - value = utils.read_only_property("_value") + return parts[0] + u"@" + idna.decode(parts[1]) def __repr__(self): - return "<RFC822Name(value={0})>".format(self.value) + return "<RFC822Name(bytes_value={0!r})>".format(self.bytes_value) def __eq__(self, other): if not isinstance(other, RFC822Name): |