Esempio n. 1
0
def _decode_certificate_policies(backend, cp):
    cp = backend._ffi.cast("Cryptography_STACK_OF_POLICYINFO *", cp)
    cp = backend._ffi.gc(cp, backend._lib.CERTIFICATEPOLICIES_free)

    num = backend._lib.sk_POLICYINFO_num(cp)
    certificate_policies = []
    for i in range(num):
        qualifiers = None
        pi = backend._lib.sk_POLICYINFO_value(cp, i)
        oid = x509.ObjectIdentifier(_obj2txt(backend, pi.policyid))
        if pi.qualifiers != backend._ffi.NULL:
            qnum = backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers)
            qualifiers = []
            for j in range(qnum):
                pqi = backend._lib.sk_POLICYQUALINFO_value(pi.qualifiers, j)
                pqualid = x509.ObjectIdentifier(_obj2txt(backend, pqi.pqualid))
                if pqualid == CertificatePoliciesOID.CPS_QUALIFIER:
                    cpsuri = backend._ffi.buffer(
                        pqi.d.cpsuri.data,
                        pqi.d.cpsuri.length)[:].decode("ascii")
                    qualifiers.append(cpsuri)
                else:
                    assert pqualid == CertificatePoliciesOID.CPS_USER_NOTICE
                    user_notice = _decode_user_notice(backend,
                                                      pqi.d.usernotice)
                    qualifiers.append(user_notice)

        certificate_policies.append(x509.PolicyInformation(oid, qualifiers))

    return x509.CertificatePolicies(certificate_policies)
Esempio n. 2
0
    def _build_certificate_policies(self, ext):
        cp = self._backend._ffi.cast("Cryptography_STACK_OF_POLICYINFO *",
                                     self._backend._lib.X509V3_EXT_d2i(ext))
        assert cp != self._backend._ffi.NULL
        cp = self._backend._ffi.gc(cp, self._backend._lib.sk_POLICYINFO_free)
        num = self._backend._lib.sk_POLICYINFO_num(cp)
        certificate_policies = []
        for i in range(num):
            qualifiers = None
            pi = self._backend._lib.sk_POLICYINFO_value(cp, i)
            oid = x509.ObjectIdentifier(_obj2txt(self._backend, pi.policyid))
            if pi.qualifiers != self._backend._ffi.NULL:
                qnum = self._backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers)
                qualifiers = []
                for j in range(qnum):
                    pqi = self._backend._lib.sk_POLICYQUALINFO_value(
                        pi.qualifiers, j)
                    pqualid = x509.ObjectIdentifier(
                        _obj2txt(self._backend, pqi.pqualid))
                    if pqualid == x509.OID_CPS_QUALIFIER:
                        cpsuri = self._backend._ffi.buffer(
                            pqi.d.cpsuri.data,
                            pqi.d.cpsuri.length)[:].decode('ascii')
                        qualifiers.append(cpsuri)
                    elif pqualid == x509.OID_CPS_USER_NOTICE:
                        user_notice = self._build_user_notice(pqi.d.usernotice)
                        qualifiers.append(user_notice)

            certificate_policies.append(x509.PolicyInformation(
                oid, qualifiers))

        return x509.CertificatePolicies(certificate_policies)
Esempio n. 3
0
def _extensions(key: rsa.RSAPrivateKey,
                cert_opts: Dict) -> List[Tuple[bool, x509.Extension]]:  # noqa
    sector = cert_opts['sector']

    # certificate policies
    policies = [
        x509.PolicyInformation(x509.ObjectIdentifier('1.3.76.16'),
                               [x509.UserNotice(None, 'AgIDroot')]),
        x509.PolicyInformation(x509.ObjectIdentifier('1.3.76.16.6'),
                               [x509.UserNotice(None, 'agIDcert')]),
    ]
    if sector == 'private':
        policies.append(
            x509.PolicyInformation(x509.ObjectIdentifier('1.3.76.16.4.3.1'),
                                   [x509.UserNotice(None, 'cert_SP_Priv')]))
    elif sector == 'public':
        policies.append(
            x509.PolicyInformation(x509.ObjectIdentifier('1.3.76.16.4.2.1'),
                                   [x509.UserNotice(None, 'cert_SP_Pub')]))
    else:
        emsg = 'Invalid value for sector (%s)' % sector
        raise Exception(emsg)

    # extensions list
    return [
        # basicCinstraints
        (False, x509.BasicConstraints(ca=False, path_length=None)),
        # keyUsage
        (True,
         x509.KeyUsage(
             digital_signature=True,
             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,
         )),
        # certifcatePolicies
        (False, x509.CertificatePolicies(policies)),
        # subjectKeyIdentifier
        (False, x509.SubjectKeyIdentifier.from_public_key(key.public_key())),
    ]
