diff options
Diffstat (limited to 'tests/x509/test_x509_ext.py')
| -rw-r--r-- | tests/x509/test_x509_ext.py | 5289 |
1 files changed, 5289 insertions, 0 deletions
diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py new file mode 100644 index 00000000..19ce4363 --- /dev/null +++ b/tests/x509/test_x509_ext.py @@ -0,0 +1,5289 @@ +# 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 binascii +import datetime +import ipaddress +import os + +import pretend + +import pytest + +import six + +from cryptography import utils, x509 +from cryptography.hazmat.backends.interfaces import ( + DSABackend, EllipticCurveBackend, RSABackend, X509Backend +) +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.x509 import DNSName, NameConstraints, SubjectAlternativeName +from cryptography.x509.extensions import _key_identifier_from_public_key +from cryptography.x509.general_name import _lazy_import_idna +from cryptography.x509.oid import ( + AuthorityInformationAccessOID, ExtendedKeyUsageOID, ExtensionOID, + NameOID, ObjectIdentifier, _OID_NAMES +) + +from .test_x509 import _load_cert +from ..hazmat.primitives.fixtures_rsa import RSA_KEY_2048 +from ..hazmat.primitives.test_ec import _skip_curve_unsupported +from ..utils import load_vectors_from_file + + +def _make_certbuilder(private_key): + name = x509.Name( + [x509.NameAttribute(NameOID.COMMON_NAME, u'example.org')]) + return ( + x509.CertificateBuilder() + .subject_name(name) + .issuer_name(name) + .public_key(private_key.public_key()) + .serial_number(777) + .not_valid_before(datetime.datetime(1999, 1, 1)) + .not_valid_after(datetime.datetime(2020, 1, 1)) + ) + + +def test_lazy_idna_import(): + try: + __import__("idna") + pytest.skip("idna is installed") + except ImportError: + pass + + with pytest.raises(ImportError): + _lazy_import_idna() + + +class TestExtension(object): + def test_not_an_oid(self): + bc = x509.BasicConstraints(ca=False, path_length=None) + with pytest.raises(TypeError): + x509.Extension("notanoid", True, bc) + + def test_critical_not_a_bool(self): + bc = x509.BasicConstraints(ca=False, path_length=None) + with pytest.raises(TypeError): + x509.Extension(ExtensionOID.BASIC_CONSTRAINTS, "notabool", bc) + + def test_repr(self): + bc = x509.BasicConstraints(ca=False, path_length=None) + ext = x509.Extension(ExtensionOID.BASIC_CONSTRAINTS, True, bc) + assert repr(ext) == ( + "<Extension(oid=<ObjectIdentifier(oid=2.5.29.19, name=basicConst" + "raints)>, critical=True, value=<BasicConstraints(ca=False, path" + "_length=None)>)>" + ) + + def test_eq(self): + ext1 = x509.Extension( + x509.ObjectIdentifier('1.2.3.4'), False, 'value' + ) + ext2 = x509.Extension( + x509.ObjectIdentifier('1.2.3.4'), False, 'value' + ) + assert ext1 == ext2 + + def test_ne(self): + ext1 = x509.Extension( + x509.ObjectIdentifier('1.2.3.4'), False, 'value' + ) + ext2 = x509.Extension( + x509.ObjectIdentifier('1.2.3.5'), False, 'value' + ) + ext3 = x509.Extension( + x509.ObjectIdentifier('1.2.3.4'), True, 'value' + ) + ext4 = x509.Extension( + x509.ObjectIdentifier('1.2.3.4'), False, 'value4' + ) + assert ext1 != ext2 + assert ext1 != ext3 + assert ext1 != ext4 + assert ext1 != object() + + def test_hash(self): + ext1 = x509.Extension( + ExtensionOID.BASIC_CONSTRAINTS, + False, + x509.BasicConstraints(ca=False, path_length=None) + ) + ext2 = x509.Extension( + ExtensionOID.BASIC_CONSTRAINTS, + False, + x509.BasicConstraints(ca=False, path_length=None) + ) + ext3 = x509.Extension( + ExtensionOID.BASIC_CONSTRAINTS, + False, + x509.BasicConstraints(ca=True, path_length=None) + ) + assert hash(ext1) == hash(ext2) + assert hash(ext1) != hash(ext3) + + +class TestTLSFeature(object): + def test_not_enum_type(self): + with pytest.raises(TypeError): + x509.TLSFeature([3]) + + def test_empty_list(self): + with pytest.raises(TypeError): + x509.TLSFeature([]) + + def test_repr(self): + ext1 = x509.TLSFeature([x509.TLSFeatureType.status_request]) + assert repr(ext1) == ( + "<TLSFeature(features=[<TLSFeatureType.status_request: 5>])>" + ) + + def test_eq(self): + ext1 = x509.TLSFeature([x509.TLSFeatureType.status_request]) + ext2 = x509.TLSFeature([x509.TLSFeatureType.status_request]) + assert ext1 == ext2 + + def test_ne(self): + ext1 = x509.TLSFeature([x509.TLSFeatureType.status_request]) + ext2 = x509.TLSFeature([x509.TLSFeatureType.status_request_v2]) + ext3 = x509.TLSFeature([ + x509.TLSFeatureType.status_request, + x509.TLSFeatureType.status_request_v2 + ]) + assert ext1 != ext2 + assert ext1 != ext3 + assert ext1 != object() + + def test_hash(self): + ext1 = x509.TLSFeature([x509.TLSFeatureType.status_request]) + ext2 = x509.TLSFeature([x509.TLSFeatureType.status_request]) + ext3 = x509.TLSFeature([ + x509.TLSFeatureType.status_request, + x509.TLSFeatureType.status_request_v2 + ]) + assert hash(ext1) == hash(ext2) + assert hash(ext1) != hash(ext3) + + def test_iter(self): + ext1_features = [x509.TLSFeatureType.status_request] + ext1 = x509.TLSFeature(ext1_features) + assert len(ext1) == 1 + assert list(ext1) == ext1_features + ext2_features = [ + x509.TLSFeatureType.status_request, + x509.TLSFeatureType.status_request_v2, + ] + ext2 = x509.TLSFeature(ext2_features) + assert len(ext2) == 2 + assert list(ext2) == ext2_features + + def test_indexing(self): + ext = x509.TLSFeature([ + x509.TLSFeatureType.status_request, + x509.TLSFeatureType.status_request_v2, + ]) + assert ext[-1] == ext[1] + assert ext[0] == x509.TLSFeatureType.status_request + + +class TestUnrecognizedExtension(object): + def test_invalid_oid(self): + with pytest.raises(TypeError): + x509.UnrecognizedExtension("notanoid", b"somedata") + + def test_eq(self): + ext1 = x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x01" + ) + ext2 = x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x01" + ) + assert ext1 == ext2 + + def test_ne(self): + ext1 = x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x01" + ) + ext2 = x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x02" + ) + ext3 = x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.2.3.5"), b"\x03\x02\x01" + ) + assert ext1 != ext2 + assert ext1 != ext3 + assert ext1 != object() + + def test_repr(self): + ext1 = x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x01" + ) + if not six.PY2: + assert repr(ext1) == ( + "<UnrecognizedExtension(oid=<ObjectIdentifier(oid=1.2.3.4, " + "name=Unknown OID)>, value=b'\\x03\\x02\\x01')>" + ) + else: + assert repr(ext1) == ( + "<UnrecognizedExtension(oid=<ObjectIdentifier(oid=1.2.3.4, " + "name=Unknown OID)>, value='\\x03\\x02\\x01')>" + ) + + def test_hash(self): + ext1 = x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x01" + ) + ext2 = x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x01" + ) + ext3 = x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.2.3.5"), b"\x03\x02\x01" + ) + assert hash(ext1) == hash(ext2) + assert hash(ext1) != hash(ext3) + + +class TestCertificateIssuer(object): + def test_iter_names(self): + ci = x509.CertificateIssuer([ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + ]) + assert len(ci) == 2 + assert list(ci) == [ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + ] + + def test_indexing(self): + ci = x509.CertificateIssuer([ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + x509.DNSName(u"another.local"), + x509.RFC822Name(u"email@another.local"), + x509.UniformResourceIdentifier(u"http://another.local"), + ]) + assert ci[-1] == ci[4] + assert ci[2:6:2] == [ci[2], ci[4]] + + def test_eq(self): + ci1 = x509.CertificateIssuer([x509.DNSName(u"cryptography.io")]) + ci2 = x509.CertificateIssuer([x509.DNSName(u"cryptography.io")]) + assert ci1 == ci2 + + def test_ne(self): + ci1 = x509.CertificateIssuer([x509.DNSName(u"cryptography.io")]) + ci2 = x509.CertificateIssuer([x509.DNSName(u"somethingelse.tld")]) + assert ci1 != ci2 + assert ci1 != object() + + def test_repr(self): + ci = x509.CertificateIssuer([x509.DNSName(u"cryptography.io")]) + if not six.PY2: + assert repr(ci) == ( + "<CertificateIssuer(<GeneralNames([<DNSName(value=" + "'cryptography.io')>])>)>" + ) + else: + assert repr(ci) == ( + "<CertificateIssuer(<GeneralNames([<DNSName(value=" + "u'cryptography.io')>])>)>" + ) + + def test_get_values_for_type(self): + ci = x509.CertificateIssuer( + [x509.DNSName(u"cryptography.io")] + ) + names = ci.get_values_for_type(x509.DNSName) + assert names == [u"cryptography.io"] + + def test_hash(self): + ci1 = x509.CertificateIssuer([x509.DNSName(u"cryptography.io")]) + ci2 = x509.CertificateIssuer([x509.DNSName(u"cryptography.io")]) + ci3 = x509.CertificateIssuer( + [x509.UniformResourceIdentifier(u"http://something")] + ) + assert hash(ci1) == hash(ci2) + assert hash(ci1) != hash(ci3) + + +class TestCRLReason(object): + def test_invalid_reason_flags(self): + with pytest.raises(TypeError): + x509.CRLReason("notareason") + + def test_eq(self): + reason1 = x509.CRLReason(x509.ReasonFlags.unspecified) + reason2 = x509.CRLReason(x509.ReasonFlags.unspecified) + assert reason1 == reason2 + + def test_ne(self): + reason1 = x509.CRLReason(x509.ReasonFlags.unspecified) + reason2 = x509.CRLReason(x509.ReasonFlags.ca_compromise) + assert reason1 != reason2 + assert reason1 != object() + + def test_hash(self): + reason1 = x509.CRLReason(x509.ReasonFlags.unspecified) + reason2 = x509.CRLReason(x509.ReasonFlags.unspecified) + reason3 = x509.CRLReason(x509.ReasonFlags.ca_compromise) + + assert hash(reason1) == hash(reason2) + assert hash(reason1) != hash(reason3) + + def test_repr(self): + reason1 = x509.CRLReason(x509.ReasonFlags.unspecified) + assert repr(reason1) == ( + "<CRLReason(reason=ReasonFlags.unspecified)>" + ) + + +class TestDeltaCRLIndicator(object): + def test_not_int(self): + with pytest.raises(TypeError): + x509.DeltaCRLIndicator("notanint") + + def test_eq(self): + delta1 = x509.DeltaCRLIndicator(1) + delta2 = x509.DeltaCRLIndicator(1) + assert delta1 == delta2 + + def test_ne(self): + delta1 = x509.DeltaCRLIndicator(1) + delta2 = x509.DeltaCRLIndicator(2) + assert delta1 != delta2 + assert delta1 != object() + + def test_repr(self): + delta1 = x509.DeltaCRLIndicator(2) + assert repr(delta1) == ( + "<DeltaCRLIndicator(crl_number=2)>" + ) + + def test_hash(self): + delta1 = x509.DeltaCRLIndicator(1) + delta2 = x509.DeltaCRLIndicator(1) + delta3 = x509.DeltaCRLIndicator(2) + assert hash(delta1) == hash(delta2) + assert hash(delta1) != hash(delta3) + + +class TestInvalidityDate(object): + def test_invalid_invalidity_date(self): + with pytest.raises(TypeError): + x509.InvalidityDate("notadate") + + def test_eq(self): + invalid1 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1)) + invalid2 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1)) + assert invalid1 == invalid2 + + def test_ne(self): + invalid1 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1)) + invalid2 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 2)) + assert invalid1 != invalid2 + assert invalid1 != object() + + def test_repr(self): + invalid1 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1)) + assert repr(invalid1) == ( + "<InvalidityDate(invalidity_date=2015-01-01 01:01:00)>" + ) + + def test_hash(self): + invalid1 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1)) + invalid2 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1)) + invalid3 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 2)) + assert hash(invalid1) == hash(invalid2) + assert hash(invalid1) != hash(invalid3) + + +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): + with pytest.raises(TypeError): + x509.NoticeReference("org", None) + + def test_iter_input(self): + numbers = [1, 3, 4] + nr = x509.NoticeReference(u"org", iter(numbers)) + assert list(nr.notice_numbers) == numbers + + def test_repr(self): + nr = x509.NoticeReference(u"org", [1, 3, 4]) + + if not six.PY2: + assert repr(nr) == ( + "<NoticeReference(organization='org', notice_numbers=[1, 3, 4" + "])>" + ) + else: + assert repr(nr) == ( + "<NoticeReference(organization=u'org', notice_numbers=[1, 3, " + "4])>" + ) + + def test_eq(self): + nr = x509.NoticeReference("org", [1, 2]) + nr2 = x509.NoticeReference("org", [1, 2]) + assert nr == nr2 + + def test_ne(self): + nr = x509.NoticeReference("org", [1, 2]) + nr2 = x509.NoticeReference("org", [1]) + nr3 = x509.NoticeReference(None, [1, 2]) + assert nr != nr2 + assert nr != nr3 + assert nr != object() + + def test_hash(self): + nr = x509.NoticeReference("org", [1, 2]) + nr2 = x509.NoticeReference("org", [1, 2]) + nr3 = x509.NoticeReference(None, [1, 2]) + assert hash(nr) == hash(nr2) + assert hash(nr) != hash(nr3) + + +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(u"org", [1]), u"text") + if not six.PY2: + assert repr(un) == ( + "<UserNotice(notice_reference=<NoticeReference(organization='" + "org', notice_numbers=[1])>, explicit_text='text')>" + ) + else: + assert repr(un) == ( + "<UserNotice(notice_reference=<NoticeReference(organization=u" + "'org', notice_numbers=[1])>, explicit_text=u'text')>" + ) + + def test_eq(self): + nr = x509.NoticeReference("org", [1, 2]) + nr2 = x509.NoticeReference("org", [1, 2]) + un = x509.UserNotice(nr, "text") + un2 = x509.UserNotice(nr2, "text") + assert un == un2 + + def test_ne(self): + nr = x509.NoticeReference("org", [1, 2]) + nr2 = x509.NoticeReference("org", [1]) + un = x509.UserNotice(nr, "text") + un2 = x509.UserNotice(nr2, "text") + un3 = x509.UserNotice(nr, "text3") + assert un != un2 + assert un != un3 + assert un != object() + + def test_hash(self): + nr = x509.NoticeReference("org", [1, 2]) + nr2 = x509.NoticeReference("org", [1, 2]) + un = x509.UserNotice(nr, "text") + un2 = x509.UserNotice(nr2, "text") + un3 = x509.UserNotice(None, "text") + assert hash(un) == hash(un2) + assert hash(un) != hash(un3) + + +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 = [u"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_iter_input(self): + qual = [u"foo", u"bar"] + pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), iter(qual)) + assert list(pi.policy_qualifiers) == qual + + def test_repr(self): + pq = [u"string", x509.UserNotice(None, u"hi")] + pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), pq) + if not six.PY2: + assert repr(pi) == ( + "<PolicyInformation(policy_identifier=<ObjectIdentifier(oid=1." + "2.3, name=Unknown OID)>, policy_qualifiers=['string', <UserNo" + "tice(notice_reference=None, explicit_text='hi')>])>" + ) + else: + assert repr(pi) == ( + "<PolicyInformation(policy_identifier=<ObjectIdentifier(oid=1." + "2.3, name=Unknown OID)>, policy_qualifiers=[u'string', <UserN" + "otice(notice_reference=None, explicit_text=u'hi')>])>" + ) + + def test_eq(self): + pi = x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3"), + [u"string", x509.UserNotice(None, u"hi")] + ) + pi2 = x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3"), + [u"string", x509.UserNotice(None, u"hi")] + ) + assert pi == pi2 + + def test_ne(self): + pi = x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3"), [u"string"] + ) + pi2 = x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3"), [u"string2"] + ) + pi3 = x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3.4"), [u"string"] + ) + assert pi != pi2 + assert pi != pi3 + assert pi != object() + + def test_hash(self): + pi = x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3"), + [u"string", x509.UserNotice(None, u"hi")] + ) + pi2 = x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3"), + [u"string", x509.UserNotice(None, u"hi")] + ) + pi3 = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), None) + assert hash(pi) == hash(pi2) + assert hash(pi) != hash(pi3) + + +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestCertificatePolicies(object): + def test_invalid_policies(self): + pq = [u"string"] + pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), pq) + with pytest.raises(TypeError): + x509.CertificatePolicies([1, pi]) + + def test_iter_len(self): + pq = [u"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_iter_input(self): + policies = [ + x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), [u"string"]) + ] + cp = x509.CertificatePolicies(iter(policies)) + assert list(cp) == policies + + def test_repr(self): + pq = [u"string"] + pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), pq) + cp = x509.CertificatePolicies([pi]) + if not six.PY2: + assert repr(cp) == ( + "<CertificatePolicies([<PolicyInformation(policy_identifier=<O" + "bjectIdentifier(oid=1.2.3, name=Unknown OID)>, policy_qualifi" + "ers=['string'])>])>" + ) + else: + assert repr(cp) == ( + "<CertificatePolicies([<PolicyInformation(policy_identifier=<O" + "bjectIdentifier(oid=1.2.3, name=Unknown OID)>, policy_qualifi" + "ers=[u'string'])>])>" + ) + + def test_eq(self): + pi = x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3"), [u"string"] + ) + cp = x509.CertificatePolicies([pi]) + pi2 = x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3"), [u"string"] + ) + cp2 = x509.CertificatePolicies([pi2]) + assert cp == cp2 + + def test_ne(self): + pi = x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3"), [u"string"] + ) + cp = x509.CertificatePolicies([pi]) + pi2 = x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3"), [u"string2"] + ) + cp2 = x509.CertificatePolicies([pi2]) + assert cp != cp2 + assert cp != object() + + def test_indexing(self): + pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), [u"test"]) + pi2 = x509.PolicyInformation(x509.ObjectIdentifier("1.2.4"), [u"test"]) + pi3 = x509.PolicyInformation(x509.ObjectIdentifier("1.2.5"), [u"test"]) + pi4 = x509.PolicyInformation(x509.ObjectIdentifier("1.2.6"), [u"test"]) + pi5 = x509.PolicyInformation(x509.ObjectIdentifier("1.2.7"), [u"test"]) + cp = x509.CertificatePolicies([pi, pi2, pi3, pi4, pi5]) + assert cp[-1] == cp[4] + assert cp[2:6:2] == [cp[2], cp[4]] + + def test_long_oid(self, backend): + """ + Test that parsing a CertificatePolicies ext with + a very long OID succeeds. + """ + cert = _load_cert( + os.path.join("x509", "bigoid.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_class( + x509.CertificatePolicies) + + oid = x509.ObjectIdentifier( + "1.3.6.1.4.1.311.21.8.8950086.10656446.2706058" + ".12775672.480128.147.13466065.13029902" + ) + + assert ext.value[0].policy_identifier == oid + + def test_hash(self): + pi = x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3"), [u"string"] + ) + cp = x509.CertificatePolicies([pi]) + pi2 = x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3"), [u"string"] + ) + cp2 = x509.CertificatePolicies([pi2]) + pi3 = x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3"), [x509.UserNotice(None, b"text")] + ) + cp3 = x509.CertificatePolicies([pi3]) + assert hash(cp) == hash(cp2) + assert hash(cp) != hash(cp3) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestCertificatePoliciesExtension(object): + def test_cps_uri_policy_qualifier(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "cp_cps_uri.pem"), + x509.load_pem_x509_certificate, + backend + ) + + cp = cert.extensions.get_extension_for_oid( + ExtensionOID.CERTIFICATE_POLICIES + ).value + + assert cp == x509.CertificatePolicies([ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [u"http://other.com/cps"] + ) + ]) + + def test_user_notice_with_notice_reference(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "cp_user_notice_with_notice_reference.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + + cp = cert.extensions.get_extension_for_oid( + ExtensionOID.CERTIFICATE_POLICIES + ).value + + assert cp == x509.CertificatePolicies([ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [ + u"http://example.com/cps", + u"http://other.com/cps", + x509.UserNotice( + x509.NoticeReference(u"my org", [1, 2, 3, 4]), + u"thing" + ) + ] + ) + ]) + + def test_user_notice_with_explicit_text(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "cp_user_notice_with_explicit_text.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + + cp = cert.extensions.get_extension_for_oid( + ExtensionOID.CERTIFICATE_POLICIES + ).value + + assert cp == x509.CertificatePolicies([ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [x509.UserNotice(None, u"thing")] + ) + ]) + + def test_user_notice_no_explicit_text(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "cp_user_notice_no_explicit_text.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + + cp = cert.extensions.get_extension_for_oid( + ExtensionOID.CERTIFICATE_POLICIES + ).value + + assert cp == x509.CertificatePolicies([ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [ + x509.UserNotice( + x509.NoticeReference(u"my org", [1, 2, 3, 4]), + None + ) + ] + ) + ]) + + +class TestKeyUsage(object): + def test_key_agreement_false_encipher_decipher_true(self): + with pytest.raises(ValueError): + x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=True, + decipher_only=False + ) + + with pytest.raises(ValueError): + x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=True, + decipher_only=True + ) + + with pytest.raises(ValueError): + x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=True + ) + + def test_properties_key_agreement_true(self): + ku = x509.KeyUsage( + digital_signature=True, + content_commitment=True, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=True, + crl_sign=False, + encipher_only=False, + decipher_only=False + ) + assert ku.digital_signature is True + assert ku.content_commitment is True + assert ku.key_encipherment is False + assert ku.data_encipherment is False + assert ku.key_agreement is False + assert ku.key_cert_sign is True + assert ku.crl_sign is False + + def test_key_agreement_true_properties(self): + ku = x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=True, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=True + ) + assert ku.key_agreement is True + assert ku.encipher_only is False + assert ku.decipher_only is True + + def test_key_agreement_false_properties(self): + ku = x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=False + ) + assert ku.key_agreement is False + with pytest.raises(ValueError): + ku.encipher_only + + with pytest.raises(ValueError): + ku.decipher_only + + def test_repr_key_agreement_false(self): + ku = x509.KeyUsage( + digital_signature=True, + content_commitment=True, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=True, + crl_sign=False, + encipher_only=False, + decipher_only=False + ) + assert repr(ku) == ( + "<KeyUsage(digital_signature=True, content_commitment=True, key_en" + "cipherment=False, data_encipherment=False, key_agreement=False, k" + "ey_cert_sign=True, crl_sign=False, encipher_only=None, decipher_o" + "nly=None)>" + ) + + def test_repr_key_agreement_true(self): + ku = x509.KeyUsage( + digital_signature=True, + content_commitment=True, + key_encipherment=False, + data_encipherment=False, + key_agreement=True, + key_cert_sign=True, + crl_sign=False, + encipher_only=False, + decipher_only=False + ) + assert repr(ku) == ( + "<KeyUsage(digital_signature=True, content_commitment=True, key_en" + "cipherment=False, data_encipherment=False, key_agreement=True, k" + "ey_cert_sign=True, crl_sign=False, encipher_only=False, decipher_" + "only=False)>" + ) + + def test_eq(self): + ku = x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=True, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=True + ) + ku2 = x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=True, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=True + ) + assert ku == ku2 + + def test_ne(self): + ku = x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=True, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=True + ) + ku2 = x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=False + ) + assert ku != ku2 + assert ku != object() + + def test_hash(self): + ku = x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=True, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=True + ) + ku2 = x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=True, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=True + ) + ku3 = x509.KeyUsage( + digital_signature=False, + content_commitment=True, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=False + ) + assert hash(ku) == hash(ku2) + assert hash(ku) != hash(ku3) + + +class TestSubjectKeyIdentifier(object): + def test_properties(self): + value = binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") + ski = x509.SubjectKeyIdentifier(value) + assert ski.digest == value + + def test_repr(self): + ski = x509.SubjectKeyIdentifier( + binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") + ) + ext = x509.Extension(ExtensionOID.SUBJECT_KEY_IDENTIFIER, False, ski) + if not six.PY2: + assert repr(ext) == ( + "<Extension(oid=<ObjectIdentifier(oid=2.5.29.14, name=subjectK" + "eyIdentifier)>, critical=False, value=<SubjectKeyIdentifier(d" + "igest=b\'\\t#\\x84\\x93\"0I\\x8b\\xc9\\x80\\xaa\\x80\\x98Eoo" + "\\xf7\\xff:\\xc9\')>)>" + ) + else: + assert repr(ext) == ( + "<Extension(oid=<ObjectIdentifier(oid=2.5.29.14, name=subjectK" + "eyIdentifier)>, critical=False, value=<SubjectKeyIdentifier(d" + "igest=\'\\t#\\x84\\x93\"0I\\x8b\\xc9\\x80\\xaa\\x80\\x98Eoo" + "\\xf7\\xff:\\xc9\')>)>" + ) + + def test_eq(self): + ski = x509.SubjectKeyIdentifier( + binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") + ) + ski2 = x509.SubjectKeyIdentifier( + binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") + ) + assert ski == ski2 + + def test_ne(self): + ski = x509.SubjectKeyIdentifier( + binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") + ) + ski2 = x509.SubjectKeyIdentifier( + binascii.unhexlify(b"aa8098456f6ff7ff3ac9092384932230498bc980") + ) + assert ski != ski2 + assert ski != object() + + def test_hash(self): + ski1 = x509.SubjectKeyIdentifier( + binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") + ) + ski2 = x509.SubjectKeyIdentifier( + binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") + ) + ski3 = x509.SubjectKeyIdentifier( + binascii.unhexlify(b"aa8098456f6ff7ff3ac9092384932230498bc980") + ) + assert hash(ski1) == hash(ski2) + assert hash(ski1) != hash(ski3) + + +class TestAuthorityKeyIdentifier(object): + def test_authority_cert_issuer_not_generalname(self): + with pytest.raises(TypeError): + x509.AuthorityKeyIdentifier(b"identifier", ["notname"], 3) + + def test_authority_cert_serial_number_not_integer(self): + dirname = x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + x509.ObjectIdentifier('2.999.1'), + u'value1' + ), + x509.NameAttribute( + x509.ObjectIdentifier('2.999.2'), + u'value2' + ), + ]) + ) + with pytest.raises(TypeError): + x509.AuthorityKeyIdentifier(b"identifier", [dirname], "notanint") + + def test_authority_issuer_none_serial_not_none(self): + with pytest.raises(ValueError): + x509.AuthorityKeyIdentifier(b"identifier", None, 3) + + def test_authority_issuer_not_none_serial_none(self): + dirname = x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + x509.ObjectIdentifier('2.999.1'), + u'value1' + ), + x509.NameAttribute( + x509.ObjectIdentifier('2.999.2'), + u'value2' + ), + ]) + ) + with pytest.raises(ValueError): + x509.AuthorityKeyIdentifier(b"identifier", [dirname], None) + + def test_authority_cert_serial_and_issuer_none(self): + aki = x509.AuthorityKeyIdentifier(b"id", None, None) + assert aki.key_identifier == b"id" + assert aki.authority_cert_issuer is None + assert aki.authority_cert_serial_number is None + + def test_authority_cert_serial_zero(self): + dns = x509.DNSName(u"SomeIssuer") + aki = x509.AuthorityKeyIdentifier(b"id", [dns], 0) + assert aki.key_identifier == b"id" + assert aki.authority_cert_issuer == [dns] + assert aki.authority_cert_serial_number == 0 + + def test_iter_input(self): + dirnames = [ + x509.DirectoryName( + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'myCN')]) + ) + ] + aki = x509.AuthorityKeyIdentifier(b"digest", iter(dirnames), 1234) + assert list(aki.authority_cert_issuer) == dirnames + + def test_repr(self): + dirname = x509.DirectoryName( + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'myCN')]) + ) + aki = x509.AuthorityKeyIdentifier(b"digest", [dirname], 1234) + + if not six.PY2: + assert repr(aki) == ( + "<AuthorityKeyIdentifier(key_identifier=b'digest', authority_" + "cert_issuer=[<DirectoryName(value=<Name(CN=myCN)>)>], author" + "ity_cert_serial_number=1234)>" + ) + else: + assert repr(aki) == ( + "<AuthorityKeyIdentifier(key_identifier='digest', authority_" + "cert_issuer=[<DirectoryName(value=<Name(CN=myCN)>)>], author" + "ity_cert_serial_number=1234)>" + ) + + def test_eq(self): + dirname = x509.DirectoryName( + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'myCN')]) + ) + aki = x509.AuthorityKeyIdentifier(b"digest", [dirname], 1234) + dirname2 = x509.DirectoryName( + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'myCN')]) + ) + aki2 = x509.AuthorityKeyIdentifier(b"digest", [dirname2], 1234) + assert aki == aki2 + + def test_ne(self): + dirname = x509.DirectoryName( + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'myCN')]) + ) + dirname5 = x509.DirectoryName( + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'aCN')]) + ) + aki = x509.AuthorityKeyIdentifier(b"digest", [dirname], 1234) + aki2 = x509.AuthorityKeyIdentifier(b"diges", [dirname], 1234) + aki3 = x509.AuthorityKeyIdentifier(b"digest", None, None) + aki4 = x509.AuthorityKeyIdentifier(b"digest", [dirname], 12345) + aki5 = x509.AuthorityKeyIdentifier(b"digest", [dirname5], 12345) + assert aki != aki2 + assert aki != aki3 + assert aki != aki4 + assert aki != aki5 + assert aki != object() + + def test_hash(self): + dirname = x509.DirectoryName( + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'myCN')]) + ) + aki1 = x509.AuthorityKeyIdentifier(b"digest", [dirname], 1234) + aki2 = x509.AuthorityKeyIdentifier(b"digest", [dirname], 1234) + aki3 = x509.AuthorityKeyIdentifier(b"digest", None, None) + assert hash(aki1) == hash(aki2) + assert hash(aki1) != hash(aki3) + + +class TestBasicConstraints(object): + def test_ca_not_boolean(self): + with pytest.raises(TypeError): + x509.BasicConstraints(ca="notbool", path_length=None) + + def test_path_length_not_ca(self): + with pytest.raises(ValueError): + x509.BasicConstraints(ca=False, path_length=0) + + def test_path_length_not_int(self): + with pytest.raises(TypeError): + x509.BasicConstraints(ca=True, path_length=1.1) + + with pytest.raises(TypeError): + x509.BasicConstraints(ca=True, path_length="notint") + + def test_path_length_negative(self): + with pytest.raises(TypeError): + x509.BasicConstraints(ca=True, path_length=-1) + + def test_repr(self): + na = x509.BasicConstraints(ca=True, path_length=None) + assert repr(na) == ( + "<BasicConstraints(ca=True, path_length=None)>" + ) + + def test_hash(self): + na = x509.BasicConstraints(ca=True, path_length=None) + na2 = x509.BasicConstraints(ca=True, path_length=None) + na3 = x509.BasicConstraints(ca=True, path_length=0) + assert hash(na) == hash(na2) + assert hash(na) != hash(na3) + + def test_eq(self): + na = x509.BasicConstraints(ca=True, path_length=None) + na2 = x509.BasicConstraints(ca=True, path_length=None) + assert na == na2 + + def test_ne(self): + na = x509.BasicConstraints(ca=True, path_length=None) + na2 = x509.BasicConstraints(ca=True, path_length=1) + na3 = x509.BasicConstraints(ca=False, path_length=None) + assert na != na2 + assert na != na3 + assert na != object() + + +class TestExtendedKeyUsage(object): + def test_not_all_oids(self): + with pytest.raises(TypeError): + x509.ExtendedKeyUsage(["notoid"]) + + def test_iter_len(self): + eku = x509.ExtendedKeyUsage([ + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.1"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.2"), + ]) + assert len(eku) == 2 + assert list(eku) == [ + ExtendedKeyUsageOID.SERVER_AUTH, + ExtendedKeyUsageOID.CLIENT_AUTH + ] + + def test_iter_input(self): + usages = [ + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.1"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.2"), + ] + aia = x509.ExtendedKeyUsage(iter(usages)) + assert list(aia) == usages + + def test_repr(self): + eku = x509.ExtendedKeyUsage([ + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.1"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.2"), + ]) + assert repr(eku) == ( + "<ExtendedKeyUsage([<ObjectIdentifier(oid=1.3.6.1.5.5.7.3.1, name=" + "serverAuth)>, <ObjectIdentifier(oid=1.3.6.1.5.5.7.3.2, name=clien" + "tAuth)>])>" + ) + + def test_eq(self): + eku = x509.ExtendedKeyUsage([ + x509.ObjectIdentifier("1.3.6"), x509.ObjectIdentifier("1.3.7") + ]) + eku2 = x509.ExtendedKeyUsage([ + x509.ObjectIdentifier("1.3.6"), x509.ObjectIdentifier("1.3.7") + ]) + assert eku == eku2 + + def test_ne(self): + eku = x509.ExtendedKeyUsage([x509.ObjectIdentifier("1.3.6")]) + eku2 = x509.ExtendedKeyUsage([x509.ObjectIdentifier("1.3.6.1")]) + assert eku != eku2 + assert eku != object() + + def test_hash(self): + eku = x509.ExtendedKeyUsage([ + x509.ObjectIdentifier("1.3.6"), x509.ObjectIdentifier("1.3.7") + ]) + eku2 = x509.ExtendedKeyUsage([ + x509.ObjectIdentifier("1.3.6"), x509.ObjectIdentifier("1.3.7") + ]) + eku3 = x509.ExtendedKeyUsage([x509.ObjectIdentifier("1.3.6")]) + assert hash(eku) == hash(eku2) + assert hash(eku) != hash(eku3) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestExtensions(object): + def test_no_extensions(self, backend): + cert = _load_cert( + os.path.join("x509", "verisign_md2_root.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions + assert len(ext) == 0 + assert list(ext) == [] + with pytest.raises(x509.ExtensionNotFound) as exc: + ext.get_extension_for_oid(ExtensionOID.BASIC_CONSTRAINTS) + + assert exc.value.oid == ExtensionOID.BASIC_CONSTRAINTS + + def test_one_extension(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "basic_constraints_not_critical.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + extensions = cert.extensions + ext = extensions.get_extension_for_oid(ExtensionOID.BASIC_CONSTRAINTS) + assert ext is not None + assert ext.value.ca is False + + def test_duplicate_extension(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "two_basic_constraints.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + with pytest.raises(x509.DuplicateExtension) as exc: + cert.extensions + + assert exc.value.oid == ExtensionOID.BASIC_CONSTRAINTS + + def test_unsupported_critical_extension(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "unsupported_extension_critical.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.ObjectIdentifier("1.2.3.4") + ) + assert ext.value.value == b"value" + + @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) + def test_unsupported_extension(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "unsupported_extension_2.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + extensions = cert.extensions + assert len(extensions) == 2 + assert extensions[0].critical is False + assert extensions[0].oid == x509.ObjectIdentifier( + "1.3.6.1.4.1.41482.2" + ) + assert extensions[0].value == x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.3.6.1.4.1.41482.2"), + b"1.3.6.1.4.1.41482.1.2" + ) + assert extensions[1].critical is False + assert extensions[1].oid == x509.ObjectIdentifier( + "1.3.6.1.4.1.45724.2.1.1" + ) + assert extensions[1].value == x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.3.6.1.4.1.45724.2.1.1"), + b"\x03\x02\x040" + ) + + def test_no_extensions_get_for_class(self, backend): + cert = _load_cert( + os.path.join( + "x509", "cryptography.io.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + exts = cert.extensions + with pytest.raises(x509.ExtensionNotFound) as exc: + exts.get_extension_for_class(x509.IssuerAlternativeName) + assert exc.value.oid == ExtensionOID.ISSUER_ALTERNATIVE_NAME + + def test_unrecognized_extension_for_class(self): + exts = x509.Extensions([]) + with pytest.raises(TypeError): + exts.get_extension_for_class(x509.UnrecognizedExtension) + + def test_indexing(self, backend): + cert = _load_cert( + os.path.join("x509", "cryptography.io.pem"), + x509.load_pem_x509_certificate, + backend + ) + exts = cert.extensions + assert exts[-1] == exts[7] + assert exts[2:6:2] == [exts[2], exts[4]] + + def test_one_extension_get_for_class(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "basic_constraints_not_critical.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_class(x509.BasicConstraints) + assert ext is not None + assert isinstance(ext.value, x509.BasicConstraints) + + def test_repr(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "basic_constraints_not_critical.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + assert repr(cert.extensions) == ( + "<Extensions([<Extension(oid=<ObjectIdentifier(oid=2.5.29.19, name" + "=basicConstraints)>, critical=False, value=<BasicConstraints(ca=F" + "alse, path_length=None)>)>])>" + ) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestBasicConstraintsExtension(object): + def test_ca_true_pathlen_6(self, backend): + cert = _load_cert( + os.path.join( + "x509", "PKITS_data", "certs", "pathLenConstraint6CACert.crt" + ), + x509.load_der_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.BASIC_CONSTRAINTS + ) + assert ext is not None + assert ext.critical is True + assert ext.value.ca is True + assert ext.value.path_length == 6 + + def test_path_length_zero(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "bc_path_length_zero.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.BASIC_CONSTRAINTS + ) + assert ext is not None + assert ext.critical is True + assert ext.value.ca is True + assert ext.value.path_length == 0 + + def test_ca_true_no_pathlen(self, backend): + cert = _load_cert( + os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), + x509.load_der_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.BASIC_CONSTRAINTS + ) + assert ext is not None + assert ext.critical is True + assert ext.value.ca is True + assert ext.value.path_length is None + + def test_ca_false(self, backend): + cert = _load_cert( + os.path.join("x509", "cryptography.io.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.BASIC_CONSTRAINTS + ) + assert ext is not None + assert ext.critical is True + assert ext.value.ca is False + assert ext.value.path_length is None + + def test_no_basic_constraints(self, backend): + cert = _load_cert( + os.path.join( + "x509", + "PKITS_data", + "certs", + "ValidCertificatePathTest1EE.crt" + ), + x509.load_der_x509_certificate, + backend + ) + with pytest.raises(x509.ExtensionNotFound): + cert.extensions.get_extension_for_oid( + ExtensionOID.BASIC_CONSTRAINTS + ) + + def test_basic_constraint_not_critical(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "basic_constraints_not_critical.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.BASIC_CONSTRAINTS + ) + assert ext is not None + assert ext.critical is False + assert ext.value.ca is False + + +class TestSubjectKeyIdentifierExtension(object): + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_subject_key_identifier(self, backend): + cert = _load_cert( + os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), + x509.load_der_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_KEY_IDENTIFIER + ) + ski = ext.value + assert ext is not None + assert ext.critical is False + assert ski.digest == binascii.unhexlify( + b"580184241bbc2b52944a3da510721451f5af3ac9" + ) + + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_no_subject_key_identifier(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "bc_path_length_zero.pem"), + x509.load_pem_x509_certificate, + backend + ) + with pytest.raises(x509.ExtensionNotFound): + cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_KEY_IDENTIFIER + ) + + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_from_rsa_public_key(self, backend): + cert = _load_cert( + os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), + x509.load_der_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_KEY_IDENTIFIER + ) + ski = x509.SubjectKeyIdentifier.from_public_key( + cert.public_key() + ) + assert ext.value == ski + + @pytest.mark.requires_backend_interface(interface=DSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_from_dsa_public_key(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "dsa_selfsigned_ca.pem"), + x509.load_pem_x509_certificate, + backend + ) + + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_KEY_IDENTIFIER + ) + ski = x509.SubjectKeyIdentifier.from_public_key( + cert.public_key() + ) + assert ext.value == ski + + @pytest.mark.requires_backend_interface(interface=DSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_invalid_bit_string_padding_from_public_key(self, backend): + data = load_vectors_from_file( + filename=os.path.join( + "asymmetric", "DER_Serialization", + "dsa_public_key_invalid_bit_string.der" + ), loader=lambda data: data.read(), mode="rb" + ) + pretend_key = pretend.stub(public_bytes=lambda x, y: data) + with pytest.raises(ValueError): + _key_identifier_from_public_key(pretend_key) + + @pytest.mark.requires_backend_interface(interface=DSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_no_optional_params_allowed_from_public_key(self, backend): + data = load_vectors_from_file( + filename=os.path.join( + "asymmetric", "DER_Serialization", + "dsa_public_key_no_params.der" + ), loader=lambda data: data.read(), mode="rb" + ) + pretend_key = pretend.stub(public_bytes=lambda x, y: data) + key_identifier = _key_identifier_from_public_key(pretend_key) + assert key_identifier == binascii.unhexlify( + b"24c0133a6a492f2c48a18c7648e515db5ac76749" + ) + + @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_from_ec_public_key(self, backend): + _skip_curve_unsupported(backend, ec.SECP384R1()) + cert = _load_cert( + os.path.join("x509", "ecdsa_root.pem"), + x509.load_pem_x509_certificate, + backend + ) + + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_KEY_IDENTIFIER + ) + ski = x509.SubjectKeyIdentifier.from_public_key( + cert.public_key() + ) + assert ext.value == ski + + @pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_from_ed25519_public_key(self, backend): + cert = _load_cert( + os.path.join("x509", "ed25519", "root-ed25519.pem"), + x509.load_pem_x509_certificate, + backend + ) + + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_KEY_IDENTIFIER + ) + ski = x509.SubjectKeyIdentifier.from_public_key( + cert.public_key() + ) + assert ext.value == ski + + @pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support" + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_from_ed448_public_key(self, backend): + cert = _load_cert( + os.path.join("x509", "ed448", "root-ed448.pem"), + x509.load_pem_x509_certificate, + backend + ) + + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_KEY_IDENTIFIER + ) + ski = x509.SubjectKeyIdentifier.from_public_key( + cert.public_key() + ) + assert ext.value == ski + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestKeyUsageExtension(object): + def test_no_key_usage(self, backend): + cert = _load_cert( + os.path.join("x509", "verisign_md2_root.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions + with pytest.raises(x509.ExtensionNotFound) as exc: + ext.get_extension_for_oid(ExtensionOID.KEY_USAGE) + + assert exc.value.oid == ExtensionOID.KEY_USAGE + + def test_all_purposes(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "all_key_usages.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + extensions = cert.extensions + ext = extensions.get_extension_for_oid(ExtensionOID.KEY_USAGE) + assert ext is not None + + ku = ext.value + assert ku.digital_signature is True + assert ku.content_commitment is True + assert ku.key_encipherment is True + assert ku.data_encipherment is True + assert ku.key_agreement is True + assert ku.key_cert_sign is True + assert ku.crl_sign is True + assert ku.encipher_only is True + assert ku.decipher_only is True + + def test_key_cert_sign_crl_sign(self, backend): + cert = _load_cert( + os.path.join( + "x509", "PKITS_data", "certs", "pathLenConstraint6CACert.crt" + ), + x509.load_der_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid(ExtensionOID.KEY_USAGE) + assert ext is not None + assert ext.critical is True + + ku = ext.value + assert ku.digital_signature is False + assert ku.content_commitment is False + assert ku.key_encipherment is False + assert ku.data_encipherment is False + assert ku.key_agreement is False + assert ku.key_cert_sign is True + assert ku.crl_sign is True + + +class TestDNSName(object): + def test_init_deprecated(self): + pytest.importorskip("idna") + with pytest.warns(utils.CryptographyDeprecationWarning): + name = x509.DNSName(u".\xf5\xe4\xf6\xfc.example.com") + assert name.value == u".xn--4ca7aey.example.com" + + with pytest.warns(utils.CryptographyDeprecationWarning): + name = x509.DNSName(u"\xf5\xe4\xf6\xfc.example.com") + assert name.value == u"xn--4ca7aey.example.com" + + def test_init(self): + name = x509.DNSName(u"*.xn--4ca7aey.example.com") + assert name.value == u"*.xn--4ca7aey.example.com" + + with pytest.raises(TypeError): + x509.DNSName(1.3) + + with pytest.raises(TypeError): + x509.DNSName(b"bytes not allowed") + + def test_ne(self): + n1 = x509.DNSName(u"test1") + n2 = x509.DNSName(u"test2") + n3 = x509.DNSName(u"test2") + assert n1 != n2 + assert not (n2 != n3) + + def test_hash(self): + n1 = x509.DNSName(u"test1") + n2 = x509.DNSName(u"test2") + n3 = x509.DNSName(u"test2") + assert hash(n1) != hash(n2) + assert hash(n2) == hash(n3) + + +class TestDirectoryName(object): + def test_not_name(self): + with pytest.raises(TypeError): + x509.DirectoryName(b"notaname") + + with pytest.raises(TypeError): + x509.DirectoryName(1.3) + + def test_repr(self): + name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'value1')]) + gn = x509.DirectoryName(name) + assert repr(gn) == "<DirectoryName(value=<Name(CN=value1)>)>" + + def test_eq(self): + name = x509.Name([ + x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1') + ]) + name2 = x509.Name([ + x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1') + ]) + gn = x509.DirectoryName(name) + gn2 = x509.DirectoryName(name2) + assert gn == gn2 + + def test_ne(self): + name = x509.Name([ + x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1') + ]) + name2 = x509.Name([ + x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2') + ]) + gn = x509.DirectoryName(name) + gn2 = x509.DirectoryName(name2) + assert gn != gn2 + assert gn != object() + + def test_hash(self): + name = x509.Name([ + x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1') + ]) + name2 = x509.Name([ + x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2') + ]) + gn = x509.DirectoryName(name) + gn2 = x509.DirectoryName(name) + gn3 = x509.DirectoryName(name2) + assert hash(gn) == hash(gn2) + assert hash(gn) != hash(gn3) + + +class TestRFC822Name(object): + def test_repr(self): + gn = x509.RFC822Name(u"string") + if not six.PY2: + assert repr(gn) == "<RFC822Name(value='string')>" + else: + assert repr(gn) == "<RFC822Name(value=u'string')>" + + def test_equality(self): + gn = x509.RFC822Name(u"string") + gn2 = x509.RFC822Name(u"string2") + gn3 = x509.RFC822Name(u"string") + assert gn != gn2 + assert gn != object() + assert gn == gn3 + + def test_not_text(self): + with pytest.raises(TypeError): + x509.RFC822Name(1.3) + + with pytest.raises(TypeError): + x509.RFC822Name(b"bytes") + + def test_invalid_email(self): + with pytest.raises(ValueError): + x509.RFC822Name(u"Name <email>") + + with pytest.raises(ValueError): + x509.RFC822Name(u"") + + def test_single_label(self): + gn = x509.RFC822Name(u"administrator") + assert gn.value == u"administrator" + + def test_idna(self): + pytest.importorskip("idna") + with pytest.warns(utils.CryptographyDeprecationWarning): + gn = x509.RFC822Name(u"email@em\xe5\xefl.com") + + assert gn.value == u"email@xn--eml-vla4c.com" + + gn2 = x509.RFC822Name(u"email@xn--eml-vla4c.com") + assert gn2.value == u"email@xn--eml-vla4c.com" + + def test_hash(self): + g1 = x509.RFC822Name(u"email@host.com") + g2 = x509.RFC822Name(u"email@host.com") + g3 = x509.RFC822Name(u"admin@host.com") + + assert hash(g1) == hash(g2) + assert hash(g1) != hash(g3) + + +class TestUniformResourceIdentifier(object): + def test_equality(self): + gn = x509.UniformResourceIdentifier(u"string") + gn2 = x509.UniformResourceIdentifier(u"string2") + gn3 = x509.UniformResourceIdentifier(u"string") + assert gn != gn2 + assert gn != object() + assert gn == gn3 + + def test_not_text(self): + with pytest.raises(TypeError): + x509.UniformResourceIdentifier(1.3) + + def test_no_parsed_hostname(self): + gn = x509.UniformResourceIdentifier(u"singlelabel") + assert gn.value == u"singlelabel" + + def test_with_port(self): + gn = x509.UniformResourceIdentifier(u"singlelabel:443/test") + assert gn.value == u"singlelabel:443/test" + + def test_idna_no_port(self): + pytest.importorskip("idna") + with pytest.warns(utils.CryptographyDeprecationWarning): + gn = x509.UniformResourceIdentifier( + u"http://\u043f\u044b\u043a\u0430.cryptography" + ) + + assert gn.value == u"http://xn--80ato2c.cryptography" + + def test_idna_with_port(self): + pytest.importorskip("idna") + with pytest.warns(utils.CryptographyDeprecationWarning): + gn = x509.UniformResourceIdentifier( + u"gopher://\u043f\u044b\u043a\u0430.cryptography:70/some/path" + ) + + assert gn.value == ( + u"gopher://xn--80ato2c.cryptography:70/some/path" + ) + + def test_empty_hostname(self): + gn = x509.UniformResourceIdentifier(u"ldap:///some-nonsense") + assert gn.value == "ldap:///some-nonsense" + + def test_query_and_fragment(self): + pytest.importorskip("idna") + with pytest.warns(utils.CryptographyDeprecationWarning): + gn = x509.UniformResourceIdentifier( + u"ldap://\u043f\u044b\u043a\u0430.cryptography:90/path?query=" + u"true#somedata" + ) + assert gn.value == ( + u"ldap://xn--80ato2c.cryptography:90/path?query=true#somedata" + ) + + def test_hash(self): + g1 = x509.UniformResourceIdentifier(u"http://host.com") + g2 = x509.UniformResourceIdentifier(u"http://host.com") + g3 = x509.UniformResourceIdentifier(u"http://other.com") + + assert hash(g1) == hash(g2) + assert hash(g1) != hash(g3) + + def test_repr(self): + gn = x509.UniformResourceIdentifier(u"string") + if not six.PY2: + assert repr(gn) == ( + "<UniformResourceIdentifier(value='string')>" + ) + else: + assert repr(gn) == ( + "<UniformResourceIdentifier(value=u'string')>" + ) + + +class TestRegisteredID(object): + def test_not_oid(self): + with pytest.raises(TypeError): + x509.RegisteredID(b"notanoid") + + with pytest.raises(TypeError): + x509.RegisteredID(1.3) + + def test_repr(self): + gn = x509.RegisteredID(NameOID.COMMON_NAME) + assert repr(gn) == ( + "<RegisteredID(value=<ObjectIdentifier(oid=2.5.4.3, name=commonNam" + "e)>)>" + ) + + def test_eq(self): + gn = x509.RegisteredID(NameOID.COMMON_NAME) + gn2 = x509.RegisteredID(NameOID.COMMON_NAME) + assert gn == gn2 + + def test_ne(self): + gn = x509.RegisteredID(NameOID.COMMON_NAME) + gn2 = x509.RegisteredID(ExtensionOID.BASIC_CONSTRAINTS) + assert gn != gn2 + assert gn != object() + + def test_hash(self): + gn = x509.RegisteredID(NameOID.COMMON_NAME) + gn2 = x509.RegisteredID(NameOID.COMMON_NAME) + gn3 = x509.RegisteredID(ExtensionOID.BASIC_CONSTRAINTS) + assert hash(gn) == hash(gn2) + assert hash(gn) != hash(gn3) + + +class TestIPAddress(object): + def test_not_ipaddress(self): + with pytest.raises(TypeError): + x509.IPAddress(b"notanipaddress") + + with pytest.raises(TypeError): + x509.IPAddress(1.3) + + def test_repr(self): + gn = x509.IPAddress(ipaddress.IPv4Address(u"127.0.0.1")) + assert repr(gn) == "<IPAddress(value=127.0.0.1)>" + + gn2 = x509.IPAddress(ipaddress.IPv6Address(u"ff::")) + assert repr(gn2) == "<IPAddress(value=ff::)>" + + gn3 = x509.IPAddress(ipaddress.IPv4Network(u"192.168.0.0/24")) + assert repr(gn3) == "<IPAddress(value=192.168.0.0/24)>" + + gn4 = x509.IPAddress(ipaddress.IPv6Network(u"ff::/96")) + assert repr(gn4) == "<IPAddress(value=ff::/96)>" + + def test_eq(self): + gn = x509.IPAddress(ipaddress.IPv4Address(u"127.0.0.1")) + gn2 = x509.IPAddress(ipaddress.IPv4Address(u"127.0.0.1")) + assert gn == gn2 + + def test_ne(self): + gn = x509.IPAddress(ipaddress.IPv4Address(u"127.0.0.1")) + gn2 = x509.IPAddress(ipaddress.IPv4Address(u"127.0.0.2")) + assert gn != gn2 + assert gn != object() + + def test_hash(self): + gn = x509.IPAddress(ipaddress.IPv4Address(u"127.0.0.1")) + gn2 = x509.IPAddress(ipaddress.IPv4Address(u"127.0.0.1")) + gn3 = x509.IPAddress(ipaddress.IPv4Address(u"127.0.0.2")) + assert hash(gn) == hash(gn2) + assert hash(gn) != hash(gn3) + + +class TestOtherName(object): + def test_invalid_args(self): + with pytest.raises(TypeError): + x509.OtherName(b"notanobjectidentifier", b"derdata") + + with pytest.raises(TypeError): + x509.OtherName(x509.ObjectIdentifier("1.2.3.4"), u"notderdata") + + def test_repr(self): + gn = x509.OtherName(x509.ObjectIdentifier("1.2.3.4"), b"derdata") + if not six.PY2: + assert repr(gn) == ( + "<OtherName(type_id=<ObjectIdentifier(oid=1.2.3.4, " + "name=Unknown OID)>, value=b'derdata')>" + ) + else: + assert repr(gn) == ( + "<OtherName(type_id=<ObjectIdentifier(oid=1.2.3.4, " + "name=Unknown OID)>, value='derdata')>" + ) + + gn = x509.OtherName(x509.ObjectIdentifier("2.5.4.65"), b"derdata") + if not six.PY2: + assert repr(gn) == ( + "<OtherName(type_id=<ObjectIdentifier(oid=2.5.4.65, " + "name=pseudonym)>, value=b'derdata')>" + ) + else: + assert repr(gn) == ( + "<OtherName(type_id=<ObjectIdentifier(oid=2.5.4.65, " + "name=pseudonym)>, value='derdata')>" + ) + + def test_eq(self): + gn = x509.OtherName(x509.ObjectIdentifier("1.2.3.4"), b"derdata") + gn2 = x509.OtherName(x509.ObjectIdentifier("1.2.3.4"), b"derdata") + assert gn == gn2 + + def test_ne(self): + gn = x509.OtherName(x509.ObjectIdentifier("1.2.3.4"), b"derdata") + assert gn != object() + + gn2 = x509.OtherName(x509.ObjectIdentifier("1.2.3.4"), b"derdata2") + assert gn != gn2 + + gn2 = x509.OtherName(x509.ObjectIdentifier("1.2.3.5"), b"derdata") + assert gn != gn2 + + def test_hash(self): + gn = x509.OtherName(x509.ObjectIdentifier("1.2.3.4"), b"derdata") + gn2 = x509.OtherName(x509.ObjectIdentifier("1.2.3.4"), b"derdata") + gn3 = x509.OtherName(x509.ObjectIdentifier("1.2.3.5"), b"derdata") + assert hash(gn) == hash(gn2) + assert hash(gn) != hash(gn3) + + +class TestGeneralNames(object): + def test_get_values_for_type(self): + gns = x509.GeneralNames( + [x509.DNSName(u"cryptography.io")] + ) + names = gns.get_values_for_type(x509.DNSName) + assert names == [u"cryptography.io"] + + def test_iter_names(self): + gns = x509.GeneralNames([ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + ]) + assert len(gns) == 2 + assert list(gns) == [ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + ] + + def test_iter_input(self): + names = [ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + ] + gns = x509.GeneralNames(iter(names)) + assert list(gns) == names + + def test_indexing(self): + gn = x509.GeneralNames([ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + x509.DNSName(u"another.local"), + x509.RFC822Name(u"email@another.local"), + x509.UniformResourceIdentifier(u"http://another.local"), + ]) + assert gn[-1] == gn[4] + assert gn[2:6:2] == [gn[2], gn[4]] + + def test_invalid_general_names(self): + with pytest.raises(TypeError): + x509.GeneralNames( + [x509.DNSName(u"cryptography.io"), "invalid"] + ) + + def test_repr(self): + gns = x509.GeneralNames( + [ + x509.DNSName(u"cryptography.io") + ] + ) + if not six.PY2: + assert repr(gns) == ( + "<GeneralNames([<DNSName(value='cryptography.io')>])>" + ) + else: + assert repr(gns) == ( + "<GeneralNames([<DNSName(value=u'cryptography.io')>])>" + ) + + def test_eq(self): + gns = x509.GeneralNames( + [x509.DNSName(u"cryptography.io")] + ) + gns2 = x509.GeneralNames( + [x509.DNSName(u"cryptography.io")] + ) + assert gns == gns2 + + def test_ne(self): + gns = x509.GeneralNames( + [x509.DNSName(u"cryptography.io")] + ) + gns2 = x509.GeneralNames( + [x509.RFC822Name(u"admin@cryptography.io")] + ) + assert gns != gns2 + assert gns != object() + + def test_hash(self): + gns = x509.GeneralNames([x509.DNSName(u"cryptography.io")]) + gns2 = x509.GeneralNames([x509.DNSName(u"cryptography.io")]) + gns3 = x509.GeneralNames([x509.RFC822Name(u"admin@cryptography.io")]) + assert hash(gns) == hash(gns2) + assert hash(gns) != hash(gns3) + + +class TestIssuerAlternativeName(object): + def test_get_values_for_type(self): + san = x509.IssuerAlternativeName( + [x509.DNSName(u"cryptography.io")] + ) + names = san.get_values_for_type(x509.DNSName) + assert names == [u"cryptography.io"] + + def test_iter_names(self): + san = x509.IssuerAlternativeName([ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + ]) + assert len(san) == 2 + assert list(san) == [ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + ] + + def test_indexing(self): + ian = x509.IssuerAlternativeName([ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + x509.DNSName(u"another.local"), + x509.RFC822Name(u"email@another.local"), + x509.UniformResourceIdentifier(u"http://another.local"), + ]) + assert ian[-1] == ian[4] + assert ian[2:6:2] == [ian[2], ian[4]] + + def test_invalid_general_names(self): + with pytest.raises(TypeError): + x509.IssuerAlternativeName( + [x509.DNSName(u"cryptography.io"), "invalid"] + ) + + def test_repr(self): + san = x509.IssuerAlternativeName( + [ + x509.DNSName(u"cryptography.io") + ] + ) + if not six.PY2: + assert repr(san) == ( + "<IssuerAlternativeName(" + "<GeneralNames([<DNSName(value='cryptography.io')>])>)>" + ) + else: + assert repr(san) == ( + "<IssuerAlternativeName(" + "<GeneralNames([<DNSName(value=u'cryptography.io')>])>)>" + ) + + def test_eq(self): + san = x509.IssuerAlternativeName( + [x509.DNSName(u"cryptography.io")] + ) + san2 = x509.IssuerAlternativeName( + [x509.DNSName(u"cryptography.io")] + ) + assert san == san2 + + def test_ne(self): + san = x509.IssuerAlternativeName( + [x509.DNSName(u"cryptography.io")] + ) + san2 = x509.IssuerAlternativeName( + [x509.RFC822Name(u"admin@cryptography.io")] + ) + assert san != san2 + assert san != object() + + def test_hash(self): + ian = x509.IssuerAlternativeName([x509.DNSName(u"cryptography.io")]) + ian2 = x509.IssuerAlternativeName([x509.DNSName(u"cryptography.io")]) + ian3 = x509.IssuerAlternativeName( + [x509.RFC822Name(u"admin@cryptography.io")] + ) + assert hash(ian) == hash(ian2) + assert hash(ian) != hash(ian3) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestRSAIssuerAlternativeNameExtension(object): + def test_uri(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "ian_uri.pem"), + x509.load_pem_x509_certificate, + backend, + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.ISSUER_ALTERNATIVE_NAME + ) + assert list(ext.value) == [ + x509.UniformResourceIdentifier(u"http://path.to.root/root.crt"), + ] + + +class TestCRLNumber(object): + def test_eq(self): + crl_number = x509.CRLNumber(15) + assert crl_number == x509.CRLNumber(15) + + def test_ne(self): + crl_number = x509.CRLNumber(15) + assert crl_number != x509.CRLNumber(14) + assert crl_number != object() + + def test_repr(self): + crl_number = x509.CRLNumber(15) + assert repr(crl_number) == "<CRLNumber(15)>" + + def test_invalid_number(self): + with pytest.raises(TypeError): + x509.CRLNumber("notanumber") + + def test_hash(self): + c1 = x509.CRLNumber(1) + c2 = x509.CRLNumber(1) + c3 = x509.CRLNumber(2) + assert hash(c1) == hash(c2) + assert hash(c1) != hash(c3) + + +class TestSubjectAlternativeName(object): + def test_get_values_for_type(self): + san = x509.SubjectAlternativeName( + [x509.DNSName(u"cryptography.io")] + ) + names = san.get_values_for_type(x509.DNSName) + assert names == [u"cryptography.io"] + + def test_iter_names(self): + san = x509.SubjectAlternativeName([ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + ]) + assert len(san) == 2 + assert list(san) == [ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + ] + + def test_indexing(self): + san = x509.SubjectAlternativeName([ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + x509.DNSName(u"another.local"), + x509.RFC822Name(u"email@another.local"), + x509.UniformResourceIdentifier(u"http://another.local"), + ]) + assert san[-1] == san[4] + assert san[2:6:2] == [san[2], san[4]] + + def test_invalid_general_names(self): + with pytest.raises(TypeError): + x509.SubjectAlternativeName( + [x509.DNSName(u"cryptography.io"), "invalid"] + ) + + def test_repr(self): + san = x509.SubjectAlternativeName( + [ + x509.DNSName(u"cryptography.io") + ] + ) + if not six.PY2: + assert repr(san) == ( + "<SubjectAlternativeName(" + "<GeneralNames([<DNSName(value='cryptography.io')>])>)>" + ) + else: + assert repr(san) == ( + "<SubjectAlternativeName(" + "<GeneralNames([<DNSName(value=u'cryptography.io')>])>)>" + ) + + def test_eq(self): + san = x509.SubjectAlternativeName( + [x509.DNSName(u"cryptography.io")] + ) + san2 = x509.SubjectAlternativeName( + [x509.DNSName(u"cryptography.io")] + ) + assert san == san2 + + def test_ne(self): + san = x509.SubjectAlternativeName( + [x509.DNSName(u"cryptography.io")] + ) + san2 = x509.SubjectAlternativeName( + [x509.RFC822Name(u"admin@cryptography.io")] + ) + assert san != san2 + assert san != object() + + def test_hash(self): + san = x509.SubjectAlternativeName([x509.DNSName(u"cryptography.io")]) + san2 = x509.SubjectAlternativeName([x509.DNSName(u"cryptography.io")]) + san3 = x509.SubjectAlternativeName( + [x509.RFC822Name(u"admin@cryptography.io")] + ) + assert hash(san) == hash(san2) + assert hash(san) != hash(san3) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestRSASubjectAlternativeNameExtension(object): + def test_dns_name(self, backend): + cert = _load_cert( + os.path.join("x509", "cryptography.io.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_ALTERNATIVE_NAME + ) + assert ext is not None + assert ext.critical is False + + san = ext.value + + dns = san.get_values_for_type(x509.DNSName) + assert dns == [u"www.cryptography.io", u"cryptography.io"] + + def test_wildcard_dns_name(self, backend): + cert = _load_cert( + os.path.join("x509", "wildcard_san.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_ALTERNATIVE_NAME + ) + + dns = ext.value.get_values_for_type(x509.DNSName) + assert dns == [ + u'*.langui.sh', + u'langui.sh', + u'*.saseliminator.com', + u'saseliminator.com' + ] + + def test_san_empty_hostname(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_empty_hostname.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + san = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_ALTERNATIVE_NAME + ) + + dns = san.value.get_values_for_type(x509.DNSName) + assert dns == [u''] + + def test_san_wildcard_idna_dns_name(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "san_wildcard_idna.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_ALTERNATIVE_NAME + ) + + dns = ext.value.get_values_for_type(x509.DNSName) + assert dns == [u'*.xn--80ato2c.cryptography'] + + def test_unsupported_gn(self, backend): + cert = _load_cert( + os.path.join("x509", "san_x400address.der"), + x509.load_der_x509_certificate, + backend + ) + with pytest.raises(x509.UnsupportedGeneralNameType) as exc: + cert.extensions + + assert exc.value.type == 3 + + def test_registered_id(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_registered_id.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_ALTERNATIVE_NAME + ) + assert ext is not None + assert ext.critical is False + + san = ext.value + rid = san.get_values_for_type(x509.RegisteredID) + assert rid == [x509.ObjectIdentifier("1.2.3.4")] + + def test_uri(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_uri_with_port.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_ALTERNATIVE_NAME + ) + assert ext is not None + uri = ext.value.get_values_for_type( + x509.UniformResourceIdentifier + ) + assert uri == [ + u"gopher://xn--80ato2c.cryptography:70/path?q=s#hel" + u"lo", + u"http://someregulardomain.com", + ] + + def test_ipaddress(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_ipaddr.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_ALTERNATIVE_NAME + ) + assert ext is not None + assert ext.critical is False + + san = ext.value + + ip = san.get_values_for_type(x509.IPAddress) + assert [ + ipaddress.ip_address(u"127.0.0.1"), + ipaddress.ip_address(u"ff::") + ] == ip + + def test_dirname(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_dirname.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_ALTERNATIVE_NAME + ) + assert ext is not None + assert ext.critical is False + + san = ext.value + + dirname = san.get_values_for_type(x509.DirectoryName) + assert [ + x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u'test'), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'Org'), + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u'Texas'), + ]) + ] == dirname + + def test_rfc822name(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_rfc822_idna.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_ALTERNATIVE_NAME + ) + assert ext is not None + assert ext.critical is False + + san = ext.value + + rfc822name = san.get_values_for_type(x509.RFC822Name) + assert [u"email@xn--eml-vla4c.com"] == rfc822name + + def test_idna2003_invalid(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_idna2003_dnsname.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + san = cert.extensions.get_extension_for_class( + x509.SubjectAlternativeName + ).value + + assert len(san) == 1 + [name] = san + assert name.value == u"xn--k4h.ws" + + def test_unicode_rfc822_name_dns_name_uri(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_idna_names.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_ALTERNATIVE_NAME + ) + assert ext is not None + rfc822_name = ext.value.get_values_for_type(x509.RFC822Name) + dns_name = ext.value.get_values_for_type(x509.DNSName) + uri = ext.value.get_values_for_type(x509.UniformResourceIdentifier) + assert rfc822_name == [u"email@xn--80ato2c.cryptography"] + assert dns_name == [u"xn--80ato2c.cryptography"] + assert uri == [u"https://www.xn--80ato2c.cryptography"] + + def test_rfc822name_dnsname_ipaddress_directoryname_uri(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_email_dns_ip_dirname_uri.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_ALTERNATIVE_NAME + ) + assert ext is not None + assert ext.critical is False + + san = ext.value + + rfc822_name = san.get_values_for_type(x509.RFC822Name) + uri = san.get_values_for_type(x509.UniformResourceIdentifier) + dns = san.get_values_for_type(x509.DNSName) + ip = san.get_values_for_type(x509.IPAddress) + dirname = san.get_values_for_type(x509.DirectoryName) + assert [u"user@cryptography.io"] == rfc822_name + assert [u"https://cryptography.io"] == uri + assert [u"cryptography.io"] == dns + assert [ + x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u'dirCN'), + x509.NameAttribute( + NameOID.ORGANIZATION_NAME, u'Cryptographic Authority' + ), + ]) + ] == dirname + assert [ + ipaddress.ip_address(u"127.0.0.1"), + ipaddress.ip_address(u"ff::") + ] == ip + + def test_invalid_rfc822name(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_rfc822_names.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + san = cert.extensions.get_extension_for_class( + x509.SubjectAlternativeName + ).value + values = san.get_values_for_type(x509.RFC822Name) + assert values == [ + u'email', u'email <email>', u'email <email@email>', + u'email <email@xn--eml-vla4c.com>', u'myemail:' + ] + + def test_other_name(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_other_name.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_ALTERNATIVE_NAME + ) + assert ext is not None + assert ext.critical is False + + expected = x509.OtherName(x509.ObjectIdentifier("1.2.3.4"), + b'\x16\x0bHello World') + assert len(ext.value) == 1 + assert list(ext.value)[0] == expected + + othernames = ext.value.get_values_for_type(x509.OtherName) + assert othernames == [expected] + + def test_certbuilder(self, backend): + sans = [u'*.example.org', u'*.xn--4ca7aey.example.com', + u'foobar.example.net'] + private_key = RSA_KEY_2048.private_key(backend) + builder = _make_certbuilder(private_key) + builder = builder.add_extension( + SubjectAlternativeName(list(map(DNSName, sans))), True) + + cert = builder.sign(private_key, hashes.SHA1(), backend) + result = [ + x.value + for x in cert.extensions.get_extension_for_class( + SubjectAlternativeName + ).value + ] + assert result == sans + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestExtendedKeyUsageExtension(object): + def test_eku(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "extended_key_usage.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.EXTENDED_KEY_USAGE + ) + assert ext is not None + assert ext.critical is False + + assert [ + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.1"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.2"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.3"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.4"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.9"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.8"), + x509.ObjectIdentifier("2.5.29.37.0"), + x509.ObjectIdentifier("2.16.840.1.113730.4.1"), + ] == list(ext.value) + + +class TestAccessDescription(object): + def test_invalid_access_method(self): + with pytest.raises(TypeError): + x509.AccessDescription("notanoid", x509.DNSName(u"test")) + + def test_invalid_access_location(self): + with pytest.raises(TypeError): + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, "invalid" + ) + + def test_valid_nonstandard_method(self): + ad = x509.AccessDescription( + ObjectIdentifier("2.999.1"), + x509.UniformResourceIdentifier(u"http://example.com") + ) + assert ad is not None + + def test_repr(self): + ad = x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ) + if not six.PY2: + assert repr(ad) == ( + "<AccessDescription(access_method=<ObjectIdentifier(oid=1.3.6" + ".1.5.5.7.48.1, name=OCSP)>, access_location=<UniformResource" + "Identifier(value='http://ocsp.domain.com')>)>" + ) + else: + assert repr(ad) == ( + "<AccessDescription(access_method=<ObjectIdentifier(oid=1.3.6" + ".1.5.5.7.48.1, name=OCSP)>, access_location=<UniformResource" + "Identifier(value=u'http://ocsp.domain.com')>)>" + ) + + def test_eq(self): + ad = x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ) + ad2 = x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ) + assert ad == ad2 + + def test_ne(self): + ad = x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ) + ad2 = x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ) + ad3 = x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://notthesame") + ) + assert ad != ad2 + assert ad != ad3 + assert ad != object() + + def test_hash(self): + ad = x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ) + ad2 = x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ) + ad3 = x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ) + assert hash(ad) == hash(ad2) + 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() + + def test_hash(self): + pc = x509.PolicyConstraints(2, 1) + pc2 = x509.PolicyConstraints(2, 1) + pc3 = x509.PolicyConstraints(2, None) + assert hash(pc) == hash(pc2) + assert hash(pc) != hash(pc3) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestPolicyConstraintsExtension(object): + def test_inhibit_policy_mapping(self, backend): + cert = _load_cert( + os.path.join("x509", "department-of-state-root.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.POLICY_CONSTRAINTS, + ) + assert ext.critical is True + + assert ext.value == x509.PolicyConstraints( + require_explicit_policy=None, inhibit_policy_mapping=0, + ) + + def test_require_explicit_policy(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "policy_constraints_explicit.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.POLICY_CONSTRAINTS + ) + assert ext.critical is True + assert ext.value == x509.PolicyConstraints( + require_explicit_policy=1, inhibit_policy_mapping=None, + ) + + +class TestAuthorityInformationAccess(object): + def test_invalid_descriptions(self): + with pytest.raises(TypeError): + x509.AuthorityInformationAccess(["notanAccessDescription"]) + + def test_iter_len(self): + aia = x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ]) + assert len(aia) == 2 + assert list(aia) == [ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ] + + def test_iter_input(self): + desc = [ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ) + ] + aia = x509.AuthorityInformationAccess(iter(desc)) + assert list(aia) == desc + + def test_repr(self): + aia = x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ]) + if not six.PY2: + assert repr(aia) == ( + "<AuthorityInformationAccess([<AccessDescription(access_method" + "=<ObjectIdentifier(oid=1.3.6.1.5.5.7.48.1, name=OCSP)>, acces" + "s_location=<UniformResourceIdentifier(value='http://oc" + "sp.domain.com')>)>, <AccessDescription(access_method=<ObjectI" + "dentifier(oid=1.3.6.1.5.5.7.48.2, name=caIssuers)>, access_lo" + "cation=<UniformResourceIdentifier(value='http://domain" + ".com/ca.crt')>)>])>" + ) + else: + assert repr(aia) == ( + "<AuthorityInformationAccess([<AccessDescription(access_method" + "=<ObjectIdentifier(oid=1.3.6.1.5.5.7.48.1, name=OCSP)>, acces" + "s_location=<UniformResourceIdentifier(value=u'http://oc" + "sp.domain.com')>)>, <AccessDescription(access_method=<ObjectI" + "dentifier(oid=1.3.6.1.5.5.7.48.2, name=caIssuers)>, access_lo" + "cation=<UniformResourceIdentifier(value=u'http://domain" + ".com/ca.crt')>)>])>" + ) + + def test_eq(self): + aia = x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ]) + aia2 = x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ]) + assert aia == aia2 + + def test_ne(self): + aia = x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ]) + aia2 = x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + ]) + + assert aia != aia2 + assert aia != object() + + def test_indexing(self): + aia = x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp2.domain.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp3.domain.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp4.domain.com") + ), + ]) + assert aia[-1] == aia[4] + assert aia[2:6:2] == [aia[2], aia[4]] + + def test_hash(self): + aia = x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ]) + aia2 = x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ]) + aia3 = x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.other.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ]) + assert hash(aia) == hash(aia2) + assert hash(aia) != hash(aia3) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestAuthorityInformationAccessExtension(object): + def test_aia_ocsp_ca_issuers(self, backend): + cert = _load_cert( + os.path.join("x509", "cryptography.io.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.AUTHORITY_INFORMATION_ACCESS + ) + assert ext is not None + assert ext.critical is False + + assert ext.value == x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://gv.symcd.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://gv.symcb.com/gv.crt") + ), + ]) + + def test_aia_multiple_ocsp_ca_issuers(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "aia_ocsp_ca_issuers.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.AUTHORITY_INFORMATION_ACCESS + ) + assert ext is not None + assert ext.critical is False + + assert ext.value == x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp2.domain.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.DirectoryName(x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"myCN"), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, + u"some Org"), + ])) + ), + ]) + + def test_aia_ocsp_only(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "aia_ocsp.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.AUTHORITY_INFORMATION_ACCESS + ) + assert ext is not None + assert ext.critical is False + + assert ext.value == x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + ]) + + def test_aia_ca_issuers_only(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "aia_ca_issuers.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.AUTHORITY_INFORMATION_ACCESS + ) + assert ext is not None + assert ext.critical is False + + assert ext.value == x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.DirectoryName(x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"myCN"), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, + u"some Org"), + ])) + ), + ]) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestAuthorityKeyIdentifierExtension(object): + def test_aki_keyid(self, backend): + cert = _load_cert( + os.path.join( + "x509", "cryptography.io.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.AUTHORITY_KEY_IDENTIFIER + ) + assert ext is not None + assert ext.critical is False + + assert ext.value.key_identifier == ( + b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08\xcbY" + ) + assert ext.value.authority_cert_issuer is None + assert ext.value.authority_cert_serial_number is None + + def test_aki_all_fields(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "authority_key_identifier.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.AUTHORITY_KEY_IDENTIFIER + ) + assert ext is not None + assert ext.critical is False + + assert ext.value.key_identifier == ( + b"9E>\xca=b\x1d\xea\x86I\xf6Z\xab@\xb7\xa4p\x98\xf1\xec" + ) + assert ext.value.authority_cert_issuer == [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + NameOID.ORGANIZATION_NAME, u"PyCA" + ), + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io" + ) + ]) + ) + ] + assert ext.value.authority_cert_serial_number == 3 + + def test_aki_no_keyid(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "authority_key_identifier_no_keyid.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.AUTHORITY_KEY_IDENTIFIER + ) + assert ext is not None + assert ext.critical is False + + assert ext.value.key_identifier is None + assert ext.value.authority_cert_issuer == [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + NameOID.ORGANIZATION_NAME, u"PyCA" + ), + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io" + ) + ]) + ) + ] + assert ext.value.authority_cert_serial_number == 3 + + def test_from_certificate(self, backend): + issuer_cert = _load_cert( + os.path.join("x509", "rapidssl_sha256_ca_g3.pem"), + x509.load_pem_x509_certificate, + backend + ) + cert = _load_cert( + os.path.join("x509", "cryptography.io.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.AUTHORITY_KEY_IDENTIFIER + ) + aki = x509.AuthorityKeyIdentifier.from_issuer_public_key( + issuer_cert.public_key() + ) + assert ext.value == aki + + def test_from_issuer_subject_key_identifier(self, backend): + issuer_cert = _load_cert( + os.path.join("x509", "rapidssl_sha256_ca_g3.pem"), + x509.load_pem_x509_certificate, + backend + ) + cert = _load_cert( + os.path.join("x509", "cryptography.io.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.AUTHORITY_KEY_IDENTIFIER + ) + ski_ext = issuer_cert.extensions.get_extension_for_class( + x509.SubjectKeyIdentifier + ) + aki = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier( + ski_ext.value + ) + assert ext.value == aki + + +class TestNameConstraints(object): + def test_ipaddress_wrong_type(self): + with pytest.raises(TypeError): + x509.NameConstraints( + permitted_subtrees=[ + x509.IPAddress(ipaddress.IPv4Address(u"127.0.0.1")) + ], + excluded_subtrees=None + ) + + with pytest.raises(TypeError): + x509.NameConstraints( + permitted_subtrees=None, + excluded_subtrees=[ + x509.IPAddress(ipaddress.IPv4Address(u"127.0.0.1")) + ] + ) + + def test_ipaddress_allowed_type(self): + permitted = [x509.IPAddress(ipaddress.IPv4Network(u"192.168.0.0/29"))] + excluded = [x509.IPAddress(ipaddress.IPv4Network(u"10.10.0.0/24"))] + nc = x509.NameConstraints( + permitted_subtrees=permitted, + excluded_subtrees=excluded + ) + assert nc.permitted_subtrees == permitted + assert nc.excluded_subtrees == excluded + + def test_invalid_permitted_subtrees(self): + with pytest.raises(TypeError): + x509.NameConstraints("badpermitted", None) + + def test_invalid_excluded_subtrees(self): + with pytest.raises(TypeError): + x509.NameConstraints(None, "badexcluded") + + def test_no_subtrees(self): + with pytest.raises(ValueError): + x509.NameConstraints(None, None) + + def test_permitted_none(self): + excluded = [x509.DNSName(u"name.local")] + nc = x509.NameConstraints( + permitted_subtrees=None, excluded_subtrees=excluded + ) + assert nc.permitted_subtrees is None + assert nc.excluded_subtrees is not None + + def test_excluded_none(self): + permitted = [x509.DNSName(u"name.local")] + nc = x509.NameConstraints( + permitted_subtrees=permitted, excluded_subtrees=None + ) + assert nc.permitted_subtrees is not None + assert nc.excluded_subtrees is None + + def test_iter_input(self): + subtrees = [x509.IPAddress(ipaddress.IPv4Network(u"192.168.0.0/24"))] + nc = x509.NameConstraints(iter(subtrees), iter(subtrees)) + assert list(nc.permitted_subtrees) == subtrees + assert list(nc.excluded_subtrees) == subtrees + + def test_repr(self): + permitted = [x509.DNSName(u"name.local"), x509.DNSName(u"name2.local")] + nc = x509.NameConstraints( + permitted_subtrees=permitted, + excluded_subtrees=None + ) + if not six.PY2: + assert repr(nc) == ( + "<NameConstraints(permitted_subtrees=[<DNSName(" + "value='name.local')>, <DNSName(value=" + "'name2.local')>], excluded_subtrees=None)>" + ) + else: + assert repr(nc) == ( + "<NameConstraints(permitted_subtrees=[<DNSName(" + "value=u'name.local')>, <DNSName(value=" + "u'name2.local')>], excluded_subtrees=None)>" + ) + + def test_eq(self): + nc = x509.NameConstraints( + permitted_subtrees=[x509.DNSName(u"name.local")], + excluded_subtrees=[x509.DNSName(u"name2.local")] + ) + nc2 = x509.NameConstraints( + permitted_subtrees=[x509.DNSName(u"name.local")], + excluded_subtrees=[x509.DNSName(u"name2.local")] + ) + assert nc == nc2 + + def test_ne(self): + nc = x509.NameConstraints( + permitted_subtrees=[x509.DNSName(u"name.local")], + excluded_subtrees=[x509.DNSName(u"name2.local")] + ) + nc2 = x509.NameConstraints( + permitted_subtrees=[x509.DNSName(u"name.local")], + excluded_subtrees=None + ) + nc3 = x509.NameConstraints( + permitted_subtrees=None, + excluded_subtrees=[x509.DNSName(u"name2.local")] + ) + + assert nc != nc2 + assert nc != nc3 + assert nc != object() + + def test_hash(self): + nc = x509.NameConstraints( + permitted_subtrees=[x509.DNSName(u"name.local")], + excluded_subtrees=[x509.DNSName(u"name2.local")] + ) + nc2 = x509.NameConstraints( + permitted_subtrees=[x509.DNSName(u"name.local")], + excluded_subtrees=[x509.DNSName(u"name2.local")] + ) + nc3 = x509.NameConstraints( + permitted_subtrees=[x509.DNSName(u"name.local")], + excluded_subtrees=None + ) + nc4 = x509.NameConstraints( + permitted_subtrees=None, + excluded_subtrees=[x509.DNSName(u"name.local")] + ) + assert hash(nc) == hash(nc2) + assert hash(nc) != hash(nc3) + assert hash(nc3) != hash(nc4) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestNameConstraintsExtension(object): + def test_permitted_excluded(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "nc_permitted_excluded_2.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + nc = cert.extensions.get_extension_for_oid( + ExtensionOID.NAME_CONSTRAINTS + ).value + assert nc == x509.NameConstraints( + permitted_subtrees=[ + x509.DNSName(u"zombo.local"), + ], + excluded_subtrees=[ + x509.DirectoryName(x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"zombo") + ])) + ] + ) + + def test_permitted(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "nc_permitted_2.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + nc = cert.extensions.get_extension_for_oid( + ExtensionOID.NAME_CONSTRAINTS + ).value + assert nc == x509.NameConstraints( + permitted_subtrees=[ + x509.DNSName(u"zombo.local"), + ], + excluded_subtrees=None + ) + + def test_permitted_with_leading_period(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "nc_permitted.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + nc = cert.extensions.get_extension_for_oid( + ExtensionOID.NAME_CONSTRAINTS + ).value + assert nc == x509.NameConstraints( + permitted_subtrees=[ + x509.DNSName(u".cryptography.io"), + x509.UniformResourceIdentifier(u"ftp://cryptography.test") + ], + excluded_subtrees=None + ) + + def test_excluded_with_leading_period(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "nc_excluded.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + nc = cert.extensions.get_extension_for_oid( + ExtensionOID.NAME_CONSTRAINTS + ).value + assert nc == x509.NameConstraints( + permitted_subtrees=None, + excluded_subtrees=[ + x509.DNSName(u".cryptography.io"), + x509.UniformResourceIdentifier(u"gopher://cryptography.test") + ] + ) + + def test_permitted_excluded_with_ips(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "nc_permitted_excluded.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + nc = cert.extensions.get_extension_for_oid( + ExtensionOID.NAME_CONSTRAINTS + ).value + assert nc == x509.NameConstraints( + permitted_subtrees=[ + x509.IPAddress(ipaddress.IPv4Network(u"192.168.0.0/24")), + x509.IPAddress(ipaddress.IPv6Network(u"FF:0:0:0:0:0:0:0/96")), + ], + excluded_subtrees=[ + x509.DNSName(u".domain.com"), + x509.UniformResourceIdentifier(u"http://test.local"), + ] + ) + + def test_single_ip_netmask(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "nc_single_ip_netmask.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + nc = cert.extensions.get_extension_for_oid( + ExtensionOID.NAME_CONSTRAINTS + ).value + assert nc == x509.NameConstraints( + permitted_subtrees=[ + x509.IPAddress(ipaddress.IPv6Network(u"FF:0:0:0:0:0:0:0/128")), + x509.IPAddress(ipaddress.IPv4Network(u"192.168.0.1/32")), + ], + excluded_subtrees=None + ) + + def test_invalid_netmask(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "nc_invalid_ip_netmask.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + with pytest.raises(ValueError): + cert.extensions.get_extension_for_oid( + ExtensionOID.NAME_CONSTRAINTS + ) + + def test_certbuilder(self, backend): + permitted = [u'.example.org', u'.xn--4ca7aey.example.com', + u'foobar.example.net'] + private_key = RSA_KEY_2048.private_key(backend) + builder = _make_certbuilder(private_key) + builder = builder.add_extension( + NameConstraints(permitted_subtrees=list(map(DNSName, permitted)), + excluded_subtrees=[]), True) + + cert = builder.sign(private_key, hashes.SHA1(), backend) + result = [ + x.value + for x in cert.extensions.get_extension_for_class( + NameConstraints + ).value.permitted_subtrees + ] + assert result == permitted + + +class TestDistributionPoint(object): + def test_distribution_point_full_name_not_general_names(self): + with pytest.raises(TypeError): + x509.DistributionPoint(["notgn"], None, None, None) + + def test_distribution_point_relative_name_not_name(self): + with pytest.raises(TypeError): + x509.DistributionPoint(None, "notname", None, None) + + def test_distribution_point_full_and_relative_not_none(self): + with pytest.raises(ValueError): + x509.DistributionPoint("data", "notname", None, None) + + def test_crl_issuer_not_general_names(self): + with pytest.raises(TypeError): + x509.DistributionPoint(None, None, None, ["notgn"]) + + def test_reason_not_reasonflags(self): + with pytest.raises(TypeError): + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + None, + frozenset(["notreasonflags"]), + None + ) + + def test_reason_not_frozenset(self): + with pytest.raises(TypeError): + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + None, + [x509.ReasonFlags.ca_compromise], + None + ) + + def test_disallowed_reasons(self): + with pytest.raises(ValueError): + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + None, + frozenset([x509.ReasonFlags.unspecified]), + None + ) + + with pytest.raises(ValueError): + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + None, + frozenset([x509.ReasonFlags.remove_from_crl]), + None + ) + + def test_reason_only(self): + with pytest.raises(ValueError): + x509.DistributionPoint( + None, + None, + frozenset([x509.ReasonFlags.aa_compromise]), + None + ) + + def test_eq(self): + dp = x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + None, + frozenset([x509.ReasonFlags.superseded]), + [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + NameOID.COMMON_NAME, u"Important CA" + ) + ]) + ) + ], + ) + dp2 = x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + None, + frozenset([x509.ReasonFlags.superseded]), + [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + NameOID.COMMON_NAME, u"Important CA" + ) + ]) + ) + ], + ) + assert dp == dp2 + + def test_ne(self): + dp = x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + None, + frozenset([x509.ReasonFlags.superseded]), + [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + NameOID.COMMON_NAME, u"Important CA" + ) + ]) + ) + ], + ) + dp2 = x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + None, + None, + None + ) + assert dp != dp2 + assert dp != object() + + def test_iter_input(self): + name = [x509.UniformResourceIdentifier(u"http://crypt.og/crl")] + issuer = [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"Important CA") + ]) + ) + ] + dp = x509.DistributionPoint( + iter(name), + None, + frozenset([x509.ReasonFlags.ca_compromise]), + iter(issuer), + ) + assert list(dp.full_name) == name + assert list(dp.crl_issuer) == issuer + + def test_repr(self): + dp = x509.DistributionPoint( + None, + x509.RelativeDistinguishedName([ + x509.NameAttribute(NameOID.COMMON_NAME, u"myCN") + ]), + frozenset([x509.ReasonFlags.ca_compromise]), + [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + NameOID.COMMON_NAME, u"Important CA" + ) + ]) + ) + ], + ) + if not six.PY2: + assert repr(dp) == ( + "<DistributionPoint(full_name=None, relative_name=<RelativeDis" + "tinguishedName(CN=myCN)>, reasons=frozenset({<ReasonFlags.ca_" + "compromise: 'cACompromise'>}), crl_issuer=[<DirectoryName(val" + "ue=<Name(CN=Important CA)>)>])>" + ) + else: + assert repr(dp) == ( + "<DistributionPoint(full_name=None, relative_name=<RelativeDis" + "tinguishedName(CN=myCN)>, reasons=frozenset([<ReasonFlags.ca_" + "compromise: 'cACompromise'>]), crl_issuer=[<DirectoryName(val" + "ue=<Name(CN=Important CA)>)>])>" + ) + + def test_hash(self): + dp = x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + None, + frozenset([x509.ReasonFlags.superseded]), + [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + NameOID.COMMON_NAME, u"Important CA" + ) + ]) + ) + ], + ) + dp2 = x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + None, + frozenset([x509.ReasonFlags.superseded]), + [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + NameOID.COMMON_NAME, u"Important CA" + ) + ]) + ) + ], + ) + dp3 = x509.DistributionPoint( + None, + x509.RelativeDistinguishedName([ + x509.NameAttribute(NameOID.COMMON_NAME, u"myCN") + ]), + None, + None, + ) + assert hash(dp) == hash(dp2) + assert hash(dp) != hash(dp3) + + +class TestFreshestCRL(object): + def test_invalid_distribution_points(self): + with pytest.raises(TypeError): + x509.FreshestCRL(["notadistributionpoint"]) + + def test_iter_len(self): + fcrl = x509.FreshestCRL([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://domain")], + None, None, None + ), + ]) + assert len(fcrl) == 1 + assert list(fcrl) == [ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://domain")], + None, None, None + ), + ] + + def test_iter_input(self): + points = [ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://domain")], + None, None, None + ), + ] + fcrl = x509.FreshestCRL(iter(points)) + assert list(fcrl) == points + + def test_repr(self): + fcrl = x509.FreshestCRL([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([x509.ReasonFlags.key_compromise]), + None + ), + ]) + if not six.PY2: + assert repr(fcrl) == ( + "<FreshestCRL([<DistributionPoint(full_name=[<Unifo" + "rmResourceIdentifier(value='ftp://domain')>], relative" + "_name=None, reasons=frozenset({<ReasonFlags.key_compromise: " + "'keyCompromise'>}), crl_issuer=None)>])>" + ) + else: + assert repr(fcrl) == ( + "<FreshestCRL([<DistributionPoint(full_name=[<Unifo" + "rmResourceIdentifier(value=u'ftp://domain')>], relative" + "_name=None, reasons=frozenset([<ReasonFlags.key_compromise: " + "'keyCompromise'>]), crl_issuer=None)>])>" + ) + + def test_eq(self): + fcrl = x509.FreshestCRL([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + fcrl2 = x509.FreshestCRL([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + assert fcrl == fcrl2 + + def test_ne(self): + fcrl = x509.FreshestCRL([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + fcrl2 = x509.FreshestCRL([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain2")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + fcrl3 = x509.FreshestCRL([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([x509.ReasonFlags.key_compromise]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + fcrl4 = x509.FreshestCRL([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + [x509.UniformResourceIdentifier(u"uri://thing2")], + ), + ]) + assert fcrl != fcrl2 + assert fcrl != fcrl3 + assert fcrl != fcrl4 + assert fcrl != object() + + def test_hash(self): + fcrl = x509.FreshestCRL([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + fcrl2 = x509.FreshestCRL([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + fcrl3 = x509.FreshestCRL([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([x509.ReasonFlags.key_compromise]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + assert hash(fcrl) == hash(fcrl2) + assert hash(fcrl) != hash(fcrl3) + + def test_indexing(self): + fcrl = x509.FreshestCRL([ + x509.DistributionPoint( + None, None, None, + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + x509.DistributionPoint( + None, None, None, + [x509.UniformResourceIdentifier(u"uri://thing2")], + ), + x509.DistributionPoint( + None, None, None, + [x509.UniformResourceIdentifier(u"uri://thing3")], + ), + x509.DistributionPoint( + None, None, None, + [x509.UniformResourceIdentifier(u"uri://thing4")], + ), + x509.DistributionPoint( + None, None, None, + [x509.UniformResourceIdentifier(u"uri://thing5")], + ), + ]) + assert fcrl[-1] == fcrl[4] + assert fcrl[2:6:2] == [fcrl[2], fcrl[4]] + + +class TestCRLDistributionPoints(object): + def test_invalid_distribution_points(self): + with pytest.raises(TypeError): + x509.CRLDistributionPoints(["notadistributionpoint"]) + + def test_iter_len(self): + cdp = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://domain")], + None, + None, + None + ), + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + None + ), + ]) + assert len(cdp) == 2 + assert list(cdp) == [ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://domain")], + None, + None, + None + ), + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + None + ), + ] + + def test_iter_input(self): + points = [ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://domain")], + None, + None, + None + ), + ] + cdp = x509.CRLDistributionPoints(iter(points)) + assert list(cdp) == points + + def test_repr(self): + cdp = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([x509.ReasonFlags.key_compromise]), + None + ), + ]) + if not six.PY2: + assert repr(cdp) == ( + "<CRLDistributionPoints([<DistributionPoint(full_name=[<Unifo" + "rmResourceIdentifier(value='ftp://domain')>], relative" + "_name=None, reasons=frozenset({<ReasonFlags.key_compromise: " + "'keyCompromise'>}), crl_issuer=None)>])>" + ) + else: + assert repr(cdp) == ( + "<CRLDistributionPoints([<DistributionPoint(full_name=[<Unifo" + "rmResourceIdentifier(value=u'ftp://domain')>], relative" + "_name=None, reasons=frozenset([<ReasonFlags.key_compromise: " + "'keyCompromise'>]), crl_issuer=None)>])>" + ) + + def test_eq(self): + cdp = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + cdp2 = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + assert cdp == cdp2 + + def test_ne(self): + cdp = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + cdp2 = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain2")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + cdp3 = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([x509.ReasonFlags.key_compromise]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + cdp4 = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + [x509.UniformResourceIdentifier(u"uri://thing2")], + ), + ]) + assert cdp != cdp2 + assert cdp != cdp3 + assert cdp != cdp4 + assert cdp != object() + + def test_hash(self): + cdp = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + cdp2 = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + cdp3 = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([x509.ReasonFlags.key_compromise]), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + assert hash(cdp) == hash(cdp2) + assert hash(cdp) != hash(cdp3) + + def test_indexing(self): + ci = x509.CRLDistributionPoints([ + x509.DistributionPoint( + None, None, None, + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + x509.DistributionPoint( + None, None, None, + [x509.UniformResourceIdentifier(u"uri://thing2")], + ), + x509.DistributionPoint( + None, None, None, + [x509.UniformResourceIdentifier(u"uri://thing3")], + ), + x509.DistributionPoint( + None, None, None, + [x509.UniformResourceIdentifier(u"uri://thing4")], + ), + x509.DistributionPoint( + None, None, None, + [x509.UniformResourceIdentifier(u"uri://thing5")], + ), + ]) + assert ci[-1] == ci[4] + assert ci[2:6:2] == [ci[2], ci[4]] + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestCRLDistributionPointsExtension(object): + def test_fullname_and_crl_issuer(self, backend): + cert = _load_cert( + os.path.join( + "x509", "PKITS_data", "certs", "ValidcRLIssuerTest28EE.crt" + ), + x509.load_der_x509_certificate, + backend + ) + + cdps = cert.extensions.get_extension_for_oid( + ExtensionOID.CRL_DISTRIBUTION_POINTS + ).value + + assert cdps == x509.CRLDistributionPoints([ + x509.DistributionPoint( + full_name=[x509.DirectoryName( + x509.Name([ + x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), + x509.NameAttribute( + NameOID.ORGANIZATION_NAME, + u"Test Certificates 2011" + ), + x509.NameAttribute( + NameOID.ORGANIZATIONAL_UNIT_NAME, + u"indirectCRL CA3 cRLIssuer" + ), + x509.NameAttribute( + NameOID.COMMON_NAME, + u"indirect CRL for indirectCRL CA3" + ), + ]) + )], + relative_name=None, + reasons=None, + crl_issuer=[x509.DirectoryName( + x509.Name([ + x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), + x509.NameAttribute( + NameOID.ORGANIZATION_NAME, + u"Test Certificates 2011" + ), + x509.NameAttribute( + NameOID.ORGANIZATIONAL_UNIT_NAME, + u"indirectCRL CA3 cRLIssuer" + ), + ]) + )], + ) + ]) + + def test_relativename_and_crl_issuer(self, backend): + cert = _load_cert( + os.path.join( + "x509", "PKITS_data", "certs", "ValidcRLIssuerTest29EE.crt" + ), + x509.load_der_x509_certificate, + backend + ) + + cdps = cert.extensions.get_extension_for_oid( + ExtensionOID.CRL_DISTRIBUTION_POINTS + ).value + + assert cdps == x509.CRLDistributionPoints([ + x509.DistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + NameOID.COMMON_NAME, + u"indirect CRL for indirectCRL CA3" + ), + ]), + reasons=None, + crl_issuer=[x509.DirectoryName( + x509.Name([ + x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), + x509.NameAttribute( + NameOID.ORGANIZATION_NAME, + u"Test Certificates 2011" + ), + x509.NameAttribute( + NameOID.ORGANIZATIONAL_UNIT_NAME, + u"indirectCRL CA3 cRLIssuer" + ), + ]) + )], + ) + ]) + + def test_fullname_crl_issuer_reasons(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "cdp_fullname_reasons_crl_issuer.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + + cdps = cert.extensions.get_extension_for_oid( + ExtensionOID.CRL_DISTRIBUTION_POINTS + ).value + + assert cdps == x509.CRLDistributionPoints([ + x509.DistributionPoint( + full_name=[x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl" + )], + relative_name=None, + reasons=frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise + ]), + crl_issuer=[x509.DirectoryName( + x509.Name([ + x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), + x509.NameAttribute( + NameOID.ORGANIZATION_NAME, u"PyCA" + ), + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography CA" + ), + ]) + )], + ) + ]) + + def test_all_reasons(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "cdp_all_reasons.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + + cdps = cert.extensions.get_extension_for_oid( + ExtensionOID.CRL_DISTRIBUTION_POINTS + ).value + + assert cdps == x509.CRLDistributionPoints([ + x509.DistributionPoint( + full_name=[x509.UniformResourceIdentifier( + u"http://domain.com/some.crl" + )], + relative_name=None, + reasons=frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + x509.ReasonFlags.affiliation_changed, + x509.ReasonFlags.superseded, + x509.ReasonFlags.privilege_withdrawn, + x509.ReasonFlags.cessation_of_operation, + x509.ReasonFlags.aa_compromise, + x509.ReasonFlags.certificate_hold, + ]), + crl_issuer=None + ) + ]) + + def test_single_reason(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "cdp_reason_aa_compromise.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + + cdps = cert.extensions.get_extension_for_oid( + ExtensionOID.CRL_DISTRIBUTION_POINTS + ).value + + assert cdps == x509.CRLDistributionPoints([ + x509.DistributionPoint( + full_name=[x509.UniformResourceIdentifier( + u"http://domain.com/some.crl" + )], + relative_name=None, + reasons=frozenset([x509.ReasonFlags.aa_compromise]), + crl_issuer=None + ) + ]) + + def test_crl_issuer_only(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "cdp_crl_issuer.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + + cdps = cert.extensions.get_extension_for_oid( + ExtensionOID.CRL_DISTRIBUTION_POINTS + ).value + + assert cdps == x509.CRLDistributionPoints([ + x509.DistributionPoint( + full_name=None, + relative_name=None, + reasons=None, + crl_issuer=[x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography CA" + ), + ]) + )], + ) + ]) + + def test_crl_empty_hostname(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "cdp_empty_hostname.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + + cdps = cert.extensions.get_extension_for_oid( + ExtensionOID.CRL_DISTRIBUTION_POINTS + ).value + + assert cdps == x509.CRLDistributionPoints([ + x509.DistributionPoint( + full_name=[x509.UniformResourceIdentifier( + u"ldap:///CN=A,OU=B,dc=C,DC=D?E?F?G?H=I" + )], + relative_name=None, + reasons=None, + crl_issuer=None + ) + ]) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestFreshestCRLExtension(object): + def test_vector(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "freshestcrl.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + + fcrl = cert.extensions.get_extension_for_class(x509.FreshestCRL).value + assert fcrl == x509.FreshestCRL([ + x509.DistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u'http://myhost.com/myca.crl' + ), + x509.UniformResourceIdentifier( + u'http://backup.myhost.com/myca.crl' + ) + ], + relative_name=None, + reasons=frozenset([ + x509.ReasonFlags.ca_compromise, + x509.ReasonFlags.key_compromise + ]), + crl_issuer=[x509.DirectoryName( + x509.Name([ + x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography CA" + ), + ]) + )] + ) + ]) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestOCSPNoCheckExtension(object): + def test_nocheck(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "ocsp_nocheck.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.OCSP_NO_CHECK + ) + assert isinstance(ext.value, x509.OCSPNoCheck) + + def test_eq(self): + onc1 = x509.OCSPNoCheck() + onc2 = x509.OCSPNoCheck() + + assert onc1 == onc2 + + def test_hash(self): + onc1 = x509.OCSPNoCheck() + onc2 = x509.OCSPNoCheck() + + assert hash(onc1) == hash(onc2) + + def test_ne(self): + onc1 = x509.OCSPNoCheck() + onc2 = x509.OCSPNoCheck() + + assert onc1 == onc2 + assert (onc1 != onc2) is False + assert onc1 != object() + + def test_repr(self): + onc = x509.OCSPNoCheck() + + assert repr(onc) == '<OCSPNoCheck()>' + + +class TestInhibitAnyPolicy(object): + def test_not_int(self): + with pytest.raises(TypeError): + x509.InhibitAnyPolicy("notint") + + def test_negative_int(self): + with pytest.raises(ValueError): + x509.InhibitAnyPolicy(-1) + + def test_repr(self): + iap = x509.InhibitAnyPolicy(0) + assert repr(iap) == "<InhibitAnyPolicy(skip_certs=0)>" + + def test_eq(self): + iap = x509.InhibitAnyPolicy(1) + iap2 = x509.InhibitAnyPolicy(1) + assert iap == iap2 + + def test_ne(self): + iap = x509.InhibitAnyPolicy(1) + iap2 = x509.InhibitAnyPolicy(4) + assert iap != iap2 + assert iap != object() + + def test_hash(self): + iap = x509.InhibitAnyPolicy(1) + iap2 = x509.InhibitAnyPolicy(1) + iap3 = x509.InhibitAnyPolicy(4) + assert hash(iap) == hash(iap2) + assert hash(iap) != hash(iap3) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestInhibitAnyPolicyExtension(object): + def test_inhibit_any_policy(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "inhibit_any_policy_5.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + iap = cert.extensions.get_extension_for_oid( + ExtensionOID.INHIBIT_ANY_POLICY + ).value + assert iap.skip_certs == 5 + + +class TestIssuingDistributionPointExtension(object): + @pytest.mark.parametrize( + ("filename", "expected"), + [ + ( + "crl_idp_fullname_indirect_crl.pem", + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl") + ], + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=True, + only_contains_attribute_certs=False, + ) + ), + ( + "crl_idp_fullname_only.pem", + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl") + ], + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ) + ), + ( + "crl_idp_fullname_only_aa.pem", + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl") + ], + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=True, + ) + ), + ( + "crl_idp_fullname_only_user.pem", + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl") + ], + relative_name=None, + only_contains_user_certs=True, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ) + ), + ( + "crl_idp_only_ca.pem", + x509.IssuingDistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ]), + only_contains_user_certs=False, + only_contains_ca_certs=True, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ) + ), + ( + "crl_idp_reasons_only.pem", + x509.IssuingDistributionPoint( + full_name=None, + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=frozenset([ + x509.ReasonFlags.key_compromise + ]), + indirect_crl=False, + only_contains_attribute_certs=False, + ) + ), + ( + "crl_idp_relative_user_all_reasons.pem", + x509.IssuingDistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ]), + only_contains_user_certs=True, + only_contains_ca_certs=False, + only_some_reasons=frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + x509.ReasonFlags.affiliation_changed, + x509.ReasonFlags.superseded, + x509.ReasonFlags.cessation_of_operation, + x509.ReasonFlags.certificate_hold, + x509.ReasonFlags.privilege_withdrawn, + x509.ReasonFlags.aa_compromise, + ]), + indirect_crl=False, + only_contains_attribute_certs=False, + ) + ), + ( + "crl_idp_relativename_only.pem", + x509.IssuingDistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ]), + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ) + ), + ] + ) + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_vectors(self, filename, expected, backend): + crl = _load_cert( + os.path.join("x509", "custom", filename), + x509.load_pem_x509_crl, backend + ) + idp = crl.extensions.get_extension_for_class( + x509.IssuingDistributionPoint + ).value + assert idp == expected + + @pytest.mark.parametrize( + ( + "error", "only_contains_user_certs", "only_contains_ca_certs", + "indirect_crl", "only_contains_attribute_certs", + "only_some_reasons", "full_name", "relative_name" + ), + [ + ( + TypeError, False, False, False, False, 'notafrozenset', None, + None + ), + ( + TypeError, False, False, False, False, frozenset(['bad']), + None, None + ), + ( + ValueError, False, False, False, False, + frozenset([x509.ReasonFlags.unspecified]), None, None + ), + ( + ValueError, False, False, False, False, + frozenset([x509.ReasonFlags.remove_from_crl]), None, None + ), + (TypeError, 'notabool', False, False, False, None, None, None), + (TypeError, False, 'notabool', False, False, None, None, None), + (TypeError, False, False, 'notabool', False, None, None, None), + (TypeError, False, False, False, 'notabool', None, None, None), + (ValueError, True, True, False, False, None, None, None), + (ValueError, False, False, True, True, None, None, None), + (ValueError, False, False, False, False, None, None, None), + ] + ) + def test_invalid_init(self, error, only_contains_user_certs, + only_contains_ca_certs, indirect_crl, + only_contains_attribute_certs, only_some_reasons, + full_name, relative_name): + with pytest.raises(error): + x509.IssuingDistributionPoint( + full_name, relative_name, only_contains_user_certs, + only_contains_ca_certs, only_some_reasons, indirect_crl, + only_contains_attribute_certs + ) + + def test_repr(self): + idp = x509.IssuingDistributionPoint( + None, None, False, False, + frozenset([x509.ReasonFlags.key_compromise]), False, False + ) + if not six.PY2: + assert repr(idp) == ( + "<IssuingDistributionPoint(full_name=None, relative_name=None," + " only_contains_user_certs=False, only_contains_ca_certs=False" + ", only_some_reasons=frozenset({<ReasonFlags.key_compromise: '" + "keyCompromise'>}), indirect_crl=False, only_contains_attribut" + "e_certs=False)>" + ) + else: + assert repr(idp) == ( + "<IssuingDistributionPoint(full_name=None, relative_name=None," + " only_contains_user_certs=False, only_contains_ca_certs=False" + ", only_some_reasons=frozenset([<ReasonFlags.key_compromise: '" + "keyCompromise'>]), indirect_crl=False, only_contains_attribut" + "e_certs=False)>" + ) + + def test_eq(self): + idp1 = x509.IssuingDistributionPoint( + only_contains_user_certs=False, + only_contains_ca_certs=False, + indirect_crl=False, + only_contains_attribute_certs=False, + only_some_reasons=None, + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") + ]) + ) + idp2 = x509.IssuingDistributionPoint( + only_contains_user_certs=False, + only_contains_ca_certs=False, + indirect_crl=False, + only_contains_attribute_certs=False, + only_some_reasons=None, + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") + ]) + ) + assert idp1 == idp2 + + def test_ne(self): + idp1 = x509.IssuingDistributionPoint( + only_contains_user_certs=False, + only_contains_ca_certs=False, + indirect_crl=False, + only_contains_attribute_certs=False, + only_some_reasons=None, + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") + ]) + ) + idp2 = x509.IssuingDistributionPoint( + only_contains_user_certs=True, + only_contains_ca_certs=False, + indirect_crl=False, + only_contains_attribute_certs=False, + only_some_reasons=None, + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") + ]) + ) + assert idp1 != idp2 + assert idp1 != object() + + def test_hash(self): + idp1 = x509.IssuingDistributionPoint( + None, None, True, False, None, False, False + ) + idp2 = x509.IssuingDistributionPoint( + None, None, True, False, None, False, False + ) + idp3 = x509.IssuingDistributionPoint( + None, + x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") + ]), + True, False, None, False, False + ) + assert hash(idp1) == hash(idp2) + assert hash(idp1) != hash(idp3) + + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + @pytest.mark.parametrize( + "idp", + [ + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl" + ) + ], + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=True, + only_contains_attribute_certs=False, + ), + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl" + ) + ], + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ), + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl" + ) + ], + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=True, + ), + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl" + ) + ], + relative_name=None, + only_contains_user_certs=True, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ), + x509.IssuingDistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ]), + only_contains_user_certs=False, + only_contains_ca_certs=True, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ), + x509.IssuingDistributionPoint( + full_name=None, + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=True, + only_some_reasons=frozenset([x509.ReasonFlags.key_compromise]), + indirect_crl=False, + only_contains_attribute_certs=False, + ), + x509.IssuingDistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA"), + x509.NameAttribute( + oid=x509.NameOID.COMMON_NAME, value=u"cryptography") + ]), + only_contains_user_certs=True, + only_contains_ca_certs=False, + only_some_reasons=frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + x509.ReasonFlags.affiliation_changed, + x509.ReasonFlags.privilege_withdrawn, + x509.ReasonFlags.aa_compromise, + ]), + indirect_crl=False, + only_contains_attribute_certs=False, + ), + x509.IssuingDistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ]), + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ), + ] + ) + def test_generate(self, idp, backend): + key = RSA_KEY_2048.private_key(backend) + last_update = datetime.datetime(2002, 1, 1, 12, 1) + next_update = datetime.datetime(2030, 1, 1, 12, 1) + builder = x509.CertificateRevocationListBuilder().issuer_name( + x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") + ]) + ).last_update( + last_update + ).next_update( + next_update + ).add_extension( + idp, True + ) + + crl = builder.sign(key, hashes.SHA256(), backend) + ext = crl.extensions.get_extension_for_class( + x509.IssuingDistributionPoint + ) + assert ext.critical is True + assert ext.value == idp + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestPrecertPoisonExtension(object): + def test_load(self, backend): + cert = _load_cert( + os.path.join("x509", "cryptography.io.precert.pem"), + x509.load_pem_x509_certificate, + backend + ) + poison = cert.extensions.get_extension_for_oid( + ExtensionOID.PRECERT_POISON + ).value + assert isinstance(poison, x509.PrecertPoison) + poison = cert.extensions.get_extension_for_class( + x509.PrecertPoison + ).value + assert isinstance(poison, x509.PrecertPoison) + + def test_generate(self, backend): + private_key = RSA_KEY_2048.private_key(backend) + cert = _make_certbuilder(private_key).add_extension( + x509.PrecertPoison(), critical=True + ).sign(private_key, hashes.SHA256(), backend) + poison = cert.extensions.get_extension_for_oid( + ExtensionOID.PRECERT_POISON + ).value + assert isinstance(poison, x509.PrecertPoison) + + def test_eq(self): + pcp1 = x509.PrecertPoison() + pcp2 = x509.PrecertPoison() + + assert pcp1 == pcp2 + + def test_hash(self): + pcp1 = x509.PrecertPoison() + pcp2 = x509.PrecertPoison() + + assert hash(pcp1) == hash(pcp2) + + def test_ne(self): + pcp1 = x509.PrecertPoison() + pcp2 = x509.PrecertPoison() + + assert pcp1 == pcp2 + assert (pcp1 != pcp2) is False + assert pcp1 != object() + + def test_repr(self): + pcp = x509.PrecertPoison() + + assert repr(pcp) == '<PrecertPoison()>' + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestSignedCertificateTimestamps(object): + @pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), + skip_message="Requires OpenSSL 1.1.0f+", + ) + def test_eq(self, backend): + sct = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value[0] + sct2 = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value[0] + assert sct == sct2 + + @pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), + skip_message="Requires OpenSSL 1.1.0f+", + ) + def test_ne(self, backend): + sct = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value[0] + sct2 = _load_cert( + os.path.join("x509", "cryptography-scts.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value[0] + assert sct != sct2 + assert sct != object() + + @pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), + skip_message="Requires OpenSSL 1.1.0f+", + ) + def test_hash(self, backend): + sct = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value[0] + sct2 = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value[0] + sct3 = _load_cert( + os.path.join("x509", "cryptography-scts.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value[0] + assert hash(sct) == hash(sct2) + assert hash(sct) != hash(sct3) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestPrecertificateSignedCertificateTimestampsExtension(object): + def test_init(self): + with pytest.raises(TypeError): + x509.PrecertificateSignedCertificateTimestamps([object()]) + + def test_repr(self): + assert repr(x509.PrecertificateSignedCertificateTimestamps([])) == ( + "<PrecertificateSignedCertificateTimestamps([])>" + ) + + @pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), + skip_message="Requires OpenSSL 1.1.0f+", + ) + def test_eq(self, backend): + psct1 = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + psct2 = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + assert psct1 == psct2 + + @pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), + skip_message="Requires OpenSSL 1.1.0f+", + ) + def test_ne(self, backend): + psct1 = _load_cert( + os.path.join("x509", "cryptography-scts.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + psct2 = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + assert psct1 != psct2 + assert psct1 != object() + + @pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), + skip_message="Requires OpenSSL 1.1.0f+", + ) + def test_hash(self, backend): + psct1 = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + psct2 = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + psct3 = _load_cert( + os.path.join("x509", "cryptography-scts.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + assert hash(psct1) == hash(psct2) + assert hash(psct1) != hash(psct3) + + @pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), + skip_message="Requires OpenSSL 1.1.0f+", + ) + def test_simple(self, backend): + cert = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ) + scts = cert.extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + assert len(scts) == 1 + [sct] = scts + assert scts[0] == sct + assert sct.version == x509.certificate_transparency.Version.v1 + assert sct.log_id == ( + b"\xa7\xceJNb\x07\xe0\xad\xde\xe5\xfd\xaaK\x1f\x86v\x87g\xb5\xd0" + b"\x02\xa5]G1\x0e~g\n\x95\xea\xb2" + ) + assert sct.timestamp == datetime.datetime( + 2016, 11, 17, 1, 56, 25, 396000 + ) + assert ( + sct.entry_type == + x509.certificate_transparency.LogEntryType.PRE_CERTIFICATE + ) + + @pytest.mark.supported( + only_if=lambda backend: ( + not backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER), + skip_message="Requires OpenSSL < 1.1.0", + ) + def test_skips_scts_if_unsupported(self, backend): + cert = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ) + assert len(cert.extensions) == 10 + with pytest.raises(x509.ExtensionNotFound): + cert.extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + + ext = cert.extensions.get_extension_for_oid( + x509.ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS + ) + assert isinstance(ext.value, x509.UnrecognizedExtension) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestInvalidExtension(object): + def test_invalid_certificate_policies_data(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "cp_invalid.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + with pytest.raises(ValueError): + cert.extensions + + +class TestOCSPNonce(object): + def test_non_bytes(self): + with pytest.raises(TypeError): + x509.OCSPNonce(38) + + def test_eq(self): + nonce1 = x509.OCSPNonce(b"0" * 5) + nonce2 = x509.OCSPNonce(b"0" * 5) + assert nonce1 == nonce2 + + def test_ne(self): + nonce1 = x509.OCSPNonce(b"0" * 5) + nonce2 = x509.OCSPNonce(b"0" * 6) + assert nonce1 != nonce2 + assert nonce1 != object() + + def test_repr(self): + nonce1 = x509.OCSPNonce(b"nonce") + if not six.PY2: + assert repr(nonce1) == "<OCSPNonce(nonce=b'nonce')>" + else: + assert repr(nonce1) == "<OCSPNonce(nonce='nonce')>" + + def test_hash(self): + nonce1 = x509.OCSPNonce(b"0" * 5) + nonce2 = x509.OCSPNonce(b"0" * 5) + nonce3 = x509.OCSPNonce(b"1" * 5) + assert hash(nonce1) == hash(nonce2) + assert hash(nonce1) != hash(nonce3) + + +def test_all_extension_oid_members_have_names_defined(): + for oid in dir(ExtensionOID): + if oid.startswith('__'): + continue + assert getattr(ExtensionOID, oid) in _OID_NAMES |
