# 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, SubjectInformationAccessOID, _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)


class TestSubjectInformationAccess(object):
    def test_invalid_descriptions(self):
        with pytest.raises(TypeError):
            x509.SubjectInformationAccess(["notanAccessDescription"])

    def test_iter_len(self):
        sia = x509.SubjectInformationAccess([
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca.domain.com")
            ),
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca2.domain.com")
            )
        ])
        assert len(sia) == 2
        assert list(sia) == [
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca.domain.com")
            ),
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca2.domain.com")
            )
        ]

    def test_iter_input(self):
        desc = [
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca.domain.com")
            )
        ]
        sia = x509.SubjectInformationAccess(iter(desc))
        assert list(sia) == desc

    def test_repr(self):
        sia = x509.SubjectInformationAccess([
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca.domain.com")
            )
        ])
        if not six.PY2:
            assert repr(sia) == (
                "<SubjectInformationAccess([<AccessDescription(access_method"
                "=<ObjectIdentifier(oid=1.3.6.1.5.5.7.48.5, name=caRepositor"
                "y)>, access_location=<UniformResourceIdentifier(value='http"
                "://ca.domain.com')>)>])>"
            )
        else:
            assert repr(sia) == (
                "<SubjectInformationAccess([<AccessDescription(access_method"
                "=<ObjectIdentifier(oid=1.3.6.1.5.5.7.48.5, name=caRepositor"
                "y)>, access_location=<UniformResourceIdentifier(value=u'htt"
                "p://ca.domain.com')>)>])>"
            )

    def test_eq(self):
        sia = x509.SubjectInformationAccess([
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca.domain.com")
            ),
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca2.domain.com")
            )
        ])
        sia2 = x509.SubjectInformationAccess([
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca.domain.com")
            ),
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca2.domain.com")
            )
        ])
        assert sia == sia2

    def test_ne(self):
        sia = x509.SubjectInformationAccess([
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca.domain.com")
            ),
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca2.domain.com")
            )
        ])
        sia2 = x509.SubjectInformationAccess([
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca.domain.com")
            ),
        ])

        assert sia != sia2
        assert sia != object()

    def test_indexing(self):
        sia = x509.SubjectInformationAccess([
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca.domain.com")
            ),
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca2.domain.com")
            ),
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca3.domain.com")
            ),
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca4.domain.com")
            ),
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca5.domain.com")
            ),
        ])
        assert sia[-1] == sia[4]
        assert sia[2:6:2] == [sia[2], sia[4]]

    def test_hash(self):
        sia = x509.SubjectInformationAccess([
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca.domain.com")
            ),
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca2.domain.com")
            ),
        ])
        sia2 = x509.SubjectInformationAccess([
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca.domain.com")
            ),
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca2.domain.com")
            ),
        ])
        sia3 = x509.SubjectInformationAccess([
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca.domain.com")
            ),
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"http://ca3.domain.com")
            ),
        ])
        assert hash(sia) == hash(sia2)
        assert hash(sia) != hash(sia3)


@pytest.mark.requires_backend_interface(interface=RSABackend)
@pytest.mark.requires_backend_interface(interface=X509Backend)
class TestSubjectInformationAccessExtension(object):
    def test_sia(self, backend):
        cert = _load_cert(
            os.path.join("x509", "custom", "sia.pem"),
            x509.load_pem_x509_certificate,
            backend
        )
        ext = cert.extensions.get_extension_for_oid(
            ExtensionOID.SUBJECT_INFORMATION_ACCESS
        )
        assert ext is not None
        assert ext.critical is False

        assert ext.value == x509.SubjectInformationAccess([
            x509.AccessDescription(
                SubjectInformationAccessOID.CA_REPOSITORY,
                x509.UniformResourceIdentifier(u"https://my.ca.issuer/")
            ),
            x509.AccessDescription(
                x509.ObjectIdentifier("2.999.7"),
                x509.UniformResourceIdentifier(u"gopher://info-mac-archive")
            ),
        ])


@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
