diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/_cffi_src/openssl/asn1.py | 1 | ||||
-rw-r--r-- | src/_cffi_src/openssl/x509v3.py | 3 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/backend.py | 22 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/x509.py | 31 | ||||
-rw-r--r-- | src/cryptography/hazmat/primitives/asymmetric/rsa.py | 14 | ||||
-rw-r--r-- | src/cryptography/x509.py | 19 |
6 files changed, 85 insertions, 5 deletions
diff --git a/src/_cffi_src/openssl/asn1.py b/src/_cffi_src/openssl/asn1.py index 01d6f4c2..5f8ca697 100644 --- a/src/_cffi_src/openssl/asn1.py +++ b/src/_cffi_src/openssl/asn1.py @@ -157,6 +157,7 @@ int ASN1_UTCTIME_check(ASN1_UTCTIME *); int ASN1_STRING_set_default_mask_asc(char *); int i2d_ASN1_TYPE(ASN1_TYPE *, unsigned char **); +ASN1_TYPE *d2i_ASN1_TYPE(ASN1_TYPE **, const unsigned char **, long); """ CUSTOMIZATIONS = """ diff --git a/src/_cffi_src/openssl/x509v3.py b/src/_cffi_src/openssl/x509v3.py index 0f5306d0..8e42b65d 100644 --- a/src/_cffi_src/openssl/x509v3.py +++ b/src/_cffi_src/openssl/x509v3.py @@ -193,6 +193,9 @@ void AUTHORITY_KEYID_free(AUTHORITY_KEYID *); NAME_CONSTRAINTS *NAME_CONSTRAINTS_new(void); void NAME_CONSTRAINTS_free(NAME_CONSTRAINTS *); +OTHERNAME *OTHERNAME_new(void); +void OTHERNAME_free(OTHERNAME *); + void *X509V3_set_ctx_nodb(X509V3_CTX *); int i2d_GENERAL_NAMES(GENERAL_NAMES *, unsigned char **); diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 7255b470..637b28cc 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -199,6 +199,28 @@ def _encode_subject_alt_name(backend, san): ) gn.type = backend._lib.GEN_IPADD gn.d.iPAddress = ipaddr + elif isinstance(alt_name, x509.OtherName): + gn = backend._lib.GENERAL_NAME_new() + assert gn != backend._ffi.NULL + other_name = backend._lib.OTHERNAME_new() + assert other_name != backend._ffi.NULL + + type_id = backend._lib.OBJ_txt2obj( + alt_name.type_id.dotted_string.encode('ascii'), 1 + ) + assert type_id != backend._ffi.NULL + data = backend._ffi.new("unsigned char[]", alt_name.value) + data_ptr_ptr = backend._ffi.new("unsigned char **") + data_ptr_ptr[0] = data + value = backend._lib.d2i_ASN1_TYPE( + backend._ffi.NULL, data_ptr_ptr, len(alt_name.value) + ) + if value == backend._ffi.NULL: + raise ValueError("Invalid ASN.1 data") + other_name.type_id = type_id + other_name.value = value + gn.type = backend._lib.GEN_OTHERNAME + gn.d.otherName = other_name else: raise NotImplementedError( "Only DNSName and RegisteredID supported right now" diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index d78c60fa..096cbc9e 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -141,11 +141,32 @@ def _decode_general_name(backend, gn): oid = _obj2txt(backend, gn.d.registeredID) return x509.RegisteredID(x509.ObjectIdentifier(oid)) elif gn.type == backend._lib.GEN_IPADD: - return x509.IPAddress( - ipaddress.ip_address( - _asn1_string_to_bytes(backend, gn.d.iPAddress) - ) - ) + data = _asn1_string_to_bytes(backend, gn.d.iPAddress) + data_len = len(data) + if data_len == 8 or data_len == 32: + # This is an IPv4 or IPv6 Network and not a single IP. This + # type of data appears in Name Constraints. Unfortunately, + # ipaddress doesn't support packed bytes + netmask. Additionally, + # IPv6Network can only handle CIDR rather than the full 16 byte + # netmask. To handle this we convert the netmask to integer, then + # find the first 0 bit, which will be the prefix. If another 1 + # bit is present after that the netmask is invalid. + base = ipaddress.ip_address(data[:data_len // 2]) + netmask = ipaddress.ip_address(data[data_len // 2:]) + bits = bin(int(netmask))[2:] + prefix = bits.find('0') + # If no 0 bits are found it is a /32 or /128 + if prefix == -1: + prefix = len(bits) + + if "1" in bits[prefix:]: + raise ValueError("Invalid netmask") + + ip = ipaddress.ip_network(base.exploded + u"/{0}".format(prefix)) + else: + ip = ipaddress.ip_address(data) + + return x509.IPAddress(ip) elif gn.type == backend._lib.GEN_DIRNAME: return x509.DirectoryName( _decode_x509_name(backend, gn.d.directoryName) diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py index 89eac4d4..41b0089e 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -307,6 +307,17 @@ class RSAPrivateNumbers(object): def __ne__(self, other): return not self == other + def __hash__(self): + return hash(( + self.p, + self.q, + self.d, + self.dmp1, + self.dmq1, + self.iqmp, + self.public_numbers, + )) + class RSAPublicNumbers(object): def __init__(self, e, n): @@ -336,3 +347,6 @@ class RSAPublicNumbers(object): def __ne__(self, other): return not self == other + + def __hash__(self): + return hash((self.e, self.n)) diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 33c64168..8bed79e2 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -6,8 +6,11 @@ from __future__ import absolute_import, division, print_function import abc import ipaddress +from email.utils import parseaddr from enum import Enum +import idna + import six from cryptography import utils @@ -901,7 +904,23 @@ class RFC822Name(object): if not isinstance(value, six.text_type): raise TypeError("value must be a unicode string") + name, address = parseaddr(value) + parts = address.split(u"@") + 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: + # Single label email name. This is valid for local delivery. + # No IDNA encoding needed since there is no domain component. + encoded = address.encode("ascii") + 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") |