diff options
author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2015-07-01 19:16:36 -0500 |
---|---|---|
committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2015-07-10 11:11:19 -0500 |
commit | cfb8aa2f39095d33d19b17123aed065dd5e9efd3 (patch) | |
tree | cc1c37f977d99be9dfc5dc588bd641409d3fd279 | |
parent | 3fe1543c9e4c04604967a9524aa5b2e641bc9ede (diff) | |
download | cryptography-cfb8aa2f39095d33d19b17123aed065dd5e9efd3.tar.gz cryptography-cfb8aa2f39095d33d19b17123aed065dd5e9efd3.tar.bz2 cryptography-cfb8aa2f39095d33d19b17123aed065dd5e9efd3.zip |
name constraints - support IP addresses with netmask
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/x509.py | 29 | ||||
-rw-r--r-- | tests/test_x509_ext.py | 35 |
2 files changed, 59 insertions, 5 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index d78c60fa..c2a32b2a 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -141,11 +141,30 @@ 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 = backend._ffi.buffer( + gn.d.iPAddress.data, gn.d.iPAddress.length + )[:] + 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 = utils.int_from_bytes(data[data_len // 2:], 'big') + bits = bin(netmask)[2:] + prefix = bits.find('0') + if bits[prefix:].find('1') != -1: + 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/tests/test_x509_ext.py b/tests/test_x509_ext.py index 993802b8..7a7e79e6 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -2184,6 +2184,41 @@ class TestNameConstraintsExtension(object): ] ) + def test_permitted_excluded_with_ips(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "nc_permitted_excluded.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + nc = cert.extensions.get_extension_for_oid( + x509.OID_NAME_CONSTRAINTS + ).value + assert nc == x509.NameConstraints( + permitted_subtrees=[ + x509.IPAddress(ipaddress.IPv4Network(u"192.168.0.0/24")), + x509.IPAddress(ipaddress.IPv6Network(u"FF:0:0:0:0:0:0:0/96")), + ], + excluded_subtrees=[ + x509.DNSName(u".domain.com"), + x509.UniformResourceIdentifier(u"http://test.local"), + ] + ) + + def test_invalid_netmask(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "nc_invalid_ip_netmask.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + with pytest.raises(ValueError): + cert.extensions.get_extension_for_oid( + x509.OID_NAME_CONSTRAINTS + ) + class TestDistributionPoint(object): def test_distribution_point_full_name_not_general_names(self): |