support encoding IPv4Network and IPv6Network, useful for NameConstraints (#3182)

* support encoding IPv4Network and IPv6Network, useful for NameConstraints

* add changelog entry

* add more networks with full and no masking (/32, /128, /0)

* parametrize the nc tests to fix coverage
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 328c430..c9fa42c 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -24,6 +24,8 @@
   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 467aa88..284c760 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 @@
     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 7fd0e04..d3b24ec 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -2405,18 +2405,44 @@
 
     @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(