aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2015-05-18 09:53:47 -0700
committerPaul Kehrer <paul.l.kehrer@gmail.com>2016-02-26 07:56:42 -0600
commit7e8fe9df4328f0d3134a502b5d3bc05435de7e6e (patch)
treee9f366f611137e2a42d4ee5cd3359b6c829e15db
parent4a00dcd02b1d3c10f76273889e12b088662b218f (diff)
downloadcryptography-7e8fe9df4328f0d3134a502b5d3bc05435de7e6e.tar.gz
cryptography-7e8fe9df4328f0d3134a502b5d3bc05435de7e6e.tar.bz2
cryptography-7e8fe9df4328f0d3134a502b5d3bc05435de7e6e.zip
add policy constraints class
-rw-r--r--docs/x509/reference.rst40
-rw-r--r--src/cryptography/x509/extensions.py54
-rw-r--r--tests/test_x509_ext.py35
3 files changed, 129 insertions, 0 deletions
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 8bb3f40d..14fc37c8 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -1860,6 +1860,40 @@ X.509 Extensions
:type: int
+.. class:: PolicyConstraints
+
+ .. versionadded:: 1.3
+
+ The policy constraints extension can be used in certificates issued
+ to CAs. The policy constraints extension constrains path validation
+ in two ways. It can be used to prohibit policy mapping or require
+ that each certificate in a path contain an acceptable policy
+ identifier. For more information about the use of this extension see
+ :rfc:`5280`.
+
+ .. attribute:: require_explicit_policy
+
+ :type: int or None
+
+ If this field is present, the value indicates the number of additional
+ certificates that may appear in the path before an explicit policy is
+ required for the entire path. When an explicit policy is required, it
+ is necessary for all certificates in the path to contain an acceptable
+ policy identifier in the certificate policies extension. An
+ acceptable policy identifier is the identifier of a policy required
+ by the user of the certification path or the identifier of a policy
+ that has been declared equivalent through policy mapping.
+
+ .. attribute:: inhibit_policy_mapping
+
+ :type: int or None
+
+ If this field is present, the value indicates the number of additional
+ certificates that may appear in the path before policy mapping is no
+ longer permitted. For example, a value of one indicates that policy
+ mapping may be processed in certificates issued by the subject of this
+ certificate, but not in additional certificates in the path.
+
.. class:: CRLNumber(crl_number)
.. versionadded:: 1.2
@@ -2392,6 +2426,12 @@ instances. The following common OIDs are available as constants.
the ``CRLNumber`` extension type. This extension only has meaning
for certificate revocation lists.
+ .. attribute:: POLICY_CONSTRAINTS
+
+ Corresponds to the dotted string ``"2.5.29.36"``. The identifier for the
+ :class:`PolicyConstraints` extension type.
+
+
.. class:: CRLEntryExtensionOID
.. versionadded:: 1.2
diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py
index db55789e..ba9cb373 100644
--- a/src/cryptography/x509/extensions.py
+++ b/src/cryptography/x509/extensions.py
@@ -490,6 +490,60 @@ class ReasonFlags(Enum):
@utils.register_interface(ExtensionType)
+class PolicyConstraints(object):
+ def __init__(self, require_explicit_policy, inhibit_policy_mapping):
+ if require_explicit_policy is not None and not isinstance(
+ require_explicit_policy, six.integer_types
+ ):
+ raise TypeError(
+ "require_explicit_policy must be a non-negative integer or "
+ "None"
+ )
+
+ if inhibit_policy_mapping is not None and not isinstance(
+ inhibit_policy_mapping, six.integer_types
+ ):
+ raise TypeError(
+ "inhibit_policy_mapping must be a non-negative integer or None"
+ )
+
+ if inhibit_policy_mapping is None and require_explicit_policy is None:
+ raise ValueError(
+ "At least one of require_explicit_policy and "
+ "inhibit_policy_mapping must not be None"
+ )
+
+ self._require_explicit_policy = require_explicit_policy
+ self._inhibit_policy_mapping = inhibit_policy_mapping
+
+ def __repr__(self):
+ return (
+ u"<PolicyConstraints(require_explicit_policy={0.require_explicit"
+ u"_policy}, inhibit_policy_mapping={0.inhibit_policy_"
+ u"mapping})>".format(self)
+ )
+
+ def __eq__(self, other):
+ if not isinstance(other, PolicyConstraints):
+ return NotImplemented
+
+ return (
+ self.require_explicit_policy == other.require_explicit_policy and
+ self.inhibit_policy_mapping == other.inhibit_policy_mapping
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+ require_explicit_policy = utils.read_only_property(
+ "_require_explicit_policy"
+ )
+ inhibit_policy_mapping = utils.read_only_property(
+ "_inhibit_policy_mapping"
+ )
+
+
+@utils.register_interface(ExtensionType)
class CertificatePolicies(object):
oid = ExtensionOID.CERTIFICATE_POLICIES
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
index d8a5f9de..ceb11dfe 100644
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -2245,6 +2245,41 @@ class TestAccessDescription(object):
assert hash(ad) != hash(ad3)
+class TestPolicyConstraints(object):
+ def test_invalid_explicit_policy(self):
+ with pytest.raises(TypeError):
+ x509.PolicyConstraints("invalid", None)
+
+ def test_invalid_inhibit_policy(self):
+ with pytest.raises(TypeError):
+ x509.PolicyConstraints(None, "invalid")
+
+ def test_both_none(self):
+ with pytest.raises(ValueError):
+ x509.PolicyConstraints(None, None)
+
+ def test_repr(self):
+ pc = x509.PolicyConstraints(0, None)
+
+ assert repr(pc) == (
+ u"<PolicyConstraints(require_explicit_policy=0, inhibit_policy_ma"
+ u"pping=None)>"
+ )
+
+ def test_eq(self):
+ pc = x509.PolicyConstraints(2, 1)
+ pc2 = x509.PolicyConstraints(2, 1)
+ assert pc == pc2
+
+ def test_ne(self):
+ pc = x509.PolicyConstraints(2, 1)
+ pc2 = x509.PolicyConstraints(2, 2)
+ pc3 = x509.PolicyConstraints(3, 1)
+ assert pc != pc2
+ assert pc != pc3
+ assert pc != object()
+
+
class TestAuthorityInformationAccess(object):
def test_invalid_descriptions(self):
with pytest.raises(TypeError):