Esempio n. 4
0
def create():
    """
    Create
    :return:
    """
    parent_id = request.args.get("parent")
    parent_cert = Certificate.objects(
        id=parent_id).first() if parent_id else None

    form_default_data = {}

    # @todo how to list meta fields
    # @todo rewrite with a intersect
    field_names = [
        f.name for f in CreateCertificateForm()
        if hasattr(x509.NameOID, f.name)
    ]

    for field_name in field_names:
        # get default value from environment variables
        form_default_data[field_name] = os.environ.get(f"DEFAULT_{field_name}")
        # get default value from parent certificate if any
        if parent_cert:
            for item in parent_cert.cert.subject:
                if item.oid == getattr(x509.NameOID, field_name):
                    form_default_data[field_name] = item.value

    if parent_cert:
        form = CreateCertificateForm(
            data={
                **form_default_data, "duration":
                int(current_app.config.get("DEFAULT_DURATION")),
                "parent":
                parent_cert.cert.serial_number,
                "mode": {
                    "is_server_auth": True,
                    "is_client_auth": True,
                },
                "policy": {
                    "oid": current_app.config.get('DEFAULT_POLICY_OID'),
                    "url": current_app.config.get('DEFAULT_POLICY_URL'),
                },
                "crl": {
                    "url":
                    current_app.config.get("DEFAULT_CA_ISSUER_URL") +
                    url_for("repository.download",
                            id=parent_cert.id,
                            file_format="crl"),
                },
                "aia": {
                    "enabled":
                    True,
                    'ca_issuers':
                    current_app.config.get("DEFAULT_CA_ISSUER_URL") + url_for(
                        "repository.download", id=parent_id,
                        file_format="crt"),
                    'ocsp':
                    current_app.config.get("DEFAULT_OCSP_URL")
                }
            })
    else:
        form = CreateCertificateForm(
            data={
                **form_default_data, "duration":
                10 * int(current_app.config.get("DEFAULT_DURATION")),
                "parent":
                0,
                "mode": {
                    "is_ca": True,
                },
                "policy": {
                    "oid": current_app.config.get('DEFAULT_POLICY_OID'),
                    "url": current_app.config.get('DEFAULT_POLICY_URL'),
                },
                "aia": {
                    "enabled": False,
                    'ca_issuers': current_app.config.get(
                        "DEFAULT_CA_ISSUER_URL"),
                    'ocsp': current_app.config.get("DEFAULT_OCSP_URL")
                }
            })

    if form.validate_on_submit():
        # key
        key = rsa.generate_private_key(public_exponent=65537,
                                       key_size=2048,
                                       backend=default_backend())

        # serial number
        serial_number = x509.random_serial_number()

        # subject
        names = []
        for field_name in field_names:
            if getattr(form, field_name).data:
                names.append(
                    x509.NameAttribute(getattr(x509.NameOID, field_name),
                                       getattr(form, field_name).data))
        subject = x509.Name(names)

        # issuer and signing key
        issuer = parent_cert.cert.subject if parent_cert else subject
        signing_key = parent_cert.key if parent_cert else key

        cert = x509.CertificateBuilder(
        ).subject_name(subject).issuer_name(issuer).public_key(
            key.public_key()).serial_number(serial_number).not_valid_before(
                datetime.utcnow()).not_valid_after(
                    datetime.utcnow() +
                    timedelta(days=int(form.duration.data))).add_extension(
                        x509.SubjectKeyIdentifier.from_public_key(
                            key.public_key()),
                        critical=False).add_extension(
                            x509.AuthorityKeyIdentifier.from_issuer_public_key(
                                signing_key.public_key()),
                            critical=False)

        # basic constraints
        cert = cert.add_extension(x509.BasicConstraints(
            form.mode.data.get('is_ca'), None),
                                  critical=False)

        # ocsp
        if form.aia.data.get("enabled"):
            cert = cert.add_extension(
                x509.AuthorityInformationAccess([
                    # openssl x509 -in 95285781730451486911577519787958288522332983584.crt -ocsp_uri -noout
                    x509.AccessDescription(
                        x509.OID_OCSP,
                        x509.UniformResourceIdentifier(
                            form.aia.data.get('ocsp'))),
                    # @todo validate issuers
                    x509.AccessDescription(
                        x509.OID_CA_ISSUERS,
                        x509.UniformResourceIdentifier(
                            form.aia.data.get('ca_issuers')))
                ]),
                critical=False)

        # key_usage
        if form.mode.data.get('is_ca'):
            cert = cert.add_extension(
                x509.KeyUsage(
                    # 数字签名
                    digital_signature=True,
                    # 认可签名
                    content_commitment=False,
                    # 秘钥加密
                    key_encipherment=False,
                    # 数据加密
                    data_encipherment=False,
                    # 秘钥协商
                    key_agreement=False,
                    # 证书签名
                    key_cert_sign=True,
                    # CRL 签名
                    crl_sign=True,
                    # 仅加密
                    encipher_only=False,
                    # 仅解密
                    decipher_only=False,
                ),
                critical=True)
        else:
            cert = cert.add_extension(x509.KeyUsage(digital_signature=True,
                                                    content_commitment=False,
                                                    key_encipherment=True,
                                                    data_encipherment=True,
                                                    key_agreement=False,
                                                    key_cert_sign=False,
                                                    crl_sign=False,
                                                    encipher_only=False,
                                                    decipher_only=False),
                                      critical=True)

        # extended_key_usage
        # @todo render all extended key usage
        extended_key_usage = []
        if form.mode.data.get('is_server_auth'):
            extended_key_usage.append(x509.oid.ExtendedKeyUsageOID.SERVER_AUTH)
        if form.mode.data.get('is_client_auth'):
            extended_key_usage.append(x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH)
        if len(extended_key_usage):
            cert = cert.add_extension(
                x509.ExtendedKeyUsage(extended_key_usage), critical=False)

        # subject alternative name
        san = []
        for item in form.san.data.split("\n"):
            if item:
                try:
                    ipaddress = IPv4Address(item)
                    san.append(x509.IPAddress(ipaddress))
                except Exception as e:
                    logger.info(e)
                    san.append(x509.DNSName(item))
        if len(san):
            cert = cert.add_extension(x509.SubjectAlternativeName(san),
                                      critical=False)

        # certificate policies
        if form.policy.data.get('url') and form.policy.data.get('oid'):
            cert = cert.add_extension(x509.CertificatePolicies([
                x509.PolicyInformation(
                    x509.ObjectIdentifier(form.policy.data.get('oid')),
                    [form.policy.data.get('url')],
                )
            ]),
                                      critical=False)

        # crl distribution points
        if form.crl.data.get('url'):
            cert = cert.add_extension(x509.CRLDistributionPoints([
                x509.DistributionPoint(
                    full_name=[
                        x509.UniformResourceIdentifier(
                            form.crl.data.get('url'))
                    ],
                    relative_name=None,
                    reasons=None,
                    crl_issuer=None,
                )
            ]),
                                      critical=False)

        # sign
        cert = cert.sign(signing_key, hashes.SHA256(), default_backend())

        # save
        c = Certificate(key=key,
                        cert=cert,
                        serial_number=str(serial_number),
                        pid=parent_cert.id if parent_cert else None)
        c.save()

        flash(f"Certificate create successful")

        return redirect(url_for(".home"))

    return render_template("create.html", form=form)
    def create_smartcard_cert(self,
                              issuer_private_key,
                              private_key,
                              outpath=None):
        subject_entries = [
            (NameOID.COUNTRY_NAME, "US"),
            (NameOID.ORGANIZATION_NAME, "My Company"),
            (NameOID.COMMON_NAME, "*****@*****.**"),
        ]
        issuer_entries = [
            (NameOID.COUNTRY_NAME, "US"),
            (NameOID.ORGANIZATION_NAME, "My Company"),
            (NameOID.COMMON_NAME, "My Company Name"),
        ]

        not_before = datetime.datetime.fromisoformat("2016-08-08 15:15:15")
        not_after = datetime.datetime.fromisoformat("2025-08-08 15:15:15")
        serial_number = x509.random_serial_number()

        aia_descriptions = [
            x509.AccessDescription(
                x509.oid.AuthorityInformationAccessOID.CA_ISSUERS,
                x509.UniformResourceIdentifier(
                    "http://sub.mycompany.com/sica.crt")),
        ]
        eku_usages = [
            x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH,
            x509.oid.ExtendedKeyUsageOID.EMAIL_PROTECTION,
            x509.ObjectIdentifier(
                "1.3.6.1.4.1.311.20.2.2"
            ),  # smartcardLogon (Microsoft enhanced key usage)
        ]
        # basic constraints
        basic_constraints_ca = False
        basic_constraints_pathlen = None

        certificate_policies = [
            x509.PolicyInformation(
                x509.oid.CertificatePoliciesOID.CPS_QUALIFIER,
                ["http://www.mycompany.com/cp/"]),
        ]

        # key usage:  Signing only
        key_usages = [True] + 8 * [False]

        # subject alternative names
        subject_alternative_names = [
            x509.DNSName("*****@*****.**"),
        ]

        crl_distribution_points = [
            x509.DistributionPoint([
                x509.UniformResourceIdentifier(
                    "http://crl.mycompany.com/sica.crl")
            ], None, None, None)
        ]

        extensions = [
            (x509.AuthorityInformationAccess(descriptions=aia_descriptions),
             False),
            (x509.SubjectKeyIdentifier.from_public_key(
                private_key.public_key()), False),
            (x509.BasicConstraints(basic_constraints_ca,
                                   basic_constraints_pathlen), True),
            (x509.AuthorityKeyIdentifier.from_issuer_public_key(
                issuer_private_key.public_key()), False),
            (x509.CertificatePolicies(policies=certificate_policies), False),
            (x509.CRLDistributionPoints(crl_distribution_points), False),
            (x509.KeyUsage(*key_usages), True),
            (x509.ExtendedKeyUsage(usages=eku_usages), False),
            (x509.SubjectAlternativeName(subject_alternative_names), False),
        ]

        cert = self.create_cert(
            not_before,
            not_after,
            serial_number,
            issuer_private_key,  # use issuer private key to sign => do not self sign
            private_key,
            subject_entries=subject_entries,
            issuer_entries=issuer_entries,
            extensions=extensions)

        self.save_to_pem(cert, outpath)

        return cert
    def create_sica_cert(self,
                         issuer_private_key,
                         private_key,
                         outpath=None,
                         ocsp_signing_eku=True):
        subject_entries = [
            (NameOID.COUNTRY_NAME, "US"),
            (NameOID.ORGANIZATION_NAME, "My Company"),
            (NameOID.COMMON_NAME, "My Company Name"),
        ]
        issuer_entries = [
            (NameOID.COUNTRY_NAME, "US"),
            (NameOID.ORGANIZATION_NAME, "Intermediate CA"),
            (NameOID.COMMON_NAME, "Intermediate CA Name"),
        ]

        not_before = datetime.datetime.fromisoformat("2016-02-02 10:10:10")
        not_after = datetime.datetime.fromisoformat("2022-02-02 10:10:10")
        serial_number = x509.random_serial_number()

        aia_descriptions = [
            x509.AccessDescription(
                x509.oid.AuthorityInformationAccessOID.CA_ISSUERS,
                x509.UniformResourceIdentifier(
                    "http://sub.rootca.com/ica.crt")),
            x509.AccessDescription(
                x509.oid.AuthorityInformationAccessOID.OCSP,
                x509.UniformResourceIdentifier("http://ica.ocsp.rootca.com")),
        ]
        eku_usages = [
            x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH,
            x509.oid.ExtendedKeyUsageOID.EMAIL_PROTECTION,
            x509.ObjectIdentifier(
                "1.3.6.1.4.1.311.20.2.2"
            ),  # smartcardLogon (Microsoft enhanced key usage)
        ]
        if ocsp_signing_eku:
            eku_usages.append(x509.oid.ExtendedKeyUsageOID.OCSP_SIGNING)

        # basic constraints
        basic_constraints_ca = True
        basic_constraints_pathlen = 0

        certificate_policies = [
            x509.PolicyInformation(
                x509.oid.CertificatePoliciesOID.CPS_QUALIFIER,
                ["http://www.rootca.com/repo"]),
            x509.PolicyInformation(
                x509.oid.CertificatePoliciesOID.CPS_QUALIFIER,
                ["http://www.mycompany.com/cp/"]),
        ]

        crl_distribution_points = [
            x509.DistributionPoint([
                x509.UniformResourceIdentifier("http://crl.rootca.com/ica.crl")
            ], None, None, None)
        ]

        # key usage:  Certificate Sign and CRL Sign set to True, rest set to False
        key_usages = 5 * [False] + 2 * [True] + 2 * [False]

        extensions = [
            (x509.AuthorityInformationAccess(descriptions=aia_descriptions),
             False),
            (x509.SubjectKeyIdentifier.from_public_key(
                private_key.public_key()), False),
            (x509.BasicConstraints(basic_constraints_ca,
                                   basic_constraints_pathlen), True),
            (x509.AuthorityKeyIdentifier.from_issuer_public_key(
                issuer_private_key.public_key()), False),
            (x509.CertificatePolicies(policies=certificate_policies), False),
            (x509.CRLDistributionPoints(crl_distribution_points), False),
            (x509.KeyUsage(*key_usages), True),
            (x509.ExtendedKeyUsage(usages=eku_usages), False),
        ]

        cert = self.create_cert(
            not_before,
            not_after,
            serial_number,
            issuer_private_key,  # use issuer private key to sign => do not self sign
            private_key,
            subject_entries=subject_entries,
            issuer_entries=issuer_entries,
            extensions=extensions)

        self.save_to_pem(cert, outpath)

        return cert
    def create_ica_cert(self, issuer_private_key, private_key, outpath=None):
        subject_entries = [
            (NameOID.COUNTRY_NAME, "US"),
            (NameOID.ORGANIZATION_NAME, "Intermediate CA"),
            (NameOID.COMMON_NAME, "Intermediate CA Name"),
        ]
        issuer_entries = [
            (NameOID.COUNTRY_NAME, "US"),
            (NameOID.ORGANIZATION_NAME, "Root CA"),
            (NameOID.COMMON_NAME, "Root CA Name"),
        ]

        not_before = datetime.datetime.fromisoformat("2016-01-01 11:11:11")
        not_after = datetime.datetime.fromisoformat("2031-01-01 11:11:11")
        serial_number = x509.random_serial_number()

        aia_descriptions = [
            x509.AccessDescription(
                x509.oid.AuthorityInformationAccessOID.OCSP,
                x509.UniformResourceIdentifier("http://ocsp.rootca.com")),
            x509.AccessDescription(
                x509.oid.AuthorityInformationAccessOID.CA_ISSUERS,
                x509.UniformResourceIdentifier(
                    "http://sub.rootca.com/rca.crt")),
        ]

        # basic constraints
        basic_constraints_ca = True
        basic_constraints_pathlen = None

        certificate_policies = [
            x509.PolicyInformation(x509.oid.CertificatePoliciesOID.ANY_POLICY,
                                   ["http://www.rootca.com/repo"]),
        ]

        crl_distribution_points = [
            x509.DistributionPoint([
                x509.UniformResourceIdentifier("http://crl.rootca.com/rca.crl")
            ], None, None, None)
        ]

        # key usage:  Certificate Sign and CRL Sign set to True, rest set to False
        key_usages = 5 * [False] + 2 * [True] + 2 * [False]

        extensions = [
            (x509.BasicConstraints(basic_constraints_ca,
                                   basic_constraints_pathlen), True),
            (x509.CertificatePolicies(policies=certificate_policies), False),
            (x509.AuthorityInformationAccess(descriptions=aia_descriptions),
             False),
            (x509.KeyUsage(*key_usages), True),
            (x509.AuthorityKeyIdentifier.from_issuer_public_key(
                issuer_private_key.public_key()), False),
            (x509.CRLDistributionPoints(crl_distribution_points), False),
            (x509.SubjectKeyIdentifier.from_public_key(
                private_key.public_key()), False),
        ]

        cert = self.create_cert(not_before,
                                not_after,
                                serial_number,
                                issuer_private_key,
                                private_key,
                                subject_entries=subject_entries,
                                issuer_entries=issuer_entries,
                                extensions=extensions)

        self.save_to_pem(cert, outpath)

        return cert
