diff options
-rw-r--r-- | CHANGELOG.rst | 2 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/encode_asn1.py | 19 | ||||
-rw-r--r-- | tests/test_x509.py | 38 |
3 files changed, 49 insertions, 10 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 328c4301..c9fa42cb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,6 +24,8 @@ Changelog when using OpenSSL 1.1.0. * Added support for generating a :meth:`~cryptography.x509.random_serial_number`. +* Added support for encoding ``IPv4Network`` and ``IPv6Network`` in X.509 + certificates for use with :class:`~cryptography.x509.NameConstraints`. 1.5.2 - 2016-09-26 ~~~~~~~~~~~~~~~~~~ diff --git a/src/cryptography/hazmat/backends/openssl/encode_asn1.py b/src/cryptography/hazmat/backends/openssl/encode_asn1.py index 467aa88e..284c760c 100644 --- a/src/cryptography/hazmat/backends/openssl/encode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/encode_asn1.py @@ -5,12 +5,13 @@ from __future__ import absolute_import, division, print_function import calendar +import ipaddress import idna import six -from cryptography import x509 +from cryptography import utils, x509 from cryptography.hazmat.backends.openssl.decode_asn1 import ( _CRL_ENTRY_REASON_ENUM_TO_CODE, _DISTPOINT_TYPE_FULLNAME, _DISTPOINT_TYPE_RELATIVENAME @@ -402,9 +403,19 @@ def _encode_general_name(backend, name): elif isinstance(name, x509.IPAddress): gn = backend._lib.GENERAL_NAME_new() backend.openssl_assert(gn != backend._ffi.NULL) - ipaddr = _encode_asn1_str( - backend, name.value.packed, len(name.value.packed) - ) + if isinstance(name.value, ipaddress.IPv4Network): + packed = ( + name.value.network_address.packed + + utils.int_to_bytes(((1 << 32) - name.value.num_addresses), 4) + ) + elif isinstance(name.value, ipaddress.IPv6Network): + packed = ( + name.value.network_address.packed + + utils.int_to_bytes((1 << 128) - name.value.num_addresses, 16) + ) + else: + packed = name.value.packed + ipaddr = _encode_asn1_str(backend, packed, len(packed)) gn.type = backend._lib.GEN_IPADD gn.d.iPAddress = ipaddr elif isinstance(name, x509.OtherName): diff --git a/tests/test_x509.py b/tests/test_x509.py index 7fd0e04c..d3b24ecc 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -2405,18 +2405,44 @@ class TestCertificateBuilder(object): @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) - def test_name_constraints(self, backend): + @pytest.mark.parametrize( + "nc", + [ + x509.NameConstraints( + permitted_subtrees=[ + x509.IPAddress(ipaddress.IPv4Network(u"192.168.0.0/24")), + x509.IPAddress(ipaddress.IPv4Network(u"192.168.0.0/29")), + x509.IPAddress(ipaddress.IPv4Network(u"127.0.0.1/32")), + x509.IPAddress(ipaddress.IPv4Network(u"8.0.0.0/8")), + x509.IPAddress(ipaddress.IPv4Network(u"0.0.0.0/0")), + x509.IPAddress( + ipaddress.IPv6Network(u"FF:0:0:0:0:0:0:0/96") + ), + x509.IPAddress( + ipaddress.IPv6Network(u"FF:FF:0:0:0:0:0:0/128") + ), + ], + excluded_subtrees=[x509.DNSName(u"name.local")] + ), + x509.NameConstraints( + permitted_subtrees=[ + x509.IPAddress(ipaddress.IPv4Network(u"0.0.0.0/0")), + ], + excluded_subtrees=None + ), + x509.NameConstraints( + permitted_subtrees=None, + excluded_subtrees=[x509.DNSName(u"name.local")] + ), + ] + ) + def test_name_constraints(self, nc, backend): issuer_private_key = RSA_KEY_2048.private_key(backend) subject_private_key = RSA_KEY_2048.private_key(backend) not_valid_before = datetime.datetime(2002, 1, 1, 12, 1) not_valid_after = datetime.datetime(2030, 12, 31, 8, 30) - excluded = [x509.DNSName(u"name.local")] - nc = x509.NameConstraints( - permitted_subtrees=None, excluded_subtrees=excluded - ) - cert = x509.CertificateBuilder().subject_name( x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) ).issuer_name( |