aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/development/test-vectors.rst3
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py3
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py154
-rw-r--r--src/cryptography/hazmat/primitives/serialization.py32
-rw-r--r--src/cryptography/utils.py21
-rw-r--r--vectors/cryptography_vectors/x509/custom/nc_invalid_ip_netmask.pem18
-rw-r--r--vectors/cryptography_vectors/x509/custom/nc_permitted_excluded.pem22
7 files changed, 137 insertions, 116 deletions
diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst
index bc171b21..ac667bb7 100644
--- a/docs/development/test-vectors.rst
+++ b/docs/development/test-vectors.rst
@@ -204,6 +204,9 @@ Custom X.509 Vectors
name constraints extension with permitted elements.
* ``nc_excluded.pem`` - An RSA 2048 bit self-signed certificate containing a
name constraints extension with excluded elements.
+* ``nc_invalid_ip_netmask.pem`` - An RSA 2048 bit self-signed certificate
+ containing a name constraints extension with a permitted element that has an
+ ``IPv6`` IP and an invalid network mask.
* ``cp_user_notice_with_notice_reference.pem`` - An RSA 2048 bit self-signed
certificate containing a certificate policies extension with a
notice reference in the user notice.
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 22179607..51f68899 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -117,6 +117,9 @@ def _txt2obj(backend, name):
def _encode_basic_constraints(backend, basic_constraints):
constraints = backend._lib.BASIC_CONSTRAINTS_new()
+ constraints = backend._ffi.gc(
+ constraints, backend._lib.BASIC_CONSTRAINTS_free
+ )
constraints.ca = 255 if basic_constraints.ca else 0
if basic_constraints.ca:
constraints.pathlen = _encode_asn1_int(
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index b387b9ee..804bce66 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -163,6 +163,45 @@ def _decode_general_name(backend, gn):
)
+def _decode_ocsp_no_check(backend, ext):
+ return x509.OCSPNoCheck()
+
+
+class _X509ExtensionParser(object):
+ def __init__(self, ext_count, get_ext, handlers):
+ self.ext_count = ext_count
+ self.get_ext = get_ext
+ self.handlers = handlers
+
+ def parse(self, backend, x509_obj):
+ extensions = []
+ seen_oids = set()
+ for i in range(self.ext_count(backend, x509_obj)):
+ ext = self.get_ext(backend, x509_obj, i)
+ assert ext != backend._ffi.NULL
+ crit = backend._lib.X509_EXTENSION_get_critical(ext)
+ critical = crit == 1
+ oid = x509.ObjectIdentifier(_obj2txt(backend, ext.object))
+ if oid in seen_oids:
+ raise x509.DuplicateExtension(
+ "Duplicate {0} extension found".format(oid), oid
+ )
+ try:
+ handler = self.handlers[oid]
+ except KeyError:
+ if critical:
+ raise x509.UnsupportedExtension(
+ "{0} is not currently supported".format(oid), oid
+ )
+ else:
+ value = handler(backend, ext)
+ extensions.append(x509.Extension(oid, critical, value))
+
+ seen_oids.add(oid)
+
+ return x509.Extensions(extensions)
+
+
@utils.register_interface(x509.Certificate)
class _Certificate(object):
def __init__(self, backend, x509):
@@ -268,58 +307,7 @@ class _Certificate(object):
@property
def extensions(self):
- extensions = []
- seen_oids = set()
- extcount = self._backend._lib.X509_get_ext_count(self._x509)
- for i in range(0, extcount):
- ext = self._backend._lib.X509_get_ext(self._x509, i)
- assert ext != self._backend._ffi.NULL
- crit = self._backend._lib.X509_EXTENSION_get_critical(ext)
- critical = crit == 1
- oid = x509.ObjectIdentifier(_obj2txt(self._backend, ext.object))
- if oid in seen_oids:
- raise x509.DuplicateExtension(
- "Duplicate {0} extension found".format(oid), oid
- )
- elif oid == x509.OID_BASIC_CONSTRAINTS:
- value = _decode_basic_constraints(self._backend, ext)
- elif oid == x509.OID_SUBJECT_KEY_IDENTIFIER:
- value = _decode_subject_key_identifier(self._backend, ext)
- elif oid == x509.OID_KEY_USAGE:
- value = _decode_key_usage(self._backend, ext)
- elif oid == x509.OID_SUBJECT_ALTERNATIVE_NAME:
- value = _decode_subject_alt_name(self._backend, ext)
- elif oid == x509.OID_EXTENDED_KEY_USAGE:
- value = _decode_extended_key_usage(self._backend, ext)
- elif oid == x509.OID_AUTHORITY_KEY_IDENTIFIER:
- value = _decode_authority_key_identifier(self._backend, ext)
- elif oid == x509.OID_AUTHORITY_INFORMATION_ACCESS:
- value = _decode_authority_information_access(
- self._backend, ext
- )
- elif oid == x509.OID_CERTIFICATE_POLICIES:
- value = _decode_certificate_policies(self._backend, ext)
- elif oid == x509.OID_CRL_DISTRIBUTION_POINTS:
- value = _decode_crl_distribution_points(self._backend, ext)
- elif oid == x509.OID_OCSP_NO_CHECK:
- value = x509.OCSPNoCheck()
- elif oid == x509.OID_INHIBIT_ANY_POLICY:
- value = _decode_inhibit_any_policy(self._backend, ext)
- elif oid == x509.OID_ISSUER_ALTERNATIVE_NAME:
- value = _decode_issuer_alt_name(self._backend, ext)
- elif critical:
- raise x509.UnsupportedExtension(
- "{0} is not currently supported".format(oid), oid
- )
- else:
- # Unsupported non-critical extension, silently skipping for now
- seen_oids.add(oid)
- continue
-
- seen_oids.add(oid)
- extensions.append(x509.Extension(oid, critical, value))
-
- return x509.Extensions(extensions)
+ return _CERTIFICATE_EXTENSION_PARSER.parse(self._backend, self._x509)
def public_bytes(self, encoding):
bio = self._backend._create_mem_bio()
@@ -704,37 +692,8 @@ class _CertificateSigningRequest(object):
@property
def extensions(self):
- extensions = []
- seen_oids = set()
x509_exts = self._backend._lib.X509_REQ_get_extensions(self._x509_req)
- extcount = self._backend._lib.sk_X509_EXTENSION_num(x509_exts)
- for i in range(0, extcount):
- ext = self._backend._lib.sk_X509_EXTENSION_value(x509_exts, i)
- assert ext != self._backend._ffi.NULL
- crit = self._backend._lib.X509_EXTENSION_get_critical(ext)
- critical = crit == 1
- oid = x509.ObjectIdentifier(_obj2txt(self._backend, ext.object))
- if oid in seen_oids:
- raise x509.DuplicateExtension(
- "Duplicate {0} extension found".format(oid), oid
- )
- elif oid == x509.OID_BASIC_CONSTRAINTS:
- value = _decode_basic_constraints(self._backend, ext)
- elif oid == x509.OID_SUBJECT_ALTERNATIVE_NAME:
- value = _decode_subject_alt_name(self._backend, ext)
- elif critical:
- raise x509.UnsupportedExtension(
- "{0} is not currently supported".format(oid), oid
- )
- else:
- # Unsupported non-critical extension, silently skipping for now
- seen_oids.add(oid)
- continue
-
- seen_oids.add(oid)
- extensions.append(x509.Extension(oid, critical, value))
-
- return x509.Extensions(extensions)
+ return _CSR_EXTENSION_PARSER.parse(self._backend, x509_exts)
def public_bytes(self, encoding):
bio = self._backend._create_mem_bio()
@@ -749,3 +708,34 @@ class _CertificateSigningRequest(object):
assert res == 1
return self._backend._read_mem_bio(bio)
+
+
+_CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser(
+ ext_count=lambda backend, x: backend._lib.X509_get_ext_count(x),
+ get_ext=lambda backend, x, i: backend._lib.X509_get_ext(x, i),
+ handlers={
+ x509.OID_BASIC_CONSTRAINTS: _decode_basic_constraints,
+ x509.OID_SUBJECT_KEY_IDENTIFIER: _decode_subject_key_identifier,
+ x509.OID_KEY_USAGE: _decode_key_usage,
+ x509.OID_SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name,
+ x509.OID_EXTENDED_KEY_USAGE: _decode_extended_key_usage,
+ x509.OID_AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier,
+ x509.OID_AUTHORITY_INFORMATION_ACCESS: (
+ _decode_authority_information_access
+ ),
+ x509.OID_CERTIFICATE_POLICIES: _decode_certificate_policies,
+ x509.OID_CRL_DISTRIBUTION_POINTS: _decode_crl_distribution_points,
+ x509.OID_OCSP_NO_CHECK: _decode_ocsp_no_check,
+ x509.OID_INHIBIT_ANY_POLICY: _decode_inhibit_any_policy,
+ x509.OID_ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name,
+ }
+)
+
+_CSR_EXTENSION_PARSER = _X509ExtensionParser(
+ ext_count=lambda backend, x: backend._lib.sk_X509_EXTENSION_num(x),
+ get_ext=lambda backend, x, i: backend._lib.sk_X509_EXTENSION_value(x, i),
+ handlers={
+ x509.OID_BASIC_CONSTRAINTS: _decode_basic_constraints,
+ x509.OID_SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name,
+ }
+)
diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py
index 9fbc32b1..098b31dc 100644
--- a/src/cryptography/hazmat/primitives/serialization.py
+++ b/src/cryptography/hazmat/primitives/serialization.py
@@ -122,8 +122,12 @@ def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend):
if len(data) != 1 + 2 * ((curve.key_size + 7) // 8):
raise ValueError("Malformed key bytes")
- x = _int_from_bytes(data[1:1 + (curve.key_size + 7) // 8], byteorder='big')
- y = _int_from_bytes(data[1 + (curve.key_size + 7) // 8:], byteorder='big')
+ x = utils.int_from_bytes(
+ data[1:1 + (curve.key_size + 7) // 8], byteorder='big'
+ )
+ y = utils.int_from_bytes(
+ data[1 + (curve.key_size + 7) // 8:], byteorder='big'
+ )
return ec.EllipticCurvePublicNumbers(x, y, curve).public_key(backend)
@@ -145,27 +149,9 @@ def _read_next_mpint(data):
"""
mpint_data, rest = _read_next_string(data)
- return _int_from_bytes(mpint_data, byteorder='big', signed=False), rest
-
-
-if hasattr(int, "from_bytes"):
- _int_from_bytes = int.from_bytes
-else:
- def _int_from_bytes(data, byteorder, signed=False):
- assert byteorder == 'big'
- assert not signed
-
- if len(data) % 4 != 0:
- data = (b'\x00' * (4 - (len(data) % 4))) + data
-
- result = 0
-
- while len(data) > 0:
- digit, = struct.unpack('>I', data[:4])
- result = (result << 32) + digit
- data = data[4:]
-
- return result
+ return (
+ utils.int_from_bytes(mpint_data, byteorder='big', signed=False), rest
+ )
class Encoding(Enum):
diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py
index 0bf8c0ea..24afe612 100644
--- a/src/cryptography/utils.py
+++ b/src/cryptography/utils.py
@@ -6,6 +6,7 @@ from __future__ import absolute_import, division, print_function
import abc
import inspect
+import struct
import sys
import warnings
@@ -25,6 +26,26 @@ def register_interface(iface):
return register_decorator
+if hasattr(int, "from_bytes"):
+ int_from_bytes = int.from_bytes
+else:
+ def int_from_bytes(data, byteorder, signed=False):
+ assert byteorder == 'big'
+ assert not signed
+
+ if len(data) % 4 != 0:
+ data = (b'\x00' * (4 - (len(data) % 4))) + data
+
+ result = 0
+
+ while len(data) > 0:
+ digit, = struct.unpack('>I', data[:4])
+ result = (result << 32) + digit
+ data = data[4:]
+
+ return result
+
+
class InterfaceNotImplemented(Exception):
pass
diff --git a/vectors/cryptography_vectors/x509/custom/nc_invalid_ip_netmask.pem b/vectors/cryptography_vectors/x509/custom/nc_invalid_ip_netmask.pem
new file mode 100644
index 00000000..42f7fd37
--- /dev/null
+++ b/vectors/cryptography_vectors/x509/custom/nc_invalid_ip_netmask.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC8TCCAdmgAwIBAgITBm/Wnt8Tt9uB01YkE0oW0WAn8DANBgkqhkiG9w0BAQsF
+ADAXMRUwEwYDVQQDDAxjcnlwdG9ncmFwaHkwHhcNMTUwNjI3MjMzNDI1WhcNMTYw
+NjI2MjMzNDI1WjAXMRUwEwYDVQQDDAxjcnlwdG9ncmFwaHkwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCylTa0WkLvIXB4sWoPdv5iL3idlVHKR+ncODKL
+nwQ2Jtd990MfakOFRLrJFF1tfPL4qyRbbyMyrgCOoKBCAuIdBZfBDH3JWFjxGy8J
+Yls8yVeAVKreV18HmLvAsBL3bnr7Gk3vpznrfoG5rn5T/fL0cqqTXFV8zQhjHiEo
+zftSaoq0LOxsSgFdxXS8e8K6RMvLCZPcMpI4fo1Kq2QBT2J1x1/Hq/VnK132cs0g
+TOyiTyyJfvRmlqdXowh7Jf8LQB4mM6gc023fEdQ+HH6JYX1vDQVxaiTM6KMYJNv/
+l4gchP3jknOfZffwGGdXQrtUMhQmltnSqV5nY/G2OGm/Z0pdAgMBAAGjNjA0MDIG
+A1UdHgEB/wQoMCagJDAihyAA/wAAAAAAAAAAAAAAAAAA/////wAA/////wD/AAAA
+ADANBgkqhkiG9w0BAQsFAAOCAQEALGCUUKrfrDkuezZmG5ibkAYOMl2jwc6qmyRO
+GzAeh1xgJpyG4Cz6E57PZwFJiU7WsagW75xiuhyt3BvjEob9TaHmkPka16SdJBP2
+6fkzUHu9HKJbJ5GNzPrcJJG0IQB9Vdqs2D3qrpNC6IQ80PLPaT8Lq3L6Na8c2VrQ
+Y80eHVxiTllDFy8NGIu5nvuKinLSW/O/WNH7M0pkQ9clFR7R+bGNwGrTJ9pKhgGK
+fNJU7CT5HTViMQmN49c3B6JrdBblBI/q3SLTqxqa0Qwp2ZH2fYjCszO3QdpPlbQD
+N8kfs6qmNhkvfIDWMNdQBqhnhuOJ8FJLo1/xYP1ziigg+ajN8g==
+-----END CERTIFICATE-----
diff --git a/vectors/cryptography_vectors/x509/custom/nc_permitted_excluded.pem b/vectors/cryptography_vectors/x509/custom/nc_permitted_excluded.pem
index 13f26ca6..7c92eaf1 100644
--- a/vectors/cryptography_vectors/x509/custom/nc_permitted_excluded.pem
+++ b/vectors/cryptography_vectors/x509/custom/nc_permitted_excluded.pem
@@ -1,19 +1,19 @@
-----BEGIN CERTIFICATE-----
-MIIDIzCCAgugAwIBAgITBm9f6VBd37JBCGQYKoXvtJ0PbDANBgkqhkiG9w0BAQsF
-ADAXMRUwEwYDVQQDDAxjcnlwdG9ncmFwaHkwHhcNMTUwNjIzMDcyMTU4WhcNMTYw
-NjIyMDcyMTU4WjAXMRUwEwYDVQQDDAxjcnlwdG9ncmFwaHkwggEiMA0GCSqGSIb3
+MIIDIzCCAgugAwIBAgITBm/Wc4kdp3PUxItnkeVsX2BhETANBgkqhkiG9w0BAQsF
+ADAXMRUwEwYDVQQDDAxjcnlwdG9ncmFwaHkwHhcNMTUwNjI3MjMyNDQ5WhcNMTYw
+NjI2MjMyNDQ5WjAXMRUwEwYDVQQDDAxjcnlwdG9ncmFwaHkwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCylTa0WkLvIXB4sWoPdv5iL3idlVHKR+ncODKL
nwQ2Jtd990MfakOFRLrJFF1tfPL4qyRbbyMyrgCOoKBCAuIdBZfBDH3JWFjxGy8J
Yls8yVeAVKreV18HmLvAsBL3bnr7Gk3vpznrfoG5rn5T/fL0cqqTXFV8zQhjHiEo
zftSaoq0LOxsSgFdxXS8e8K6RMvLCZPcMpI4fo1Kq2QBT2J1x1/Hq/VnK132cs0g
TOyiTyyJfvRmlqdXowh7Jf8LQB4mM6gc023fEdQ+HH6JYX1vDQVxaiTM6KMYJNv/
l4gchP3jknOfZffwGGdXQrtUMhQmltnSqV5nY/G2OGm/Z0pdAgMBAAGjaDBmMGQG
-A1UdHgEB/wRaMFigMDAKhwjAqAAA////ADAihyAA/wAAAAAAAAAAAAAAAAAAAP8A
-AAAAAAAAAAAAAAAA/6EkMA2CCy5kb21haW4uY29tMBOGEWh0dHA6Ly90ZXN0Lmxv
-Y2FsMA0GCSqGSIb3DQEBCwUAA4IBAQAKS62+aFz7T7Vt2K5/dHWE8sqh9g86veQL
-wBQPG+6ysG4QkQQOiS4CUwOCf4S3quS0pXn+UeJsQKistjFWxoVIrLhEaCPMjpwX
-2LSnQQVBF4YCOnnGyGD1m4hCH1j3hWkHKwPLCcQ7LQ6a1a7CKHLitVxWGWUW+CM+
-NYxt/mon5rYZTomI6p1eVsdrq7Ma942HbgvvQBT8EJjrNGRbH9RV7mGj1ZxBdyyX
-Li7iLk670nIzTG/DfA+yckU5vZkrhicezhsLqXYwhzWUpmWp68vehj0zd25qHP2k
-lCXgYIHtlc9m8p/Io4eRM/Kx8qMsMGe8l7FI8j9uNNZGHt0ecdbX
+A1UdHgEB/wRaMFigMDAKhwjAqAAA////ADAihyAA/wAAAAAAAAAAAAAAAAAA////
+////////////AAAAAKEkMA2CCy5kb21haW4uY29tMBOGEWh0dHA6Ly90ZXN0Lmxv
+Y2FsMA0GCSqGSIb3DQEBCwUAA4IBAQCA+WJUYgrKl4XG/zNL9EcxMexWrJAfpGf8
+wcBpvG7Xko0OBdLhspylDL2wDGh1tqAwBCqxJHoDwxuYLJdN7uc4Zq75RCa6aP8C
+Lq8gcSlO4TNrFB2GCnHaFNkDpvSBIDkWdqHZr9IykNZ2KhPB+/rKxZGlaupATUSO
+aYKJ/8Vl62IpNLx1KqVtNM8pCyiWO8Eru2NVWoqwmTRKnyWhFLi/kWNn7A76EsQF
+9skfHoZGlGY69pklyY92y6c7eLma4l6DzRwxut3dNCM1AFtdFoN+RRyYduwTN9qo
+dMmAD6sb6wn0a+Ss6K20lJv/DQc4A3nFPKzKFmZh5RwO4f+hUSAe
-----END CERTIFICATE-----