Esempio n. 8
0
class PolicyInformationTestCase(TestCaseMixin, TestCase):
    """Test PolicyInformation class."""

    oid = "2.5.29.32.0"

    # various qualifiers
    q1 = "text1"
    q2 = x509.UserNotice(explicit_text="text2", notice_reference=None)
    q3 = x509.UserNotice(explicit_text=None,
                         notice_reference=x509.NoticeReference(
                             organization="text3", notice_numbers=[1]))
    q4 = "text4"
    q5 = x509.UserNotice(
        explicit_text="text5",
        notice_reference=x509.NoticeReference(organization="text6",
                                              notice_numbers=[1, 2, 3]),
    )

    x1 = x509.PolicyInformation(policy_identifier=ObjectIdentifier(oid),
                                policy_qualifiers=[q1])
    x2 = x509.PolicyInformation(
        policy_identifier=ObjectIdentifier(oid),
        policy_qualifiers=[q2],
    )
    x3 = x509.PolicyInformation(
        policy_identifier=ObjectIdentifier(oid),
        policy_qualifiers=[q3],
    )
    x4 = x509.PolicyInformation(
        policy_identifier=ObjectIdentifier(oid),
        policy_qualifiers=[q4, q5],
    )
    s1: ParsablePolicyInformation = {
        "policy_identifier": oid,
        "policy_qualifiers": ["text1"],
    }
    s2: ParsablePolicyInformation = {
        "policy_identifier": oid,
        "policy_qualifiers": [{
            "explicit_text": "text2",
        }],
    }
    s3: ParsablePolicyInformation = {
        "policy_identifier":
        oid,
        "policy_qualifiers": [{
            "notice_reference": {
                "organization": "text3",
                "notice_numbers": [
                    1,
                ],
            }
        }],
    }
    s4: ParsablePolicyInformation = {
        "policy_identifier":
        oid,
        "policy_qualifiers": [
            "text4",
            {
                "explicit_text": "text5",
                "notice_reference": {
                    "organization": "text6",
                    "notice_numbers": [1, 2, 3],
                },
            },
        ],
    }
    s5: ParsablePolicyInformation = {
        "policy_identifier":
        oid,
        "policy_qualifiers": [{
            "explicit_text": "text5",
            "notice_reference": {
                "notice_numbers": [1, 2, 3],
            },
        }],
    }

    def setUp(self) -> None:
        super().setUp()

        self.pi1 = PolicyInformation(self.s1)
        self.pi2 = PolicyInformation(self.s2)
        self.pi3 = PolicyInformation(self.s3)
        self.pi4 = PolicyInformation(self.s4)
        self.pi5 = PolicyInformation(self.s5)
        self.pi_empty = PolicyInformation()

    def test_append(self) -> None:
        """Test PolicyInformation.append()."""
        self.pi1.append(self.q2)
        self.pi1.append(self.s3["policy_qualifiers"][0])
        self.assertEqual(
            self.pi1,
            PolicyInformation({
                "policy_identifier": self.oid,
                "policy_qualifiers": [self.q1, self.q2, self.q3],
            }),
        )

        self.pi_empty.policy_identifier = self.oid
        self.pi_empty.append(self.q3)
        self.assertEqual(self.pi3, self.pi_empty)

    def test_as_text(self) -> None:
        """Test as_text()."""
        self.assertEqual(
            self.pi1.as_text(), "Policy Identifier: 2.5.29.32.0\n"
            "Policy Qualifiers:\n* text1")
        self.assertEqual(
            self.pi2.as_text(),
            "Policy Identifier: 2.5.29.32.0\n"
            "Policy Qualifiers:\n"
            "* UserNotice:\n"
            "  * Explicit text: text2",
        )
        self.assertEqual(
            self.pi3.as_text(),
            "Policy Identifier: 2.5.29.32.0\n"
            "Policy Qualifiers:\n"
            "* UserNotice:\n"
            "  * Reference:\n"
            "    * Organiziation: text3\n"
            "    * Notice Numbers: [1]",
        )
        self.assertEqual(
            self.pi4.as_text(),
            "Policy Identifier: 2.5.29.32.0\n"
            "Policy Qualifiers:\n"
            "* text4\n"
            "* UserNotice:\n"
            "  * Explicit text: text5\n"
            "  * Reference:\n"
            "    * Organiziation: text6\n"
            "    * Notice Numbers: [1, 2, 3]",
        )
        self.assertEqual(self.pi_empty.as_text(),
                         "Policy Identifier: None\nNo Policy Qualifiers")

        self.load_named_cas("__all__")
        self.load_named_certs("__all__")
        for name, cert in list(self.new_cas.items()) + list(
                self.new_certs.items()):  # type: ignore[arg-type]
            try:
                ext = cert.pub.loaded.extensions.get_extension_for_class(
                    x509.CertificatePolicies).value
            except x509.ExtensionNotFound:
                continue

            for index, policy in enumerate(ext):
                pinfo = PolicyInformation(policy)
                self.assertEqual(pinfo.as_text(),
                                 certs[name]["policy_texts"][index])

    def test_certs(self) -> None:
        """Test for all known certs."""
        self.load_named_cas("__all__")
        self.load_named_certs("__all__")
        for cert in list(self.new_cas.values()) + list(
                self.new_certs.values()):  # type: ignore[arg-type]
            try:
                val = cert.pub.loaded.extensions.get_extension_for_class(
                    x509.CertificatePolicies).value
            except x509.ExtensionNotFound:
                continue

            for policy in val:
                pi1 = PolicyInformation(policy)
                self.assertEqual(pi1.for_extension_type, policy)

                # pass the serialized value to the constructor and see if it's still the same
                pi2 = PolicyInformation(
                    typing.cast(ParsablePolicyInformation, pi1.serialize()))
                self.assertEqual(pi1, pi2)
                self.assertEqual(pi1.serialize(), pi2.serialize())
                self.assertEqual(pi2.for_extension_type, policy)

    def test_clear(self) -> None:
        """Test PolicyInformation.clear()."""
        self.pi1.clear()
        self.assertIsNone(self.pi1.policy_qualifiers)

    def test_constructor(self) -> None:
        """Test some constructors that are otherwise not called."""
        pinfo = PolicyInformation()
        self.assertIsNone(pinfo.policy_identifier)
        self.assertIsNone(pinfo.policy_qualifiers)

        pinfo = PolicyInformation({
            "policy_identifier":
            "1.2.3",
            "policy_qualifiers": [
                x509.UserNotice(notice_reference=None, explicit_text="foobar"),
            ],
        })
        self.assertEqual(len(pinfo), 1)

        pinfo = PolicyInformation({
            "policy_identifier":
            "1.2.3",
            "policy_qualifiers": [{
                "notice_reference":
                x509.NoticeReference(organization="foobar",
                                     notice_numbers=[1]),
            }],
        })
        self.assertEqual(len(pinfo), 1)

    def test_constructor_errors(self) -> None:
        """Test various invalid values for the constructor."""
        # type ignores are because we're testing exactly that here
        with self.assertRaisesRegex(
                ValueError,
                r"^PolicyInformation data must be either x509.PolicyInformation or dict$"
        ):
            PolicyInformation(True)  # type: ignore[arg-type]

        with self.assertRaisesRegex(
                ValueError,
                r"^PolicyQualifier must be string, dict or x509.UserNotice$"):
            PolicyInformation({
                "policy_identifier": "1.2.3",
                "policy_qualifiers": [True]
            }  # type: ignore[list-item]
                              )

        with self.assertRaisesRegex(
                ValueError,
                r"^NoticeReference must be either None, a dict or an x509.NoticeReference$"
        ):
            PolicyInformation({
                "policy_identifier":
                "1.2.3",
                "policy_qualifiers": [{
                    "notice_reference": True,  # type: ignore[typeddict-item]
                }],
            })

    def test_contains(self) -> None:
        """Test PolicyInformation.contains()."""
        self.assertIn(self.q1, self.pi1)
        self.assertIn(self.q2, self.pi2)
        self.assertIn(self.q3, self.pi3)
        self.assertIn(self.q4, self.pi4)
        self.assertIn(self.q5, self.pi4)
        self.assertIn(self.s1["policy_qualifiers"][0], self.pi1)
        self.assertIn(self.s2["policy_qualifiers"][0], self.pi2)
        self.assertIn(self.s3["policy_qualifiers"][0], self.pi3)
        self.assertIn(self.s4["policy_qualifiers"][0], self.pi4)
        self.assertIn(self.s4["policy_qualifiers"][1], self.pi4)

        self.assertNotIn(self.q2, self.pi1)
        self.assertNotIn(self.q1, self.pi_empty)
        self.assertNotIn(self.s1["policy_qualifiers"][0], self.pi2)
        self.assertNotIn(self.s2["policy_qualifiers"][0], self.pi1)
        self.assertNotIn(self.s2["policy_qualifiers"][0], self.pi_empty)

        # Invalid values are always false:
        self.assertNotIn(True, self.pi1)

    def test_count(self) -> None:
        """Test PolicyInformation.count()."""
        self.assertEqual(self.pi1.count(self.s1["policy_qualifiers"][0]), 1)
        self.assertEqual(self.pi1.count(self.q1), 1)
        self.assertEqual(self.pi1.count(self.s2),
                         0)  # type: ignore[arg-type] # full pi is wrong
        self.assertEqual(self.pi1.count(self.q2), 0)
        self.assertEqual(self.pi_empty.count(self.q2), 0)
        self.assertEqual(
            self.pi1.count(True),
            0)  # type: ignore[arg-type] # what we're testing here!

    def test_delitem(self) -> None:
        """Test item deletion (e.g. ``del pi[0]``)."""
        del self.pi1[0]
        self.pi_empty.policy_identifier = self.oid
        self.assertEqual(self.pi1, self.pi_empty)

        self.assertEqual(len(self.pi4), 2)
        del self.pi4[0]
        self.assertEqual(len(self.pi4), 1)

        with self.assertRaisesRegex(IndexError,
                                    r"^list assignment index out of range$"):
            del self.pi1[0]

    def test_extend(self) -> None:
        """Test PolicyInformation.extend()."""
        self.pi1.extend([self.q2, self.q4])
        self.assertEqual(
            self.pi1,
            PolicyInformation({
                "policy_identifier": self.oid,
                "policy_qualifiers": [self.q1, self.q2, self.q4],
            }),
        )

        self.pi2.extend([self.s1["policy_qualifiers"][0]])
        self.assertEqual(
            self.pi2,
            PolicyInformation({
                "policy_identifier": self.oid,
                "policy_qualifiers": [self.q2, self.q1],
            }),
        )

        # extend an empty list
        self.pi_empty.extend([self.s1["policy_qualifiers"][0]])
        self.assertEqual(
            self.pi_empty,
            PolicyInformation({
                "policy_identifier": None,
                "policy_qualifiers": [self.q1],
            }),
        )

    def test_getitem(self) -> None:
        """Test item getter (e.g. ``x = ext[0]``)."""
        self.assertEqual(self.pi1[0], self.s1["policy_qualifiers"][0])
        self.assertEqual(self.pi4[0], self.s4["policy_qualifiers"][0])
        self.assertEqual(self.pi4[1], self.s4["policy_qualifiers"][1])
        self.assertEqual(self.pi4[1:], [self.s4["policy_qualifiers"][1]])

        with self.assertRaisesRegex(IndexError, r"^list index out of range$"):
            self.pi_empty[0]  # pylint: disable=pointless-statement
        with self.assertRaisesRegex(IndexError, r"^list index out of range$"):
            self.pi_empty[2:]  # pylint: disable=pointless-statement

    def test_hash(self) -> None:
        """Test hash()."""
        self.assertEqual(hash(self.pi1), hash(self.pi1))
        self.assertEqual(hash(self.pi2), hash(self.pi2))
        self.assertEqual(hash(self.pi3), hash(self.pi3))
        self.assertEqual(hash(self.pi4), hash(self.pi4))
        self.assertEqual(hash(self.pi5), hash(self.pi5))
        self.assertEqual(hash(self.pi_empty), hash(self.pi_empty))

        self.assertEqual(hash(self.pi1), hash(PolicyInformation(self.s1)))
        self.assertEqual(hash(self.pi2), hash(PolicyInformation(self.s2)))
        self.assertEqual(hash(self.pi3), hash(PolicyInformation(self.s3)))
        self.assertEqual(hash(self.pi4), hash(PolicyInformation(self.s4)))
        self.assertEqual(hash(self.pi5), hash(PolicyInformation(self.s5)))
        self.assertEqual(hash(self.pi_empty), hash(PolicyInformation()))

        self.assertNotEqual(hash(self.pi1), hash(self.pi2))
        self.assertNotEqual(hash(self.pi1), hash(self.pi3))
        self.assertNotEqual(hash(self.pi1), hash(self.pi4))
        self.assertNotEqual(hash(self.pi2), hash(self.pi3))
        self.assertNotEqual(hash(self.pi2), hash(self.pi4))
        self.assertNotEqual(hash(self.pi3), hash(self.pi4))

    def test_insert(self) -> None:
        """Test PolicyInformation.insert()."""
        self.pi1.insert(0, self.q2)
        self.assertEqual(
            self.pi1,
            PolicyInformation({
                "policy_identifier": self.oid,
                "policy_qualifiers": [self.q2, self.q1],
            }),
        )
        self.pi1.insert(1, self.s3["policy_qualifiers"][0])
        self.assertEqual(
            self.pi1,
            PolicyInformation({
                "policy_identifier": self.oid,
                "policy_qualifiers": [self.q2, self.q3, self.q1],
            }),
        )

        self.pi_empty.insert(1, self.q2)
        self.pi_empty.policy_identifier = self.oid
        self.assertEqual(self.pi2, self.pi_empty)

    def test_iter(self) -> None:
        """Test iter(pi)."""
        self.assertEqual(list(self.pi1), [self.q1])
        self.assertEqual(list(self.pi2), [self.q2])
        self.assertEqual(list(self.pi4), [self.q4, self.q5])
        self.assertEqual(list(self.pi_empty), [])

    def test_len(self) -> None:
        """Test len(ext)."""
        self.assertEqual(len(self.pi1), 1)
        self.assertEqual(len(self.pi2), 1)
        self.assertEqual(len(self.pi3), 1)
        self.assertEqual(len(self.pi4), 2)
        self.assertEqual(len(self.pi5), 1)
        self.assertEqual(len(self.pi_empty), 0)

    def test_policy_identifier_setter(self) -> None:
        """Test setting a policy identifier."""
        value = "1.2.3"
        expected = ObjectIdentifier(value)
        pinfo = PolicyInformation({
            "policy_identifier": value,
            "policy_qualifiers": []
        })
        pinfo.policy_identifier = value
        self.assertEqual(pinfo.policy_identifier, expected)

        pinfo = PolicyInformation({"policy_identifier": expected})
        self.assertEqual(pinfo.policy_identifier, expected)

        new_value = "2.3.4"
        new_expected = ObjectIdentifier(new_value)
        pinfo.policy_identifier = new_value
        self.assertEqual(pinfo.policy_identifier, new_expected)

    def test_pop(self) -> None:
        """Test PolicyInformation.pop()."""
        self.pi_empty.policy_identifier = self.oid
        self.assertEqual(self.pi1.pop(), self.s1["policy_qualifiers"][0])
        self.assertEqual(self.pi1, self.pi_empty)

        self.assertEqual(self.pi4.pop(1), self.s4["policy_qualifiers"][1])
        self.assertEqual(
            self.pi4,
            PolicyInformation({
                "policy_identifier": self.oid,
                "policy_qualifiers": [self.q4],
            }),
        )

        self.assertEqual(self.pi4.pop(), self.s4["policy_qualifiers"][0])
        self.assertEqual(self.pi4, self.pi_empty)

        with self.assertRaisesRegex(IndexError, r"^pop from empty list$"):
            self.pi_empty.pop()

    def test_remove(self) -> None:
        """Test PolicyInformation.remove()."""
        self.pi_empty.policy_identifier = self.oid
        self.pi1.remove(self.q1)
        self.assertEqual(self.pi1, self.pi_empty)

        self.pi2.remove(self.s2["policy_qualifiers"][0])
        self.assertEqual(self.pi1, self.pi_empty)

        self.pi4.remove(self.q4)
        self.assertEqual(
            self.pi4,
            PolicyInformation({
                "policy_identifier": self.oid,
                "policy_qualifiers": [self.q5],
            }),
        )

        with self.assertRaisesRegex(ValueError, r"^.*: not in list\.$"):
            self.pi_empty.remove(self.s3["policy_qualifiers"][0])

    def _test_repr(self, func: typing.Callable[[typing.Any], str]) -> None:
        self.assertEqual(
            func(self.pi1),
            "<PolicyInformation(oid=2.5.29.32.0, qualifiers=['text1'])>")
        self.assertEqual(
            func(self.pi2),
            "<PolicyInformation(oid=2.5.29.32.0, qualifiers=[{'explicit_text': 'text2'}])>"
        )
        self.assertEqual(func(self.pi_empty),
                         "<PolicyInformation(oid=None, qualifiers=None)>")

        # NOTE: order of dict is different here, so we do not test output, just make sure there's no exception
        func(self.pi3)
        func(self.pi4)

    def test_repr(self) -> None:
        """Test repr()."""
        self._test_repr(repr)

    def test_serialize(self) -> None:
        """Test serialization."""
        self.assertEqual(self.pi1.serialize(), {
            "policy_identifier": "2.5.29.32.0",
            "policy_qualifiers": ["text1"]
        })
        self.assertEqual(
            self.pi2.serialize(),
            {
                "policy_identifier": "2.5.29.32.0",
                "policy_qualifiers": [{
                    "explicit_text": "text2"
                }]
            },
        )
        self.assertEqual(
            self.pi3.serialize(),
            {
                "policy_identifier":
                "2.5.29.32.0",
                "policy_qualifiers": [{
                    "notice_reference": {
                        "notice_numbers": [1],
                        "organization": "text3"
                    }
                }],
            },
        )
        self.assertEqual(
            self.pi4.serialize(),
            {
                "policy_identifier":
                "2.5.29.32.0",
                "policy_qualifiers": [
                    "text4",
                    {
                        "explicit_text": "text5",
                        "notice_reference": {
                            "notice_numbers": [1, 2, 3],
                            "organization": "text6"
                        },
                    },
                ],
            },
        )
        self.assertEqual(
            self.pi5.serialize(),
            {
                "policy_identifier":
                "2.5.29.32.0",
                "policy_qualifiers": [{
                    "explicit_text": "text5",
                    "notice_reference": {
                        "notice_numbers": [1, 2, 3]
                    }
                }],
            },
        )

    def test_setitem(self) -> None:
        """Test __setitem__()."""
        # pylint: disable=invalid-name; let's just use pi here
        pi = PolicyInformation(self.s1)
        self.assertEqual(pi, self.pi1)
        pi[0] = self.q2
        self.assertEqual(pi, self.pi2)

        pi = PolicyInformation(self.s1)
        pi[0:1] = [self.q2]
        self.assertEqual(pi, self.pi2)

        # list()[0:1] = "x" also works
        pi = PolicyInformation({"policy_identifier": "2.5.29.32.0"})
        pi[0:1] = [self.q2]
        self.assertEqual(pi, self.pi2)

        pi = PolicyInformation()
        with self.assertRaisesRegex(ValueError, r"^Index out of range$"):
            pi[0] = self.q1
        self.assertEqual(len(pi), 0)

        pi = PolicyInformation(self.s1)
        with self.assertRaisesRegex(
                ValueError,
                r"^PolicyQualifier must be string, dict or x509.UserNotice$"):
            pi[0] = True  # type: ignore[assignment]
        self.assertEqual(pi, self.pi1)

        pi = PolicyInformation(self.s1)
        with self.assertRaisesRegex(
                TypeError, r"^bar/%s: Invalid key/value type$" % self.q1):
            pi["bar"] = self.q1  # type: ignore[index]
        self.assertEqual(pi, self.pi1)

    def test_str(self) -> None:
        """Test str()."""
        self._test_repr(str)
