aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/x509.rst43
-rw-r--r--src/cryptography/x509.py46
-rw-r--r--tests/test_x509_ext.py40
3 files changed, 129 insertions, 0 deletions
diff --git a/docs/x509.rst b/docs/x509.rst
index 27f1d544..89265df2 100644
--- a/docs/x509.rst
+++ b/docs/x509.rst
@@ -273,6 +273,49 @@ X.509 Certificate Object
The dotted string value of the OID (e.g. ``"2.5.4.3"``)
+X.509 Extensions
+~~~~~~~~~~~~~~~~
+
+.. class:: Extension
+
+ .. versionadded:: 0.9
+
+ All X.509 extensions are registered against this interface.
+
+ .. attribute:: critical
+
+ :type: bool
+
+ Determines whether a given extension is critical or not.
+
+.. class:: BasicConstraints
+
+ .. versionadded:: 0.9
+
+ Basic constraints is an X.509 extension that defines whether a given
+ certificate is allowed to sign additional certificates and what path
+ length restrictions may exist.
+
+ .. attribute:: ca
+
+ :type: bool
+
+ Whether the certificate can sign certificates.
+
+ .. attribute:: path_length
+
+ :type: int, None
+
+ The maximum path length for certificates subordinate to this
+ certificate. This attribute only has meaning if ``ca`` is true.
+ If ``ca`` is true then a path length of None means there's no
+ restriction on the number of subordinate CAs in the certificate chain.
+ If it is zero or greater then that number defines the maximum length.
+ For example, a ``path_length`` of 1 means the certificate can sign a
+ subordinate CA, but the subordinate CA is not allowed to create
+ ``ca`` true certificates.
+
+
Object Identifiers
~~~~~~~~~~~~~~~~~~
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
index ad7ebbe0..c053dd61 100644
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -141,6 +141,52 @@ class Name(object):
return len(self._attributes)
+OID_BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19")
+
+
+@six.add_metaclass(abc.ABCMeta)
+class Extension(object):
+ @abc.abstractproperty
+ def critical(self):
+ """
+ Returns the boolean value of the critical extension field.
+ """
+
+
+@utils.register_interface(Extension)
+class BasicConstraints(object):
+ oid = OID_BASIC_CONSTRAINTS
+
+ def __init__(self, ca, path_length, critical):
+ if not isinstance(ca, bool):
+ raise TypeError("ca must be a boolean value")
+
+ if not isinstance(critical, bool):
+ raise TypeError("critical must be a boolean value")
+
+ if path_length is not None and ca is False:
+ raise ValueError("path_length must be None when ca is False")
+
+ if path_length is not None and (not isinstance(path_length, int)
+ or path_length < 0):
+ raise TypeError(
+ "path_length must be a non-negative integer or None"
+ )
+
+ self._ca = ca
+ self._path_length = path_length
+ self._critical = critical
+
+ ca = utils.read_only_property("_ca")
+ path_length = utils.read_only_property("_path_length")
+ critical = utils.read_only_property("_critical")
+
+ def __repr__(self):
+ return "<BasicConstraints(ca={}, path_length={}, critical={})>".format(
+ self.ca, self.path_length, self.critical
+ )
+
+
OID_COMMON_NAME = ObjectIdentifier("2.5.4.3")
OID_COUNTRY_NAME = ObjectIdentifier("2.5.4.6")
OID_LOCALITY_NAME = ObjectIdentifier("2.5.4.7")
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
new file mode 100644
index 00000000..9fde1be1
--- /dev/null
+++ b/tests/test_x509_ext.py
@@ -0,0 +1,40 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import pytest
+
+from cryptography import x509
+
+
+class TestBasicConstraints(object):
+ def test_ca_not_boolean(self):
+ with pytest.raises(TypeError):
+ x509.BasicConstraints("notbool", None, False)
+
+ def test_critical_not_boolean(self):
+ with pytest.raises(TypeError):
+ x509.BasicConstraints(False, None, "notbool")
+
+ def test_path_length_not_ca(self):
+ with pytest.raises(ValueError):
+ x509.BasicConstraints(False, 0, True)
+
+ def test_path_length_not_int(self):
+ with pytest.raises(TypeError):
+ x509.BasicConstraints(True, 1.1, True)
+
+ with pytest.raises(TypeError):
+ x509.BasicConstraints(True, "notint", True)
+
+ def test_path_length_negative(self):
+ with pytest.raises(TypeError):
+ x509.BasicConstraints(True, -1, True)
+
+ def test_repr(self):
+ na = x509.BasicConstraints(True, None, True)
+ assert repr(na) == (
+ "<BasicConstraints(ca=True, path_length=None, critical=True)>"
+ )