diff options
-rw-r--r-- | src/cryptography/x509.py | 119 | ||||
-rw-r--r-- | tests/test_x509_ext.py | 117 |
2 files changed, 236 insertions, 0 deletions
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index dfc0af8c..3509303f 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -69,6 +69,8 @@ _OID_NAMES = { "1.3.6.1.5.5.7.48.1.5": "OCSPNoCheck", "1.3.6.1.5.5.7.48.1": "OCSP", "1.3.6.1.5.5.7.48.2": "caIssuers", + "1.3.6.1.5.5.7.2.1": "id-qt-cps", + "1.3.6.1.5.5.7.2.2": "id-qt-unotice", } @@ -460,6 +462,120 @@ class AccessDescription(object): access_location = utils.read_only_property("_access_location") +class CertificatePolicies(object): + def __init__(self, policies): + if not all(map(lambda x: isinstance(x, PolicyInformation), policies)): + raise TypeError( + "Every item in the policies list must be a " + "PolicyInformation" + ) + + self._policies = policies + + def __iter__(self): + return iter(self._policies) + + def __len__(self): + return len(self._policies) + + def __repr__(self): + return "<CertificatePolicies({0})>".format(self._policies) + + +class PolicyInformation(object): + def __init__(self, policy_identifier, policy_qualifiers): + if not isinstance(policy_identifier, ObjectIdentifier): + raise TypeError("policy_identifier must be an ObjectIdentifier") + + self._policy_identifier = policy_identifier + if policy_qualifiers and not all( + map( + lambda x: isinstance(x, PolicyQualifierInfo), policy_qualifiers + ) + ): + raise TypeError( + "policy_qualifiers must be a list of PolicyQualifierInfo " + "objects or None" + ) + + self._policy_qualifiers = policy_qualifiers + + def __repr__(self): + return ( + "<PolicyInformation(policy_identifier={0.policy_identifier}, polic" + "y_qualifiers={0.policy_qualifiers})>".format(self) + ) + + policy_identifier = utils.read_only_property("_policy_identifier") + policy_qualifiers = utils.read_only_property("_policy_qualifiers") + + +class PolicyQualifierInfo(object): + def __init__(self, qualifier): + if not isinstance(qualifier, (six.string_types, UserNotice)): + raise ValueError("qualifier must be string or UserNotice") + + if isinstance(qualifier, six.string_types): + self._policy_qualifier_id = OID_CPS_QUALIFIER + else: + self._policy_qualifier_id = OID_CPS_USER_NOTICE + + self._qualifier = qualifier + + def __repr__(self): + return ( + "<PolicyQualifierInfo(policy_qualifier_id={0.policy_qualifier_id}" + ", qualifier={0.qualifier})>".format(self) + ) + + policy_qualifier_id = utils.read_only_property("_policy_qualifier_id") + qualifier = utils.read_only_property("_qualifier") + + +class UserNotice(object): + def __init__(self, notice_reference, explicit_text): + if notice_reference and not isinstance( + notice_reference, NoticeReference + ): + raise TypeError( + "notice_reference must be None or a NoticeReference" + ) + + self._notice_reference = notice_reference + self._explicit_text = explicit_text + + def __repr__(self): + return ( + "<UserNotice(notice_reference={0.notice_reference}, explicit_text=" + "{0.explicit_text})>".format(self) + ) + + notice_reference = utils.read_only_property("_notice_reference") + explicit_text = utils.read_only_property("_explicit_text") + + +class NoticeReference(object): + def __init__(self, organization, notice_numbers): + self._organization = organization + if notice_numbers and not all( + map(lambda x: isinstance(x, int), notice_numbers) + ): + raise TypeError( + "notice_numbers must be a list of integers or None" + ) + + self._notice_numbers = notice_numbers + + def __repr__(self): + return ( + "<NoticeReference(organization={0.organization}, notice_numbers=" + "{0.notice_numbers})>".format(self) + ) + + organization = utils.read_only_property("_organization") + notice_numbers = utils.read_only_property("_notice_numbers") + + class SubjectKeyIdentifier(object): def __init__(self, digest): self._digest = digest @@ -874,6 +990,9 @@ OID_OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9") OID_CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2") OID_OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1") +OID_CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1") +OID_CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2") + @six.add_metaclass(abc.ABCMeta) class Certificate(object): diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index 06a68600..c6303432 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -39,6 +39,123 @@ class TestExtension(object): ) +class TestNoticeReference(object): + def test_notice_numbers_not_all_int(self): + with pytest.raises(TypeError): + x509.NoticeReference("org", [1, 2, "three"]) + + def test_notice_numbers_none(self): + nr = x509.NoticeReference("org", None) + assert nr.organization == "org" + assert nr.notice_numbers is None + + def test_repr(self): + nr = x509.NoticeReference("org", [1, 3, 4]) + + assert repr(nr) == ( + "<NoticeReference(organization=org, notice_numbers=[1, 3, 4])>" + ) + + +class TestUserNotice(object): + def test_notice_reference_invalid(self): + with pytest.raises(TypeError): + x509.UserNotice("invalid", None) + + def test_notice_reference_none(self): + un = x509.UserNotice(None, "text") + assert un.notice_reference is None + assert un.explicit_text == "text" + + def test_repr(self): + un = x509.UserNotice(x509.NoticeReference("org", None), "text") + assert repr(un) == ( + "<UserNotice(notice_reference=<NoticeReference(organization=org, " + "notice_numbers=None)>, explicit_text=text)>" + ) + + +class TestPolicyQualifierInfo(object): + def test_invalid_qualifier(self): + with pytest.raises(ValueError): + x509.PolicyQualifierInfo(None) + + def test_string_qualifier(self): + pqi = x509.PolicyQualifierInfo("1.2.3") + assert pqi.policy_qualifier_id == x509.OID_CPS_QUALIFIER + assert pqi.qualifier == "1.2.3" + + def test_user_notice_qualifier(self): + pqi = x509.PolicyQualifierInfo(x509.UserNotice(None, "text")) + assert pqi.policy_qualifier_id == x509.OID_CPS_USER_NOTICE + assert isinstance(pqi.qualifier, x509.UserNotice) + + def test_repr(self): + pqi = x509.PolicyQualifierInfo("1.2.3.4") + assert repr(pqi) == ( + "<PolicyQualifierInfo(policy_qualifier_id=<ObjectIdentifier(oid=1." + "3.6.1.5.5.7.2.1, name=id-qt-cps)>, qualifier=1.2.3.4)>" + ) + + +class TestPolicyInformation(object): + def test_invalid_policy_identifier(self): + with pytest.raises(TypeError): + x509.PolicyInformation("notanoid", None) + + def test_none_policy_qualifiers(self): + pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), None) + assert pi.policy_identifier == x509.ObjectIdentifier("1.2.3") + assert pi.policy_qualifiers is None + + def test_policy_qualifiers(self): + pq = [x509.PolicyQualifierInfo("string")] + pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), pq) + assert pi.policy_identifier == x509.ObjectIdentifier("1.2.3") + assert pi.policy_qualifiers == pq + + def test_invalid_policy_identifiers(self): + with pytest.raises(TypeError): + x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), [1, 2]) + + def test_repr(self): + pq = [x509.PolicyQualifierInfo("string")] + pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), pq) + assert repr(pi) == ( + "<PolicyInformation(policy_identifier=<ObjectIdentifier(oid=1.2.3," + " name=Unknown OID)>, policy_qualifiers=[<PolicyQualifierInfo(poli" + "cy_qualifier_id=<ObjectIdentifier(oid=1.3.6.1.5.5.7.2.1, name=id-" + "qt-cps)>, qualifier=string)>])>" + ) + + +class TestCertificatePolicies(object): + def test_invalid_policies(self): + pq = [x509.PolicyQualifierInfo("string")] + pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), pq) + with pytest.raises(TypeError): + x509.CertificatePolicies([1, pi]) + + def test_iter_len(self): + pq = [x509.PolicyQualifierInfo("string")] + pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), pq) + cp = x509.CertificatePolicies([pi]) + assert len(cp) == 1 + for policyinfo in cp: + assert policyinfo == pi + + def test_repr(self): + pq = [x509.PolicyQualifierInfo("string")] + pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), pq) + cp = x509.CertificatePolicies([pi]) + assert repr(cp) == ( + "<CertificatePolicies([<PolicyInformation(policy_identifier=<Objec" + "tIdentifier(oid=1.2.3, name=Unknown OID)>, policy_qualifiers=[<Po" + "licyQualifierInfo(policy_qualifier_id=<ObjectIdentifier(oid=1.3.6" + ".1.5.5.7.2.1, name=id-qt-cps)>, qualifier=string)>])>])>" + ) + + class TestKeyUsage(object): def test_key_agreement_false_encipher_decipher_true(self): with pytest.raises(ValueError): |