Esempio n. 9
0
 def for_extension_type(self) -> x509.PolicyInformation:
     """Convert instance to a suitable cryptography class."""
     return x509.PolicyInformation(policy_identifier=self.policy_identifier,
                                   policy_qualifiers=self.policy_qualifiers)
Esempio n. 10
0
class PolicyInformationTestCase(DjangoCATestCase):
    """Test PolicyInformation class."""

    oid = '2.5.29.32.0'

    # various qualifiers
    q1 = 'text1'
    q2 = x509.UserNotice(explicit_text='text2', notice_reference=None)
    q3 = x509.UserNotice(explicit_text=None,
                         notice_reference=x509.NoticeReference(
                             organization='text3', notice_numbers=[1]))
    q4 = 'text4'
    q5 = x509.UserNotice(explicit_text='text5',
                         notice_reference=x509.NoticeReference(
                             organization='text6', notice_numbers=[1, 2, 3]))

    x1 = x509.PolicyInformation(policy_identifier=ObjectIdentifier(oid),
                                policy_qualifiers=[q1])
    x2 = x509.PolicyInformation(
        policy_identifier=ObjectIdentifier(oid),
        policy_qualifiers=[q2],
    )
    x3 = x509.PolicyInformation(
        policy_identifier=ObjectIdentifier(oid),
        policy_qualifiers=[q3],
    )
    x4 = x509.PolicyInformation(
        policy_identifier=ObjectIdentifier(oid),
        policy_qualifiers=[q4, q5],
    )
    s1 = {
        'policy_identifier': oid,
        'policy_qualifiers': ['text1'],
    }
    s2 = {
        'policy_identifier': oid,
        'policy_qualifiers': [{
            'explicit_text': 'text2',
        }],
    }
    s3 = {
        'policy_identifier':
        oid,
        'policy_qualifiers': [{
            'notice_reference': {
                'organization': 'text3',
                'notice_numbers': [
                    1,
                ],
            }
        }],
    }
    s4 = {
        'policy_identifier':
        oid,
        'policy_qualifiers': [
            'text4', {
                'explicit_text': 'text5',
                'notice_reference': {
                    'organization': 'text6',
                    'notice_numbers': [1, 2, 3],
                }
            }
        ],
    }

    def setUp(self):
        super().setUp()

        self.pi1 = PolicyInformation(self.s1)
        self.pi2 = PolicyInformation(self.s2)
        self.pi3 = PolicyInformation(self.s3)
        self.pi4 = PolicyInformation(self.s4)
        self.pi_empty = PolicyInformation()

    def test_append(self):
        """Test PolicyInformation.append()."""
        self.pi1.append(self.q2)
        self.pi1.append(self.s3['policy_qualifiers'][0])
        self.assertEqual(
            self.pi1,
            PolicyInformation({
                'policy_identifier': self.oid,
                'policy_qualifiers': [self.q1, self.q2, self.q3],
            }))

        self.pi_empty.policy_identifier = self.oid
        self.pi_empty.append(self.q3)
        self.assertEqual(self.pi3, self.pi_empty)

    def test_as_text(self):
        """Test as_text()."""
        self.assertEqual(
            self.pi1.as_text(), 'Policy Identifier: 2.5.29.32.0\n'
            'Policy Qualifiers:\n* text1')
        self.assertEqual(
            self.pi2.as_text(), 'Policy Identifier: 2.5.29.32.0\n'
            'Policy Qualifiers:\n'
            '* UserNotice:\n'
            '  * Explicit text: text2')
        self.assertEqual(
            self.pi3.as_text(), 'Policy Identifier: 2.5.29.32.0\n'
            'Policy Qualifiers:\n'
            '* UserNotice:\n'
            '  * Reference:\n'
            '    * Organiziation: text3\n'
            '    * Notice Numbers: [1]')
        self.assertEqual(
            self.pi4.as_text(), 'Policy Identifier: 2.5.29.32.0\n'
            'Policy Qualifiers:\n'
            '* text4\n'
            '* UserNotice:\n'
            '  * Explicit text: text5\n'
            '  * Reference:\n'
            '    * Organiziation: text6\n'
            '    * Notice Numbers: [1, 2, 3]')
        self.assertEqual(self.pi_empty.as_text(),
                         'Policy Identifier: None\nNo Policy Qualifiers')

        self.load_all_cas()
        self.load_all_certs()
        for name, cert in list(self.cas.items()) + list(self.certs.items()):
            try:
                ext = cert.x509.extensions.get_extension_for_oid(
                    ExtensionOID.CERTIFICATE_POLICIES).value
            except x509.ExtensionNotFound:
                continue

            for index, policy in enumerate(ext):
                pinfo = PolicyInformation(policy)
                self.assertEqual(pinfo.as_text(),
                                 certs[name]['policy_texts'][index])

    def test_certs(self):
        """Test for all known certs."""
        self.load_all_cas()
        self.load_all_certs()
        for _name, cert in list(self.cas.items()) + list(self.certs.items()):
            try:
                val = cert.x509.extensions.get_extension_for_oid(
                    ExtensionOID.CERTIFICATE_POLICIES).value
            except x509.ExtensionNotFound:
                continue

            for policy in val:
                pi1 = PolicyInformation(policy)
                self.assertEqual(pi1.for_extension_type, policy)

                # pass the serialized value to the constructor and see if it's still the same
                pi2 = PolicyInformation(pi1.serialize())
                self.assertEqual(pi1, pi2)
                self.assertEqual(pi1.serialize(), pi2.serialize())
                self.assertEqual(pi2.for_extension_type, policy)

    def test_clear(self):
        """Test PolicyInformation.clear()."""
        self.pi1.clear()
        self.assertIsNone(self.pi1.policy_qualifiers)

    def test_constructor(self):
        """Test some constructors that are otherwise not called."""
        pinfo = PolicyInformation()
        self.assertIsNone(pinfo.policy_identifier)
        self.assertIsNone(pinfo.policy_qualifiers)

        pinfo = PolicyInformation({
            'policy_identifier':
            '1.2.3',
            'policy_qualifiers': [
                x509.UserNotice(notice_reference=None, explicit_text='foobar'),
            ],
        })
        self.assertEqual(len(pinfo), 1)

        pinfo = PolicyInformation({
            'policy_identifier':
            '1.2.3',
            'policy_qualifiers': [{
                'notice_reference':
                x509.NoticeReference(organization='foobar',
                                     notice_numbers=[1]),
            }],
        })
        self.assertEqual(len(pinfo), 1)

    def test_constructor_errors(self):
        """Test various invalid values for the constructor."""
        with self.assertRaisesRegex(
                ValueError,
                r'^PolicyInformation data must be either x509.PolicyInformation or dict$'
        ):
            PolicyInformation(True)

        with self.assertRaisesRegex(
                ValueError,
                r'^PolicyQualifier must be string, dict or x509.UserNotice$'):
            PolicyInformation({
                'policy_identifier': '1.2.3',
                'policy_qualifiers': [True]
            })

        with self.assertRaisesRegex(
                ValueError,
                r'^NoticeReference must be either None, a dict or an x509.NoticeReference$'
        ):
            PolicyInformation({
                'policy_identifier':
                '1.2.3',
                'policy_qualifiers': [{
                    'notice_reference': True,
                }]
            })

    def test_contains(self):
        """Test PolicyInformation.contains()."""
        self.assertIn(self.q1, self.pi1)
        self.assertIn(self.q2, self.pi2)
        self.assertIn(self.q3, self.pi3)
        self.assertIn(self.q4, self.pi4)
        self.assertIn(self.q5, self.pi4)
        self.assertIn(self.s1['policy_qualifiers'][0], self.pi1)
        self.assertIn(self.s2['policy_qualifiers'][0], self.pi2)
        self.assertIn(self.s3['policy_qualifiers'][0], self.pi3)
        self.assertIn(self.s4['policy_qualifiers'][0], self.pi4)
        self.assertIn(self.s4['policy_qualifiers'][1], self.pi4)

        self.assertNotIn(self.q2, self.pi1)
        self.assertNotIn(self.q1, self.pi_empty)
        self.assertNotIn(self.s1['policy_qualifiers'][0], self.pi2)
        self.assertNotIn(self.s2['policy_qualifiers'][0], self.pi1)
        self.assertNotIn(self.s2['policy_qualifiers'][0], self.pi_empty)

    def test_count(self):
        """Test PolicyInformation.count()."""
        self.assertEqual(self.pi1.count(self.s1['policy_qualifiers'][0]), 1)
        self.assertEqual(self.pi1.count(self.q1), 1)
        self.assertEqual(self.pi1.count(self.s2), 0)
        self.assertEqual(self.pi1.count(self.q2), 0)
        self.assertEqual(self.pi_empty.count(self.q2), 0)
        self.assertEqual(self.pi1.count(True), 0)  # pass an unparseable value

    def test_delitem(self):
        """Test item deletion (e.g. ``del pi[0]``)."""
        del self.pi1[0]
        self.pi_empty.policy_identifier = self.oid
        self.assertEqual(self.pi1, self.pi_empty)

        self.assertEqual(len(self.pi4), 2)
        del self.pi4[0]
        self.assertEqual(len(self.pi4), 1)

        with self.assertRaisesRegex(IndexError,
                                    r'^list assignment index out of range$'):
            del self.pi1[0]

    def test_extend(self):
        """Test PolicyInformation.extend()."""
        self.pi1.extend([self.q2, self.q4])
        self.assertEqual(
            self.pi1,
            PolicyInformation({
                'policy_identifier': self.oid,
                'policy_qualifiers': [self.q1, self.q2, self.q4],
            }))

        self.pi2.extend([self.s1['policy_qualifiers'][0]])
        self.assertEqual(
            self.pi2,
            PolicyInformation({
                'policy_identifier': self.oid,
                'policy_qualifiers': [self.q2, self.q1],
            }))

        # extend an empty list
        self.pi_empty.extend([self.s1['policy_qualifiers'][0]])
        self.assertEqual(
            self.pi_empty,
            PolicyInformation({
                'policy_identifier': None,
                'policy_qualifiers': [self.q1],
            }))

    def test_getitem(self):
        """Test item getter (e.g. ``x = ext[0]``)."""
        self.assertEqual(self.pi1[0], self.s1['policy_qualifiers'][0])
        self.assertEqual(self.pi4[0], self.s4['policy_qualifiers'][0])
        self.assertEqual(self.pi4[1], self.s4['policy_qualifiers'][1])
        self.assertEqual(self.pi4[1:], [self.s4['policy_qualifiers'][1]])

        with self.assertRaisesRegex(IndexError, r'^list index out of range$'):
            self.pi_empty[0]  # pylint: disable=pointless-statement
        with self.assertRaisesRegex(IndexError, r'^list index out of range$'):
            self.pi_empty[2:]  # pylint: disable=pointless-statement

    def test_hash(self):
        """Test hash()."""
        self.assertEqual(hash(self.pi1), hash(self.pi1))
        self.assertEqual(hash(self.pi2), hash(self.pi2))
        self.assertEqual(hash(self.pi3), hash(self.pi3))
        self.assertEqual(hash(self.pi4), hash(self.pi4))
        self.assertEqual(hash(self.pi_empty), hash(self.pi_empty))

        self.assertEqual(hash(self.pi1), hash(PolicyInformation(self.s1)))
        self.assertEqual(hash(self.pi2), hash(PolicyInformation(self.s2)))
        self.assertEqual(hash(self.pi3), hash(PolicyInformation(self.s3)))
        self.assertEqual(hash(self.pi4), hash(PolicyInformation(self.s4)))
        self.assertEqual(hash(self.pi_empty), hash(PolicyInformation()))

        self.assertNotEqual(hash(self.pi1), hash(self.pi2))
        self.assertNotEqual(hash(self.pi1), hash(self.pi3))
        self.assertNotEqual(hash(self.pi1), hash(self.pi4))
        self.assertNotEqual(hash(self.pi2), hash(self.pi3))
        self.assertNotEqual(hash(self.pi2), hash(self.pi4))
        self.assertNotEqual(hash(self.pi3), hash(self.pi4))

    def test_insert(self):
        """Test PolicyInformation.insert()."""
        self.pi1.insert(0, self.q2)
        self.assertEqual(
            self.pi1,
            PolicyInformation({
                'policy_identifier': self.oid,
                'policy_qualifiers': [self.q2, self.q1],
            }))
        self.pi1.insert(1, self.s3['policy_qualifiers'][0])
        self.assertEqual(
            self.pi1,
            PolicyInformation({
                'policy_identifier': self.oid,
                'policy_qualifiers': [self.q2, self.q3, self.q1],
            }))

        self.pi_empty.insert(1, self.q2)
        self.pi_empty.policy_identifier = self.oid
        self.assertEqual(self.pi2, self.pi_empty)

    def test_len(self):
        """Test len(ext)."""
        self.assertEqual(len(self.pi1), 1)
        self.assertEqual(len(self.pi2), 1)
        self.assertEqual(len(self.pi3), 1)
        self.assertEqual(len(self.pi4), 2)
        self.assertEqual(len(self.pi_empty), 0)

    def test_policy_identifier_setter(self):
        """Test setting a policy identifier."""
        value = '1.2.3'
        expected = ObjectIdentifier(value)
        pinfo = PolicyInformation({'policy_identifier': value})
        pinfo.policy_identifier = value
        self.assertEqual(pinfo.policy_identifier, expected)

        pinfo = PolicyInformation({'policy_identifier': expected})
        self.assertEqual(pinfo.policy_identifier, expected)

        new_value = '2.3.4'
        new_expected = ObjectIdentifier(new_value)
        pinfo.policy_identifier = new_value
        self.assertEqual(pinfo.policy_identifier, new_expected)

    def test_pop(self):
        """Test PolicyInformation.pop()."""
        self.pi_empty.policy_identifier = self.oid
        self.assertEqual(self.pi1.pop(), self.s1['policy_qualifiers'][0])
        self.assertEqual(self.pi1, self.pi_empty)

        self.assertEqual(self.pi4.pop(1), self.s4['policy_qualifiers'][1])
        self.assertEqual(
            self.pi4,
            PolicyInformation({
                'policy_identifier': self.oid,
                'policy_qualifiers': [self.q4],
            }))

        self.assertEqual(self.pi4.pop(), self.s4['policy_qualifiers'][0])
        self.assertEqual(self.pi4, self.pi_empty)

        with self.assertRaisesRegex(IndexError, r'^pop from empty list$'):
            self.pi_empty.pop()

    def test_remove(self):
        """Test PolicyInformation.remove()."""
        self.pi_empty.policy_identifier = self.oid
        self.pi1.remove(self.q1)
        self.assertEqual(self.pi1, self.pi_empty)

        self.pi2.remove(self.s2['policy_qualifiers'][0])
        self.assertEqual(self.pi1, self.pi_empty)

        self.pi4.remove(self.q4)
        self.assertEqual(
            self.pi4,
            PolicyInformation({
                'policy_identifier': self.oid,
                'policy_qualifiers': [self.q5],
            }))

        with self.assertRaisesRegex(ValueError, r'^.*: not in list\.$'):
            self.pi_empty.remove(self.s3['policy_qualifiers'][0])

    def _test_repr(self, func):
        self.assertEqual(
            func(self.pi1),
            "<PolicyInformation(oid=2.5.29.32.0, qualifiers=['text1'])>")
        self.assertEqual(
            func(self.pi2),
            "<PolicyInformation(oid=2.5.29.32.0, qualifiers=[{'explicit_text': 'text2'}])>"
        )
        self.assertEqual(func(self.pi_empty),
                         "<PolicyInformation(oid=None, qualifiers=None)>")

        # NOTE: order of dict is different here, so we do not test output, just make sure there's no exception
        func(self.pi3)
        func(self.pi4)

    def test_repr(self):
        """Test repr()."""
        self._test_repr(repr)

    def test_str(self):
        """Test str()."""
        self._test_repr(str)