Exemplo n.º 1
0
 def get_common_extensions(self,
                           issuer_url=None,
                           crl_url=None,
                           ocsp_url=None):
     extensions = []
     if crl_url:
         if isinstance(crl_url, six.string_types):
             crl_url = [url.strip() for url in crl_url.split()]
         urls = [
             x509.UniformResourceIdentifier(force_text(c)) for c in crl_url
         ]
         dps = [
             x509.DistributionPoint(full_name=[c],
                                    relative_name=None,
                                    crl_issuer=None,
                                    reasons=None) for c in urls
         ]
         extensions.append((False, x509.CRLDistributionPoints(dps)))
     auth_info_access = []
     if ocsp_url:
         uri = x509.UniformResourceIdentifier(force_text(ocsp_url))
         auth_info_access.append(
             x509.AccessDescription(
                 access_method=AuthorityInformationAccessOID.OCSP,
                 access_location=uri))
     if issuer_url:
         uri = x509.UniformResourceIdentifier(force_text(issuer_url))
         auth_info_access.append(
             x509.AccessDescription(
                 access_method=AuthorityInformationAccessOID.CA_ISSUERS,
                 access_location=uri))
     if auth_info_access:
         extensions.append(
             (False, x509.AuthorityInformationAccess(auth_info_access)))
     return extensions
Exemplo n.º 2
0
    def get_common_extensions(
        self,
        issuer_url: Optional[str] = None,
        crl_url: Optional[Iterable[str]] = None,
        ocsp_url: Optional[str] = None,
    ) -> List[Tuple[bool, Union[x509.CRLDistributionPoints, x509.AuthorityInformationAccess]]]:
        """Add extensions potentially common to both CAs and certs."""

        extensions: List[Tuple[bool, Union[x509.CRLDistributionPoints, x509.AuthorityInformationAccess]]] = []
        if crl_url:
            urls = [x509.UniformResourceIdentifier(c) for c in crl_url]
            dps = [
                x509.DistributionPoint(full_name=[c], relative_name=None, crl_issuer=None, reasons=None)
                for c in urls
            ]
            extensions.append((False, x509.CRLDistributionPoints(dps)))
        auth_info_access = []
        if ocsp_url:
            uri = x509.UniformResourceIdentifier(ocsp_url)
            auth_info_access.append(
                x509.AccessDescription(access_method=AuthorityInformationAccessOID.OCSP, access_location=uri)
            )
        if issuer_url:
            uri = x509.UniformResourceIdentifier(issuer_url)
            auth_info_access.append(
                x509.AccessDescription(
                    access_method=AuthorityInformationAccessOID.CA_ISSUERS, access_location=uri
                )
            )
        if auth_info_access:
            extensions.append((False, x509.AuthorityInformationAccess(auth_info_access)))
        return extensions
Exemplo n.º 3
0
 def extension_type(self) -> x509.AuthorityInformationAccess:
     # pylint: disable=not-an-iterable; pylint does not detect GeneralNameList as iterable
     descs = [
         x509.AccessDescription(AuthorityInformationAccessOID.CA_ISSUERS, v)
         for v in self._issuers
     ]
     descs += [
         x509.AccessDescription(AuthorityInformationAccessOID.OCSP, v)
         for v in self._ocsp
     ]
     return x509.AuthorityInformationAccess(descriptions=descs)
Exemplo n.º 4
0
 def assert_oscp(self, crt, certificate):
     ext = crt.extensions.get_extension_for_oid(ExtensionOID.AUTHORITY_INFORMATION_ACCESS)
     self.assertFalse(ext.critical)
     self.assertEqual(
         ext.value[0],
         x509.AccessDescription(
             AuthorityInformationAccessOID.OCSP, x509.UniformResourceIdentifier(certificate.ocsp_distribution_host)
         ),
     )
Exemplo n.º 5
0
 def _set_ocsp_distribution_url(self, cert: Certificate_model) -> None:
     if cert.type == CertificateTypes.SERVER_CERT or cert.type == CertificateTypes.CLIENT_CERT:
         cert = cert.parent
     if cert.ocsp_distribution_host:
         self._builder = self._builder.add_extension(
             x509.AuthorityInformationAccess([
                 x509.AccessDescription(
                     AuthorityInformationAccessOID.OCSP,
                     x509.UniformResourceIdentifier(
                         cert.ocsp_distribution_host))
             ]),
             critical=True)
Exemplo n.º 6
0
def _decode_authority_information_access(backend, aia):
    aia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia)
    aia = backend._ffi.gc(aia, backend._lib.sk_ACCESS_DESCRIPTION_free)
    num = backend._lib.sk_ACCESS_DESCRIPTION_num(aia)
    access_descriptions = []
    for i in range(num):
        ad = backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i)
        backend.openssl_assert(ad.method != backend._ffi.NULL)
        oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method))
        backend.openssl_assert(ad.location != backend._ffi.NULL)
        gn = _decode_general_name(backend, ad.location)
        access_descriptions.append(x509.AccessDescription(oid, gn))

    return x509.AuthorityInformationAccess(access_descriptions)
Exemplo n.º 7
0
 def _set_ocsp_distribution_url(self, cert: CertificateType) -> None:
     if cert.type is not CertificateTypes.ROOT:
         cert = cert.parent
         if cert.ocsp_distribution_host:
             self._builder = self._builder.add_extension(
                 x509.AuthorityInformationAccess([
                     x509.AccessDescription(
                         AuthorityInformationAccessOID.OCSP,
                         x509.UniformResourceIdentifier(
                             cert.ocsp_distribution_host),
                     )
                 ]),
                 critical=False,
             )
Exemplo n.º 8
0
def test_multiple_aia(ca_workspace, server):
    root = ca_workspace.issue_new_trusted_root()
    intermediate = ca_workspace.issue_new_ca(root)
    intermediate_url = server.create_aia_url(intermediate)
    cert = ca_workspace.issue_new_leaf(
        intermediate, ca_issuers=[
            x509.AccessDescription(
                x509.AuthorityInformationAccessOID.OCSP,
                x509.UniformResourceIdentifier("http://example.com")
            ),
            intermediate_url
        ]
    )

    ca_workspace.assert_validates(cert, [cert, intermediate, root])
Exemplo n.º 9
0
def _decode_information_access(backend, ia):
    ia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", ia)
    ia = backend._ffi.gc(
        ia, lambda x: backend._lib.sk_ACCESS_DESCRIPTION_pop_free(
            x,
            backend._ffi.addressof(backend._lib._original_lib,
                                   "ACCESS_DESCRIPTION_free")))
    num = backend._lib.sk_ACCESS_DESCRIPTION_num(ia)
    access_descriptions = []
    for i in range(num):
        ad = backend._lib.sk_ACCESS_DESCRIPTION_value(ia, i)
        backend.openssl_assert(ad.method != backend._ffi.NULL)
        oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method))
        backend.openssl_assert(ad.location != backend._ffi.NULL)
        gn = _decode_general_name(backend, ad.location)
        access_descriptions.append(x509.AccessDescription(oid, gn))

    return access_descriptions
Exemplo n.º 10
0
    def _build_authority_information_access(self, ext):
        aia = self._backend._lib.X509V3_EXT_d2i(ext)
        assert aia != self._backend._ffi.NULL
        aia = self._backend._ffi.cast(
            "Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia)
        aia = self._backend._ffi.gc(
            aia, self._backend._lib.sk_ACCESS_DESCRIPTION_free)
        num = self._backend._lib.sk_ACCESS_DESCRIPTION_num(aia)
        access_descriptions = []
        for i in range(num):
            ad = self._backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i)
            assert ad.method != self._backend._ffi.NULL
            oid = x509.ObjectIdentifier(_obj2txt(self._backend, ad.method))
            assert ad.location != self._backend._ffi.NULL
            gn = _build_general_name(self._backend, ad.location)
            access_descriptions.append(x509.AccessDescription(oid, gn))

        return x509.AuthorityInformationAccess(access_descriptions)
Exemplo n.º 11
0
def parse_access_desc(desc):
    if 'method' not in desc:
        raise ValueError('Access description must contain \'method\' field.')

    method = desc['method']
    if method != 'OCSP' and method != 'CA_ISSUERS':
        raise ValueError(
            'Available methods for access description are OCSP and CA_ISSUERS')

    if method == 'OCSP':
        method = x509.AuthorityInformationAccessOID.OCSP
    else:
        method = x509.AuthorityInformationAccessOID.CA_ISSUERS

    if 'value' not in desc:
        raise ValueError('Access description must contain \'value\' field.')

    return x509.AccessDescription(method, parse_general_name(desc['value']))
Exemplo n.º 12
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)
Exemplo n.º 13
0
    def test_generate_user_certificate(self):
        root_key = Key().create_key(2048)
        root_certificate = CertificateFactory(expires_at=arrow.get(
            timezone.now()).replace(days=+6).date(),
                                              key=root_key.serialize())
        root_certhandler = Certificate()
        root_certhandler.create_certificate(root_certificate)

        subject = DistinguishedNameFactory(
            countryName=root_certificate.dn.countryName,
            stateOrProvinceName=root_certificate.dn.stateOrProvinceName,
            organizationName=root_certificate.dn.organizationName)

        int_key = Key().create_key(2048)

        int_certificate = CertificateFactory(
            expires_at=arrow.get(timezone.now()).replace(days=+5).date(),
            type=CertificateTypes.INTERMEDIATE,
            parent=root_certificate,
            dn=subject,
            key=int_key.serialize())
        int_certhandler = Certificate()
        int_certhandler.create_certificate(int_certificate)

        key = Key().create_key(2048)
        server_subject = DistinguishedNameFactory(
            subjectAltNames=["jeroen", "*****@*****.**"])
        certificate = CertificateFactory(type=CertificateTypes.CLIENT_CERT,
                                         parent=int_certificate,
                                         dn=server_subject,
                                         key=key.serialize())
        certhandler = Certificate()
        certhandler.create_certificate(certificate)

        crt = certhandler.certificate

        self.assertEqual(crt.serial_number, int(certificate.serial))
        self.assertEqual(crt.public_key().public_numbers(),
                         key.key.public_key().public_numbers())
        self.assertEqual(
            crt.not_valid_before,
            datetime.datetime(year=certificate.created_at.year,
                              month=certificate.created_at.month,
                              day=certificate.created_at.day))

        self.assertEqual(
            crt.not_valid_after,
            datetime.datetime(year=certificate.expires_at.year,
                              month=certificate.expires_at.month,
                              day=certificate.expires_at.day))
        # basicConstraints = CA:FALSE
        ext = crt.extensions.get_extension_for_oid(
            ExtensionOID.BASIC_CONSTRAINTS)
        self.assertFalse(ext.critical)
        self.assertEqual(ext.value,
                         x509.BasicConstraints(ca=False, path_length=None))

        # authorityKeyIdentifier = keyid:always, issuer
        ext = crt.extensions.get_extension_for_oid(
            ExtensionOID.AUTHORITY_KEY_IDENTIFIER)
        self.assertTrue(ext.critical)
        self.assertEqual(
            ext.value.key_identifier,
            _key_identifier_from_public_key(int_key.key.public_key()))

        # subjectKeyIdentifier = hash
        ext = crt.extensions.get_extension_for_oid(
            ExtensionOID.SUBJECT_KEY_IDENTIFIER)
        self.assertTrue(ext.critical)
        self.assertEqual(ext.value.digest,
                         _key_identifier_from_public_key(key.key.public_key()))

        # keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
        ext = crt.extensions.get_extension_for_oid(ExtensionOID.KEY_USAGE)
        self.assertTrue(ext.critical)
        self.assertEqual(
            ext.value,
            x509.KeyUsage(digital_signature=True,
                          content_commitment=True,
                          key_encipherment=True,
                          data_encipherment=False,
                          key_agreement=False,
                          key_cert_sign=False,
                          crl_sign=False,
                          encipher_only=False,
                          decipher_only=False))

        # extendedKeyUsage = clientAuth, emailProtection
        ext = crt.extensions.get_extension_for_oid(
            ExtensionOID.EXTENDED_KEY_USAGE)
        self.assertFalse(ext.critical)
        self.assertEqual([x for x in ext.value], [
            ExtendedKeyUsageOID.CLIENT_AUTH,
            ExtendedKeyUsageOID.EMAIL_PROTECTION
        ])

        # { % if cert.dn.subjectAltNames %}
        # subjectAltName = @alt_names
        ext = crt.extensions.get_extension_for_oid(
            ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
        self.assertFalse(ext.critical)
        self.assertEqual([x.value for x in ext.value],
                         ['jeroen', '*****@*****.**'])

        # crlDistributionPoints
        ext = crt.extensions.get_extension_for_oid(
            ExtensionOID.CRL_DISTRIBUTION_POINTS)
        self.assertTrue(ext.critical)
        crl_dp = ext.value
        self.assertEqual(
            crl_dp[0].full_name[0].value,
            'URI:{}{}.crl'.format(int_certificate.crl_distribution_url,
                                  int_certificate.shortname))
        self.assertEqual(
            crl_dp[0].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,
            ]))

        # OCSP
        # authorityInfoAccess = OCSP;URI:{{cert.ocsp_distribution_host}}
        ext = crt.extensions.get_extension_for_oid(
            ExtensionOID.AUTHORITY_INFORMATION_ACCESS)
        self.assertTrue(ext.critical)
        self.assertEqual(
            ext.value[0],
            x509.AccessDescription(
                AuthorityInformationAccessOID.OCSP,
                x509.UniformResourceIdentifier(
                    int_certificate.ocsp_distribution_host)))

        # subject
        subject = crt.subject
        self.assertIsInstance(subject, x509.Name)
        self.assertListEqual(list(subject), [
            x509.NameAttribute(NameOID.COMMON_NAME, certificate.dn.commonName),
            x509.NameAttribute(NameOID.ORGANIZATION_NAME,
                               certificate.dn.organizationName),
            x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME,
                               certificate.dn.organizationalUnitName),
            x509.NameAttribute(NameOID.LOCALITY_NAME,
                               certificate.dn.localityName),
            x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME,
                               certificate.dn.stateOrProvinceName),
            x509.NameAttribute(NameOID.EMAIL_ADDRESS,
                               certificate.dn.emailAddress),
            x509.NameAttribute(NameOID.COUNTRY_NAME,
                               str(certificate.dn.countryName)),
        ])

        # issuer
        issuer = crt.issuer
        self.assertIsInstance(issuer, x509.Name)
        self.assertListEqual(list(issuer), [
            x509.NameAttribute(NameOID.COMMON_NAME,
                               int_certificate.dn.commonName),
            x509.NameAttribute(NameOID.ORGANIZATION_NAME,
                               int_certificate.dn.organizationName),
            x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME,
                               int_certificate.dn.organizationalUnitName),
            x509.NameAttribute(NameOID.LOCALITY_NAME,
                               int_certificate.dn.localityName),
            x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME,
                               int_certificate.dn.stateOrProvinceName),
            x509.NameAttribute(NameOID.EMAIL_ADDRESS,
                               int_certificate.dn.emailAddress),
            x509.NameAttribute(NameOID.COUNTRY_NAME,
                               str(int_certificate.dn.countryName)),
        ])
Exemplo n.º 14
0
    def generate(self,
                 csr,
                 issuer_crt,
                 issuer_key,
                 profile,
                 ca=False,
                 selfSigned=False,
                 start=None,
                 duration=None,
                 digest=None,
                 sans=[]):
        """Generate a certificate using:
            - Certificate request (csr)
            - Issuer certificate (issuer_crt)
            - Issuer key (issuer_key)
            - profile object (profile)
        Optional parameters set:
            - a CA certificate role (ca)
            - a self-signed certificate (selfSigned)
            - a specific start timestamp (start) 
        """

        # Retrieve subject from csr
        subject = csr.subject
        self.output('Subject found: {s}'.format(s=subject.rfc4514_string()),
                    level="DEBUG")
        dn = self._get_dn(subject)
        self.output('DN found is {d}'.format(d=dn), level="DEBUG")

        try:
            alt_names = None
            alt_names = csr.extensions.get_extension_for_oid(
                ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
            self.output('Subject alternate found: {s}'.format(s=alt_names),
                        level="DEBUG")
        except x509.ExtensionNotFound as err:
            pass

        # Force default if necessary
        now = datetime.datetime.utcnow(
        ) if start is None else datetime.fromtimestamp(start)
        duration = profile['duration'] if duration is None else duration

        # Generate serial number
        try:
            serial_number = self._generate_serial()
        except Exception as err:
            raise Exception(
                'Error during serial number generation: {e}'.format(e=err))

        # For self-signed certificate issuer is certificate itself
        issuer_name = subject if selfSigned else issuer_crt.issuer
        issuer_serial = serial_number if selfSigned else issuer_crt.serial_number

        try:
            # Define basic constraints
            if ca:
                basic_contraints = x509.BasicConstraints(ca=True,
                                                         path_length=0)
            else:
                basic_contraints = x509.BasicConstraints(ca=False,
                                                         path_length=None)
            builder = (x509.CertificateBuilder().subject_name(
                subject).issuer_name(issuer_name).public_key(
                    csr.public_key()).serial_number(
                        serial_number).not_valid_before(now).not_valid_after(
                            now +
                            datetime.timedelta(days=duration)).add_extension(
                                basic_contraints, critical=True))
        except Exception as err:
            raise Exception('Unable to build structure: {e}'.format(e=err))

        # We never trust CSR extensions
        # they may have been alterated by the user
        try:
            # Due to uPKI design (TLS for renew), digital_signature MUST be setup
            digital_signature = True
            # Initialize key usage
            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

            # Build Key Usages from profile
            for usage in profile['keyUsage']:
                if usage == 'digitalSignature':
                    digital_signature = True
                elif usage == 'nonRepudiation':
                    content_commitment = True
                elif usage == 'keyEncipherment':
                    key_encipherment = True
                elif usage == 'dataEncipherment':
                    data_encipherment = True
                elif usage == 'keyAgreement':
                    key_agreement = True
                elif usage == 'keyCertSign':
                    key_cert_sign = True
                elif usage == 'cRLSign':
                    crl_sign = True
                elif usage == 'encipherOnly':
                    encipher_only = True
                elif usage == 'decipherOnly':
                    decipher_only = True

            # Setup X509 Key Usages
            key_usages = x509.KeyUsage(digital_signature=digital_signature,
                                       content_commitment=content_commitment,
                                       key_encipherment=key_encipherment,
                                       data_encipherment=data_encipherment,
                                       key_agreement=key_agreement,
                                       key_cert_sign=key_cert_sign,
                                       crl_sign=crl_sign,
                                       encipher_only=encipher_only,
                                       decipher_only=decipher_only)
            builder = builder.add_extension(key_usages, critical=True)
        except KeyError:
            # If no Key Usages are set, thats strange
            raise Exception('No Key Usages set.')
        except Exception as err:
            raise Exception('Unable to set Key Usages: {e}'.format(e=err))

        try:
            # Build Key Usages extended based on profile
            key_usages_extended = list()
            for eusage in profile['extendedKeyUsage']:
                if eusage == 'serverAuth':
                    key_usages_extended.append(ExtendedKeyUsageOID.SERVER_AUTH)
                elif eusage == 'clientAuth':
                    key_usages_extended.append(ExtendedKeyUsageOID.CLIENT_AUTH)
                elif eusage == 'codeSigning':
                    key_usages_extended.append(
                        ExtendedKeyUsageOID.CODE_SIGNING)
                elif eusage == 'emailProtection':
                    key_usages_extended.append(
                        ExtendedKeyUsageOID.EMAIL_PROTECTION)
                elif eusage == 'timeStamping':
                    key_usages_extended.append(
                        ExtendedKeyUsageOID.TIME_STAMPING)
                elif eusage == 'OCSPSigning':
                    key_usages_extended.append(
                        ExtendedKeyUsageOID.OCSP_SIGNING)

            #### CHECK TROUBLES ASSOCIATED WITH THIS CHOICE #####
            # Always add 'clientAuth' for automatic renewal
            if ExtendedKeyUsageOID.CLIENT_AUTH not in key_usages_extended:
                key_usages_extended.append(ExtendedKeyUsageOID.CLIENT_AUTH)
            #####################################################

            # Add Deprecated nsCertType (still required by some software)
            # nsCertType_oid = x509.ObjectIdentifier('2.16.840.1.113730.1.1')
            # for c_type in profile['certType']:
            #     if c_type.lower() in ['client', 'server', 'email', 'objsign']:
            #         builder.add_extension(nsCertType_oid, c_type.lower())

            # Set Key Usages if needed
            if len(key_usages_extended):
                builder = builder.add_extension(
                    x509.ExtendedKeyUsage(key_usages_extended), critical=False)
        except KeyError:
            # If no extended key usages are set, do nothing
            pass
        except Exception as err:
            raise Exception(
                'Unable to set Extended Key Usages: {e}'.format(e=err))

        # Add alternate names if found in CSR
        if alt_names is not None:
            # Verify each time that SANS entry was registered
            # We can NOT trust CSR data (client manipulation)
            subject_alt = list([])

            for entry in alt_names.value.get_values_for_type(x509.IPAddress):
                if entry not in sans:
                    continue
                subject_alt.append(x509.IPAddress(ipaddress.ip_address(entry)))

            for entry in alt_names.value.get_values_for_type(x509.DNSName):
                if entry not in sans:
                    continue
                subject_alt.append(x509.DNSName(entry))

            for entry in alt_names.value.get_values_for_type(x509.RFC822Name):
                if entry not in sans:
                    continue
                subject_alt.append(x509.RFC822Name(entry))

            for entry in alt_names.value.get_values_for_type(
                    x509.UniformResourceIdentifier):
                if entry not in sans:
                    continue
                subject_alt.append(x509.UniformResourceIdentifier(entry))

            try:
                # Add all alternates to certificate
                builder = builder.add_extension(
                    x509.SubjectAlternativeName(subject_alt), critical=False)
            except Exception as err:
                raise Exception(
                    'Unable to set alternatives name: {e}'.format(e=err))

        try:
            # Register signing authority
            issuer_key_id = x509.SubjectKeyIdentifier.from_public_key(
                issuer_key.public_key())
            builder = builder.add_extension(x509.AuthorityKeyIdentifier(
                issuer_key_id.digest, [x509.DirectoryName(issuer_name)],
                issuer_serial),
                                            critical=False)
        except Exception as err:
            raise Exception(
                'Unable to setup Authority Identifier: {e}'.format(e=err))

        ca_endpoints = list()
        try:
            # Default value if not set in profile
            ca_url = profile['ca'] if profile[
                'ca'] else "https://certificates.{d}/certs/ca.crt".format(
                    d=profile['domain'])
        except KeyError:
            ca_url = None
        try:
            # Default value if not set in profile
            ocsp_url = profile['ocsp'] if profile[
                'ocsp'] else "https://certificates.{d}/ocsp".format(
                    d=profile['domain'])
        except KeyError:
            ocsp_url = None

        try:
            # Add CA certificate distribution point and OCSP validation url
            if ca_url:
                ca_endpoints.append(
                    x509.AccessDescription(
                        x509.oid.AuthorityInformationAccessOID.OCSP,
                        x509.UniformResourceIdentifier(ca_url)))
            if ocsp_url:
                ca_endpoints.append(
                    x509.AccessDescription(
                        x509.oid.AuthorityInformationAccessOID.OCSP,
                        x509.UniformResourceIdentifier(ocsp_url)))
            builder = builder.add_extension(
                x509.AuthorityInformationAccess(ca_endpoints), critical=False)
        except Exception as err:
            raise Exception(
                'Unable to setup OCSP/CA endpoint: {e}'.format(e=err))

        try:
            # Add CRL distribution point
            crl_endpoints = list()
            # Default value if not set in profile
            url = "https://certificates.{d}/certs/crl.pem".format(
                d=profile['domain'])
            try:
                if profile['csr']:
                    url = profile['csr']
            except KeyError:
                pass
            crl_endpoints.append(
                x509.DistributionPoint(
                    [x509.UniformResourceIdentifier(url)], None, None,
                    [x509.DNSName(issuer_name.rfc4514_string())]))
            builder = builder.add_extension(
                x509.CRLDistributionPoints(crl_endpoints), critical=False)
        except Exception as err:
            raise Exception('Unable to setup CRL endpoints: {e}'.format(e=err))

        if digest is None:
            digest = profile['digest']

        if digest == 'md5':
            digest = hashes.MD5()
        elif digest == 'sha1':
            digest = hashes.SHA1()
        elif digest == 'sha256':
            digest = hashes.SHA256()
        elif digest == 'sha512':
            digest = hashed.SHA512()
        else:
            raise NotImplementedError(
                'Private key only support {s} digest signatures'.format(
                    s=self._allowed.Digest))

        try:
            pub_crt = builder.sign(private_key=issuer_key,
                                   algorithm=digest,
                                   backend=self.__backend)
        except Exception as err:
            raise Exception('Unable to sign certificate: {e}'.format(e=err))

        return pub_crt
Exemplo n.º 15
0
def makeCert(cert_data):
    #given parameters for cert, returns bytes for certificate (private key and public key)

    private_key = rsa.generate_private_key(public_exponent=65537,
                                           key_size=2048,
                                           backend=default_backend())
    public_key = private_key.public_key()

    builder = x509.CertificateBuilder()
    subject = x509.Name([
        x509.NameAttribute(NameOID.COMMON_NAME, cert_data.common_name),
        x509.NameAttribute(NameOID.COUNTRY_NAME, cert_data.country_name),
        x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME,
                           cert_data.state_or_province_name),
        x509.NameAttribute(NameOID.LOCALITY_NAME, cert_data.locality_name),
        x509.NameAttribute(NameOID.ORGANIZATION_NAME,
                           cert_data.organization_name),
        x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME,
                           cert_data.organization_unit_name),
        x509.NameAttribute(NameOID.USER_ID, cert_data.user_id),
        x509.NameAttribute(NameOID.EMAIL_ADDRESS, cert_data.email_address),
    ])
    builder = builder.subject_name(subject)
    builder = builder.not_valid_before(cert_data.not_valid_before)
    builder = builder.not_valid_after(cert_data.not_valid_after)
    builder = builder.serial_number(cert_data.serial_number)
    builder = builder.public_key(public_key)
    builder = builder.add_extension(x509.SubjectAlternativeName(
        [x509.DNSName(cert_data.dns_name)]),
                                    critical=False)

    #if CA

    if (cert_data.is_ca):

        builder = builder.issuer_name(subject)
        builder = builder.add_extension(
            x509.BasicConstraints(ca=True, path_length=2),
            critical=True,
        )
        builder = builder.add_extension(x509.KeyUsage(digital_signature=True,
                                                      content_commitment=True,
                                                      key_encipherment=True,
                                                      key_agreement=False,
                                                      data_encipherment=False,
                                                      crl_sign=True,
                                                      encipher_only=False,
                                                      decipher_only=False,
                                                      key_cert_sign=True),
                                        critical=True)

        builder = builder.add_extension(x509.AuthorityInformationAccess([
            (x509.AccessDescription(
                x509.oid.AuthorityInformationAccessOID.OCSP,
                x509.UniformResourceIdentifier('https:ocsp.zibawa.com')))
        ]),
                                        critical=False)

        certificate = builder.sign(private_key=private_key,
                                   algorithm=hashes.SHA256(),
                                   backend=default_backend())
        #write certificate to pem file
        with open(certStorePath(cert_data.serial_number), "wb") as f:

            f.write(certificate.public_bytes(serialization.Encoding.PEM))
    #write private key to pem file
        with open(keyStorePath(cert_data.serial_number), "wb") as f:
            f.write(
                private_key.private_bytes(
                    encoding=serialization.Encoding.PEM,
                    format=serialization.PrivateFormat.TraditionalOpenSSL,
                    encryption_algorithm=serialization.NoEncryption()))
        #returns only public cert as datastream
        dataStream = (certificate.public_bytes(serialization.Encoding.PEM))

    else:

        #if NOT CA

        builder = builder.issuer_name(
            loadPEMCert(certStorePath(cert_data.issuer_serial_number)).subject)
        builder = builder.add_extension(
            x509.BasicConstraints(ca=False, path_length=None),
            critical=True,
        )
        builder = builder.add_extension(x509.KeyUsage(digital_signature=True,
                                                      content_commitment=True,
                                                      key_encipherment=True,
                                                      key_agreement=False,
                                                      data_encipherment=False,
                                                      crl_sign=False,
                                                      encipher_only=False,
                                                      decipher_only=False,
                                                      key_cert_sign=False),
                                        critical=True)

        certificate = builder.sign(private_key=loadPEMKey(
            keyStorePath(cert_data.issuer_serial_number)),
                                   algorithm=hashes.SHA256(),
                                   backend=default_backend())
        #if not CA return public AND private key
        dataStream = private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption())
        dataStream += (certificate.public_bytes(serialization.Encoding.PEM))

    return dataStream
Exemplo n.º 16
0
def sign_csr(key,
             csr,
             caprofile,
             valid=30,
             isca=False,
             cacert=None,
             aia_issuers=None,
             ocsp_responders=None):
    global SETTINGS

    one_day = datetime.timedelta(1, 0, 0)

    builder = x509.CertificateBuilder()
    builder = builder.subject_name(csr.subject)

    if not cacert:
        builder = builder.issuer_name(x509.Name(construct_sn(caprofile)))
    else:
        builder = builder.issuer_name(cacert.subject)

    builder = builder.not_valid_before(datetime.datetime.today() - one_day)
    builder = builder.not_valid_after(datetime.datetime.today() +
                                      (one_day * valid))
    #builder = builder.serial_number(x509.random_serial_number()) # too new to some systems
    builder = builder.serial_number(
        int.from_bytes(os.urandom(10), byteorder="big"))
    builder = builder.public_key(csr.public_key())

    builder = builder.add_extension(x509.SubjectKeyIdentifier.from_public_key(
        csr.public_key()),
                                    critical=False)

    # more info about issuer

    has_ski = False
    try:
        if cacert:
            ski = cacert.extensions.get_extension_for_class(
                x509.SubjectKeyIdentifier)
            builder = builder.add_extension(
                x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
                    ski),
                critical=False)
            has_ski = True
    except AttributeError:
        # this is workaround for older versions of python cryptography, not having from_issuer_subject_key_identifier
        # -> which throws AttributeError
        has_ski = False
    except x509.extensions.ExtensionNotFound:
        has_ski = False

    if not has_ski:
        builder = builder.add_extension(
            x509.AuthorityKeyIdentifier.from_issuer_public_key(
                key.public_key()),
            critical=False)

    all_aias = []
    if aia_issuers:
        for loc in aia_issuers:
            aia_uri = x509.AccessDescription(
                AuthorityInformationAccessOID.CA_ISSUERS,
                x509.UniformResourceIdentifier(loc))
            all_aias.append(aia_uri)

    if ocsp_responders:
        for resp in ocsp_responders:
            aia_uri = x509.AccessDescription(
                AuthorityInformationAccessOID.OCSP,
                x509.UniformResourceIdentifier(resp))
            all_aias.append(aia_uri)

    if all_aias:
        alist = x509.AuthorityInformationAccess(all_aias)
        builder = builder.add_extension(alist, critical=False)

    print("sign CSR: == extensions ==")
    for e in csr.extensions:
        if isinstance(e.value, x509.BasicConstraints):
            print("sign CSR: %s" % (e.oid, ))

            if e.value.ca:
                print("           CA=TRUE requested")

                if isca and not SETTINGS["ca"]["settings"]["grant_ca"]:
                    print("           not allowed but overridden")
                elif not SETTINGS["ca"]["settings"]["grant_ca"]:
                    print("           not allowed by rule")
                    continue
                else:
                    print("           allowed by rule")

        builder = builder.add_extension(e.value, e.critical)

    certificate = builder.sign(private_key=key,
                               algorithm=hashes.SHA256(),
                               backend=default_backend())
    return certificate
Exemplo n.º 17
0
    def test_generate_root_ca(self):
        key = Key().create_key(2048)
        certificate = CertificateFactory(key=key.serialize())
        certhandler = Certificate()
        certhandler.create_certificate(certificate)

        crt = certhandler.certificate

        self.assertEqual(crt.serial_number, int(certificate.serial))
        self.assertEqual(crt.public_key().public_numbers(),
                         key.key.public_key().public_numbers())
        self.assertEqual(
            crt.not_valid_before,
            datetime.datetime(year=certificate.created_at.year,
                              month=certificate.created_at.month,
                              day=certificate.created_at.day))

        self.assertEqual(
            crt.not_valid_after,
            datetime.datetime(year=certificate.expires_at.year,
                              month=certificate.expires_at.month,
                              day=certificate.expires_at.day))

        # subject
        subject = crt.subject
        self.assertIsInstance(subject, x509.Name)
        self.assertListEqual(list(subject), [
            x509.NameAttribute(NameOID.COMMON_NAME, certificate.dn.commonName),
            x509.NameAttribute(NameOID.ORGANIZATION_NAME,
                               certificate.dn.organizationName),
            x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME,
                               certificate.dn.organizationalUnitName),
            x509.NameAttribute(NameOID.LOCALITY_NAME,
                               certificate.dn.localityName),
            x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME,
                               certificate.dn.stateOrProvinceName),
            x509.NameAttribute(NameOID.EMAIL_ADDRESS,
                               certificate.dn.emailAddress),
            x509.NameAttribute(NameOID.COUNTRY_NAME,
                               str(certificate.dn.countryName)),
        ])

        # issuer
        issuer = crt.issuer
        self.assertIsInstance(issuer, x509.Name)
        self.assertListEqual(list(subject), [
            x509.NameAttribute(NameOID.COMMON_NAME, certificate.dn.commonName),
            x509.NameAttribute(NameOID.ORGANIZATION_NAME,
                               certificate.dn.organizationName),
            x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME,
                               certificate.dn.organizationalUnitName),
            x509.NameAttribute(NameOID.LOCALITY_NAME,
                               certificate.dn.localityName),
            x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME,
                               certificate.dn.stateOrProvinceName),
            x509.NameAttribute(NameOID.EMAIL_ADDRESS,
                               certificate.dn.emailAddress),
            x509.NameAttribute(NameOID.COUNTRY_NAME,
                               str(certificate.dn.countryName)),
        ])
        # crlDistributionspoints
        ext = crt.extensions.get_extension_for_oid(
            ExtensionOID.CRL_DISTRIBUTION_POINTS)
        self.assertTrue(ext.critical)
        crl_dp = ext.value
        self.assertEqual(
            crl_dp[0].full_name[0].value,
            'URI:{}{}.crl'.format(certificate.crl_distribution_url,
                                  certificate.shortname))
        self.assertEqual(
            crl_dp[0].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,
            ]))

        # keyUsage = basicConstraints = critical, CA:true
        ext = crt.extensions.get_extension_for_oid(
            ExtensionOID.BASIC_CONSTRAINTS)
        self.assertTrue(ext.critical)
        self.assertEqual(ext.value,
                         x509.BasicConstraints(ca=True, path_length=None))

        # keyUsage = critical, digitalSignature, cRLSign, keyCertSign
        ext = crt.extensions.get_extension_for_oid(ExtensionOID.KEY_USAGE)
        self.assertTrue(ext.critical)
        self.assertEqual(
            ext.value,
            x509.KeyUsage(digital_signature=True,
                          content_commitment=False,
                          key_encipherment=False,
                          data_encipherment=False,
                          key_agreement=False,
                          key_cert_sign=True,
                          crl_sign=True,
                          encipher_only=False,
                          decipher_only=False))

        # OCSP
        # authorityInfoAccess = OCSP;URI:{{cert.ocsp_distribution_host}}
        ext = crt.extensions.get_extension_for_oid(
            ExtensionOID.AUTHORITY_INFORMATION_ACCESS)
        self.assertTrue(ext.critical)
        self.assertEqual(
            ext.value[0],
            x509.AccessDescription(
                AuthorityInformationAccessOID.OCSP,
                x509.UniformResourceIdentifier(
                    certificate.ocsp_distribution_host)))

        # authorityKeyIdentifier = keyid:always, issuer
        ext = crt.extensions.get_extension_for_oid(
            ExtensionOID.AUTHORITY_KEY_IDENTIFIER)
        self.assertTrue(ext.critical)
        self.assertEqual(ext.value.key_identifier,
                         _key_identifier_from_public_key(key.key.public_key()))

        # subjectKeyIdentifier = hash
        ext = crt.extensions.get_extension_for_oid(
            ExtensionOID.SUBJECT_KEY_IDENTIFIER)
        self.assertTrue(ext.critical)
        self.assertEqual(ext.value.digest,
                         _key_identifier_from_public_key(key.key.public_key()))
Exemplo n.º 18
0
class TestCertificateRevocationListBuilder(object):
    def test_issuer_name_invalid(self):
        builder = x509.CertificateRevocationListBuilder()
        with pytest.raises(TypeError):
            builder.issuer_name("notanx509name")

    def test_set_issuer_name_twice(self):
        builder = x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
        )
        with pytest.raises(ValueError):
            builder.issuer_name(
                x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
            )

    @pytest.mark.requires_backend_interface(interface=RSABackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_aware_last_update(self, backend):
        last_time = datetime.datetime(2012, 1, 16, 22, 43)
        tz = pytz.timezone("US/Pacific")
        last_time = tz.localize(last_time)
        utc_last = datetime.datetime(2012, 1, 17, 6, 43)
        next_time = datetime.datetime(2022, 1, 17, 6, 43)
        private_key = RSA_KEY_2048.private_key(backend)
        builder = x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([
                x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
            ])
        ).last_update(last_time).next_update(next_time)

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert crl.last_update == utc_last

    def test_last_update_invalid(self):
        builder = x509.CertificateRevocationListBuilder()
        with pytest.raises(TypeError):
            builder.last_update("notadatetime")

    def test_last_update_before_unix_epoch(self):
        builder = x509.CertificateRevocationListBuilder()
        with pytest.raises(ValueError):
            builder.last_update(datetime.datetime(1960, 8, 10))

    def test_set_last_update_twice(self):
        builder = x509.CertificateRevocationListBuilder().last_update(
            datetime.datetime(2002, 1, 1, 12, 1)
        )
        with pytest.raises(ValueError):
            builder.last_update(datetime.datetime(2002, 1, 1, 12, 1))

    @pytest.mark.requires_backend_interface(interface=RSABackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_aware_next_update(self, backend):
        next_time = datetime.datetime(2022, 1, 16, 22, 43)
        tz = pytz.timezone("US/Pacific")
        next_time = tz.localize(next_time)
        utc_next = datetime.datetime(2022, 1, 17, 6, 43)
        last_time = datetime.datetime(2012, 1, 17, 6, 43)
        private_key = RSA_KEY_2048.private_key(backend)
        builder = x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([
                x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
            ])
        ).last_update(last_time).next_update(next_time)

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert crl.next_update == utc_next

    def test_next_update_invalid(self):
        builder = x509.CertificateRevocationListBuilder()
        with pytest.raises(TypeError):
            builder.next_update("notadatetime")

    def test_next_update_before_unix_epoch(self):
        builder = x509.CertificateRevocationListBuilder()
        with pytest.raises(ValueError):
            builder.next_update(datetime.datetime(1960, 8, 10))

    def test_set_next_update_twice(self):
        builder = x509.CertificateRevocationListBuilder().next_update(
            datetime.datetime(2002, 1, 1, 12, 1)
        )
        with pytest.raises(ValueError):
            builder.next_update(datetime.datetime(2002, 1, 1, 12, 1))

    def test_last_update_after_next_update(self):
        builder = x509.CertificateRevocationListBuilder()

        builder = builder.next_update(
            datetime.datetime(2002, 1, 1, 12, 1)
        )
        with pytest.raises(ValueError):
            builder.last_update(datetime.datetime(2003, 1, 1, 12, 1))

    def test_next_update_after_last_update(self):
        builder = x509.CertificateRevocationListBuilder()

        builder = builder.last_update(
            datetime.datetime(2002, 1, 1, 12, 1)
        )
        with pytest.raises(ValueError):
            builder.next_update(datetime.datetime(2001, 1, 1, 12, 1))

    def test_add_extension_checks_for_duplicates(self):
        builder = x509.CertificateRevocationListBuilder().add_extension(
            x509.CRLNumber(1), False
        )

        with pytest.raises(ValueError):
            builder.add_extension(x509.CRLNumber(2), False)

    def test_add_invalid_extension(self):
        builder = x509.CertificateRevocationListBuilder()

        with pytest.raises(TypeError):
            builder.add_extension(
                object(), False
            )

    def test_add_invalid_revoked_certificate(self):
        builder = x509.CertificateRevocationListBuilder()

        with pytest.raises(TypeError):
            builder.add_revoked_certificate(object())

    @pytest.mark.requires_backend_interface(interface=RSABackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_no_issuer_name(self, backend):
        private_key = RSA_KEY_2048.private_key(backend)
        builder = x509.CertificateRevocationListBuilder().last_update(
            datetime.datetime(2002, 1, 1, 12, 1)
        ).next_update(
            datetime.datetime(2030, 1, 1, 12, 1)
        )

        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.SHA256(), backend)

    @pytest.mark.requires_backend_interface(interface=RSABackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_no_last_update(self, backend):
        private_key = RSA_KEY_2048.private_key(backend)
        builder = x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
        ).next_update(
            datetime.datetime(2030, 1, 1, 12, 1)
        )

        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.SHA256(), backend)

    @pytest.mark.requires_backend_interface(interface=RSABackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_no_next_update(self, backend):
        private_key = RSA_KEY_2048.private_key(backend)
        builder = x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')])
        ).last_update(
            datetime.datetime(2030, 1, 1, 12, 1)
        )

        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.SHA256(), backend)

    @pytest.mark.requires_backend_interface(interface=RSABackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_sign_empty_list(self, backend):
        private_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)

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert len(crl) == 0
        assert crl.last_update == last_update
        assert crl.next_update == next_update

    @pytest.mark.parametrize(
        "extension",
        [
            x509.CRLNumber(13),
            x509.AuthorityKeyIdentifier(
                b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08"
                b"\xcbY",
                None,
                None
            ),
            x509.AuthorityInformationAccess([
                x509.AccessDescription(
                    AuthorityInformationAccessOID.CA_ISSUERS,
                    x509.DNSName(u"cryptography.io")
                )
            ]),
            x509.IssuerAlternativeName([
                x509.UniformResourceIdentifier(u"https://cryptography.io"),
            ])
        ]
    )
    @pytest.mark.requires_backend_interface(interface=RSABackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_sign_extensions(self, backend, extension):
        private_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(
            extension, False
        )

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert len(crl) == 0
        assert len(crl.extensions) == 1
        ext = crl.extensions.get_extension_for_class(type(extension))
        assert ext.critical is False
        assert ext.value == extension

    @pytest.mark.requires_backend_interface(interface=RSABackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_sign_multiple_extensions_critical(self, backend):
        private_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)
        ian = x509.IssuerAlternativeName([
            x509.UniformResourceIdentifier(u"https://cryptography.io"),
        ])
        crl_number = x509.CRLNumber(13)
        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(
            crl_number, False
        ).add_extension(
            ian, True
        )

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert len(crl) == 0
        assert len(crl.extensions) == 2
        ext1 = crl.extensions.get_extension_for_class(x509.CRLNumber)
        assert ext1.critical is False
        assert ext1.value == crl_number
        ext2 = crl.extensions.get_extension_for_class(
            x509.IssuerAlternativeName
        )
        assert ext2.critical is True
        assert ext2.value == ian

    @pytest.mark.requires_backend_interface(interface=RSABackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_add_unsupported_extension(self, backend):
        private_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(
            x509.OCSPNoCheck(), False
        )
        with pytest.raises(NotImplementedError):
            builder.sign(private_key, hashes.SHA256(), backend)

    @pytest.mark.requires_backend_interface(interface=RSABackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_sign_rsa_key_too_small(self, backend):
        private_key = RSA_KEY_512.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
        )

        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.SHA512(), backend)

    @pytest.mark.requires_backend_interface(interface=RSABackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_sign_with_invalid_hash(self, backend):
        private_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
        )

        with pytest.raises(TypeError):
            builder.sign(private_key, object(), backend)

    @pytest.mark.requires_backend_interface(interface=DSABackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_sign_dsa_key(self, backend):
        private_key = DSA_KEY_2048.private_key(backend)
        invalidity_date = x509.InvalidityDate(
            datetime.datetime(2002, 1, 1, 0, 0)
        )
        ian = x509.IssuerAlternativeName([
            x509.UniformResourceIdentifier(u"https://cryptography.io"),
        ])
        revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
            2
        ).revocation_date(
            datetime.datetime(2012, 1, 1, 1, 1)
        ).add_extension(
            invalidity_date, False
        ).build(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_revoked_certificate(
            revoked_cert0
        ).add_extension(
            ian, False
        )

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert crl.extensions.get_extension_for_class(
            x509.IssuerAlternativeName
        ).value == ian
        assert crl[0].serial_number == revoked_cert0.serial_number
        assert crl[0].revocation_date == revoked_cert0.revocation_date
        assert len(crl[0].extensions) == 1
        ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
        assert ext.critical is False
        assert ext.value == invalidity_date

    @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_sign_ec_key(self, backend):
        _skip_curve_unsupported(backend, ec.SECP256R1())
        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
        invalidity_date = x509.InvalidityDate(
            datetime.datetime(2002, 1, 1, 0, 0)
        )
        ian = x509.IssuerAlternativeName([
            x509.UniformResourceIdentifier(u"https://cryptography.io"),
        ])
        revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
            2
        ).revocation_date(
            datetime.datetime(2012, 1, 1, 1, 1)
        ).add_extension(
            invalidity_date, False
        ).build(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_revoked_certificate(
            revoked_cert0
        ).add_extension(
            ian, False
        )

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert crl.extensions.get_extension_for_class(
            x509.IssuerAlternativeName
        ).value == ian
        assert crl[0].serial_number == revoked_cert0.serial_number
        assert crl[0].revocation_date == revoked_cert0.revocation_date
        assert len(crl[0].extensions) == 1
        ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
        assert ext.critical is False
        assert ext.value == invalidity_date

    @pytest.mark.requires_backend_interface(interface=DSABackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_dsa_key_sign_md5(self, backend):
        private_key = DSA_KEY_2048.private_key(backend)
        last_time = datetime.datetime(2012, 1, 16, 22, 43)
        next_time = datetime.datetime(2022, 1, 17, 6, 43)
        builder = x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([
                x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
            ])
        ).last_update(last_time).next_update(next_time)

        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.MD5(), backend)

    @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_ec_key_sign_md5(self, backend):
        _skip_curve_unsupported(backend, ec.SECP256R1())
        private_key = EC_KEY_SECP256R1.private_key(backend)
        last_time = datetime.datetime(2012, 1, 16, 22, 43)
        next_time = datetime.datetime(2022, 1, 17, 6, 43)
        builder = x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([
                x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA")
            ])
        ).last_update(last_time).next_update(next_time)

        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.MD5(), backend)

    @pytest.mark.requires_backend_interface(interface=RSABackend)
    @pytest.mark.requires_backend_interface(interface=X509Backend)
    def test_sign_with_revoked_certificates(self, backend):
        private_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)
        invalidity_date = x509.InvalidityDate(
            datetime.datetime(2002, 1, 1, 0, 0)
        )
        revoked_cert0 = x509.RevokedCertificateBuilder().serial_number(
            38
        ).revocation_date(
            datetime.datetime(2011, 1, 1, 1, 1)
        ).build(backend)
        revoked_cert1 = x509.RevokedCertificateBuilder().serial_number(
            2
        ).revocation_date(
            datetime.datetime(2012, 1, 1, 1, 1)
        ).add_extension(
            invalidity_date, False
        ).build(backend)
        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_revoked_certificate(
            revoked_cert0
        ).add_revoked_certificate(
            revoked_cert1
        )

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert len(crl) == 2
        assert crl.last_update == last_update
        assert crl.next_update == next_update
        assert crl[0].serial_number == revoked_cert0.serial_number
        assert crl[0].revocation_date == revoked_cert0.revocation_date
        assert len(crl[0].extensions) == 0
        assert crl[1].serial_number == revoked_cert1.serial_number
        assert crl[1].revocation_date == revoked_cert1.revocation_date
        assert len(crl[1].extensions) == 1
        ext = crl[1].extensions.get_extension_for_class(x509.InvalidityDate)
        assert ext.critical is False
        assert ext.value == invalidity_date
Exemplo n.º 19
0
class TestCertificateRevocationListBuilder:
    def test_issuer_name_invalid(self):
        builder = x509.CertificateRevocationListBuilder()
        with pytest.raises(TypeError):
            builder.issuer_name("notanx509name")  # type:ignore[arg-type]

    def test_set_issuer_name_twice(self):
        builder = x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]))
        with pytest.raises(ValueError):
            builder.issuer_name(
                x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]))

    def test_aware_last_update(self, backend):
        last_time = datetime.datetime(2012, 1, 16, 22, 43)
        tz = pytz.timezone("US/Pacific")
        last_time = tz.localize(last_time)
        utc_last = datetime.datetime(2012, 1, 17, 6, 43)
        next_time = datetime.datetime(2022, 1, 17, 6, 43)
        private_key = RSA_KEY_2048.private_key(backend)
        builder = (x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([
                x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA")
            ])).last_update(last_time).next_update(next_time))

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert crl.last_update == utc_last

    def test_last_update_invalid(self):
        builder = x509.CertificateRevocationListBuilder()
        with pytest.raises(TypeError):
            builder.last_update("notadatetime")  # type:ignore[arg-type]

    def test_last_update_before_1950(self):
        builder = x509.CertificateRevocationListBuilder()
        with pytest.raises(ValueError):
            builder.last_update(datetime.datetime(1940, 8, 10))

    def test_set_last_update_twice(self):
        builder = x509.CertificateRevocationListBuilder().last_update(
            datetime.datetime(2002, 1, 1, 12, 1))
        with pytest.raises(ValueError):
            builder.last_update(datetime.datetime(2002, 1, 1, 12, 1))

    def test_aware_next_update(self, backend):
        next_time = datetime.datetime(2022, 1, 16, 22, 43)
        tz = pytz.timezone("US/Pacific")
        next_time = tz.localize(next_time)
        utc_next = datetime.datetime(2022, 1, 17, 6, 43)
        last_time = datetime.datetime(2012, 1, 17, 6, 43)
        private_key = RSA_KEY_2048.private_key(backend)
        builder = (x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([
                x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA")
            ])).last_update(last_time).next_update(next_time))

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert crl.next_update == utc_next

    def test_next_update_invalid(self):
        builder = x509.CertificateRevocationListBuilder()
        with pytest.raises(TypeError):
            builder.next_update("notadatetime")  # type:ignore[arg-type]

    def test_next_update_before_1950(self):
        builder = x509.CertificateRevocationListBuilder()
        with pytest.raises(ValueError):
            builder.next_update(datetime.datetime(1940, 8, 10))

    def test_set_next_update_twice(self):
        builder = x509.CertificateRevocationListBuilder().next_update(
            datetime.datetime(2002, 1, 1, 12, 1))
        with pytest.raises(ValueError):
            builder.next_update(datetime.datetime(2002, 1, 1, 12, 1))

    def test_last_update_after_next_update(self):
        builder = x509.CertificateRevocationListBuilder()

        builder = builder.next_update(datetime.datetime(2002, 1, 1, 12, 1))
        with pytest.raises(ValueError):
            builder.last_update(datetime.datetime(2003, 1, 1, 12, 1))

    def test_next_update_after_last_update(self):
        builder = x509.CertificateRevocationListBuilder()

        builder = builder.last_update(datetime.datetime(2002, 1, 1, 12, 1))
        with pytest.raises(ValueError):
            builder.next_update(datetime.datetime(2001, 1, 1, 12, 1))

    def test_add_extension_checks_for_duplicates(self):
        builder = x509.CertificateRevocationListBuilder().add_extension(
            x509.CRLNumber(1), False)

        with pytest.raises(ValueError):
            builder.add_extension(x509.CRLNumber(2), False)

    def test_add_invalid_extension(self):
        builder = x509.CertificateRevocationListBuilder()

        with pytest.raises(TypeError):
            builder.add_extension(object(), False)  # type:ignore[arg-type]

    def test_add_invalid_revoked_certificate(self):
        builder = x509.CertificateRevocationListBuilder()

        with pytest.raises(TypeError):
            builder.add_revoked_certificate(object())  # type:ignore[arg-type]

    def test_no_issuer_name(self, backend):
        private_key = RSA_KEY_2048.private_key(backend)
        builder = (x509.CertificateRevocationListBuilder().last_update(
            datetime.datetime(2002, 1, 1, 12, 1)).next_update(
                datetime.datetime(2030, 1, 1, 12, 1)))

        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.SHA256(), backend)

    def test_no_last_update(self, backend):
        private_key = RSA_KEY_2048.private_key(backend)
        builder = (x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")
                       ])).next_update(datetime.datetime(2030, 1, 1, 12, 1)))

        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.SHA256(), backend)

    def test_no_next_update(self, backend):
        private_key = RSA_KEY_2048.private_key(backend)
        builder = (x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")
                       ])).last_update(datetime.datetime(2030, 1, 1, 12, 1)))

        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.SHA256(), backend)

    def test_sign_empty_list(self, backend):
        private_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, "cryptography.io CA")
            ])).last_update(last_update).next_update(next_update))

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert len(crl) == 0
        assert crl.last_update == last_update
        assert crl.next_update == next_update

    @pytest.mark.parametrize(
        "extension",
        [
            x509.CRLNumber(13),
            x509.DeltaCRLIndicator(12345678901234567890),
            x509.AuthorityKeyIdentifier(
                b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08"
                b"\xcbY",
                None,
                None,
            ),
            x509.AuthorityInformationAccess([
                x509.AccessDescription(
                    AuthorityInformationAccessOID.CA_ISSUERS,
                    x509.DNSName("cryptography.io"),
                )
            ]),
            x509.IssuerAlternativeName(
                [x509.UniformResourceIdentifier("https://cryptography.io")]),
        ],
    )
    def test_sign_extensions(self, backend, extension):
        private_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, "cryptography.io CA")
            ])).last_update(last_update).next_update(
                next_update).add_extension(extension, False))

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert len(crl) == 0
        assert len(crl.extensions) == 1
        ext = crl.extensions.get_extension_for_class(type(extension))
        assert ext.critical is False
        assert ext.value == extension

    def test_sign_multiple_extensions_critical(self, backend):
        private_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)
        ian = x509.IssuerAlternativeName(
            [x509.UniformResourceIdentifier("https://cryptography.io")])
        crl_number = x509.CRLNumber(13)
        builder = (x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([
                x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA")
            ])).last_update(last_update).next_update(
                next_update).add_extension(crl_number,
                                           False).add_extension(ian, True))

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert len(crl) == 0
        assert len(crl.extensions) == 2
        ext1 = crl.extensions.get_extension_for_class(x509.CRLNumber)
        assert ext1.critical is False
        assert ext1.value == crl_number
        ext2 = crl.extensions.get_extension_for_class(
            x509.IssuerAlternativeName)
        assert ext2.critical is True
        assert ext2.value == ian

    def test_freshestcrl_extension(self, backend):
        private_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)
        freshest = x509.FreshestCRL([
            x509.DistributionPoint(
                [x509.UniformResourceIdentifier("http://d.om/delta")],
                None,
                None,
                None,
            )
        ])
        builder = (x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([
                x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA")
            ])).last_update(last_update).next_update(
                next_update).add_extension(freshest, False))

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert len(crl) == 0
        assert len(crl.extensions) == 1
        ext1 = crl.extensions.get_extension_for_class(x509.FreshestCRL)
        assert ext1.critical is False
        assert isinstance(ext1.value, x509.FreshestCRL)
        assert isinstance(ext1.value[0], x509.DistributionPoint)
        assert ext1.value[0].full_name is not None
        uri = ext1.value[0].full_name[0]
        assert isinstance(uri, x509.UniformResourceIdentifier)
        assert uri.value == "http://d.om/delta"

    def test_add_unsupported_extension(self, backend):
        private_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, "cryptography.io CA")
            ])).last_update(last_update).next_update(
                next_update).add_extension(DummyExtension(), False))
        with pytest.raises(NotImplementedError):
            builder.sign(private_key, hashes.SHA256(), backend)

    def test_add_unsupported_entry_extension(self, backend):
        private_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, "cryptography.io CA")
            ])).last_update(last_update).next_update(
                next_update).add_revoked_certificate(
                    x509.RevokedCertificateBuilder().serial_number(
                        1234).revocation_date(
                            datetime.datetime.utcnow()).add_extension(
                                DummyExtension(), critical=False).build()))
        with pytest.raises(NotImplementedError):
            builder.sign(private_key, hashes.SHA256(), backend)

    def test_sign_rsa_key_too_small(self, backend):
        private_key = RSA_KEY_512.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, "cryptography.io CA")
            ])).last_update(last_update).next_update(next_update))

        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.SHA512(), backend)

    def test_sign_with_invalid_hash(self, backend):
        private_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, "cryptography.io CA")
            ])).last_update(last_update).next_update(next_update))

        with pytest.raises(TypeError):
            builder.sign(
                private_key,
                object(),
                backend  # type: ignore[arg-type]
            )

    @pytest.mark.supported(
        only_if=lambda backend: backend.ed25519_supported(),
        skip_message="Requires OpenSSL with Ed25519 support",
    )
    def test_sign_with_invalid_hash_ed25519(self, backend):
        private_key = ed25519.Ed25519PrivateKey.generate()
        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, "cryptography.io CA")
            ])).last_update(last_update).next_update(next_update))

        with pytest.raises(TypeError):
            builder.sign(
                private_key,
                object(),  # type:ignore[arg-type]
                backend,
            )
        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.SHA256(), backend)

    @pytest.mark.supported(
        only_if=lambda backend: backend.ed448_supported(),
        skip_message="Requires OpenSSL with Ed448 support",
    )
    def test_sign_with_invalid_hash_ed448(self, backend):
        private_key = ed448.Ed448PrivateKey.generate()
        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, "cryptography.io CA")
            ])).last_update(last_update).next_update(next_update))

        with pytest.raises(TypeError):
            builder.sign(
                private_key,
                object(),  # type:ignore[arg-type]
                backend,
            )
        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.SHA256(), backend)

    def test_sign_dsa_key(self, backend):
        private_key = DSA_KEY_2048.private_key(backend)
        invalidity_date = x509.InvalidityDate(
            datetime.datetime(2002, 1, 1, 0, 0))
        ian = x509.IssuerAlternativeName(
            [x509.UniformResourceIdentifier("https://cryptography.io")])
        revoked_cert0 = (
            x509.RevokedCertificateBuilder().serial_number(2).revocation_date(
                datetime.datetime(2012, 1, 1, 1,
                                  1)).add_extension(invalidity_date,
                                                    False).build(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, "cryptography.io CA")
            ])).last_update(last_update).next_update(next_update).
                   add_revoked_certificate(revoked_cert0).add_extension(
                       ian, False))

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert (crl.extensions.get_extension_for_class(
            x509.IssuerAlternativeName).value == ian)
        assert crl[0].serial_number == revoked_cert0.serial_number
        assert crl[0].revocation_date == revoked_cert0.revocation_date
        assert len(crl[0].extensions) == 1
        ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
        assert ext.critical is False
        assert ext.value == invalidity_date

    def test_sign_ec_key(self, backend):
        _skip_curve_unsupported(backend, ec.SECP256R1())
        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
        invalidity_date = x509.InvalidityDate(
            datetime.datetime(2002, 1, 1, 0, 0))
        ian = x509.IssuerAlternativeName(
            [x509.UniformResourceIdentifier("https://cryptography.io")])
        revoked_cert0 = (
            x509.RevokedCertificateBuilder().serial_number(2).revocation_date(
                datetime.datetime(2012, 1, 1, 1,
                                  1)).add_extension(invalidity_date,
                                                    False).build(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, "cryptography.io CA")
            ])).last_update(last_update).next_update(next_update).
                   add_revoked_certificate(revoked_cert0).add_extension(
                       ian, False))

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert (crl.extensions.get_extension_for_class(
            x509.IssuerAlternativeName).value == ian)
        assert crl[0].serial_number == revoked_cert0.serial_number
        assert crl[0].revocation_date == revoked_cert0.revocation_date
        assert len(crl[0].extensions) == 1
        ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
        assert ext.critical is False
        assert ext.value == invalidity_date

    @pytest.mark.supported(
        only_if=lambda backend: backend.ed25519_supported(),
        skip_message="Requires OpenSSL with Ed25519 support",
    )
    def test_sign_ed25519_key(self, backend):
        private_key = ed25519.Ed25519PrivateKey.generate()
        invalidity_date = x509.InvalidityDate(
            datetime.datetime(2002, 1, 1, 0, 0))
        ian = x509.IssuerAlternativeName(
            [x509.UniformResourceIdentifier("https://cryptography.io")])
        revoked_cert0 = (
            x509.RevokedCertificateBuilder().serial_number(2).revocation_date(
                datetime.datetime(2012, 1, 1, 1,
                                  1)).add_extension(invalidity_date,
                                                    False).build(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, "cryptography.io CA")
            ])).last_update(last_update).next_update(next_update).
                   add_revoked_certificate(revoked_cert0).add_extension(
                       ian, False))

        crl = builder.sign(private_key, None, backend)
        assert crl.signature_hash_algorithm is None
        assert crl.signature_algorithm_oid == SignatureAlgorithmOID.ED25519
        assert (crl.extensions.get_extension_for_class(
            x509.IssuerAlternativeName).value == ian)
        assert crl[0].serial_number == revoked_cert0.serial_number
        assert crl[0].revocation_date == revoked_cert0.revocation_date
        assert len(crl[0].extensions) == 1
        ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
        assert ext.critical is False
        assert ext.value == invalidity_date

    @pytest.mark.supported(
        only_if=lambda backend: backend.ed448_supported(),
        skip_message="Requires OpenSSL with Ed448 support",
    )
    def test_sign_ed448_key(self, backend):
        private_key = ed448.Ed448PrivateKey.generate()
        invalidity_date = x509.InvalidityDate(
            datetime.datetime(2002, 1, 1, 0, 0))
        ian = x509.IssuerAlternativeName(
            [x509.UniformResourceIdentifier("https://cryptography.io")])
        revoked_cert0 = (
            x509.RevokedCertificateBuilder().serial_number(2).revocation_date(
                datetime.datetime(2012, 1, 1, 1,
                                  1)).add_extension(invalidity_date,
                                                    False).build(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, "cryptography.io CA")
            ])).last_update(last_update).next_update(next_update).
                   add_revoked_certificate(revoked_cert0).add_extension(
                       ian, False))

        crl = builder.sign(private_key, None, backend)
        assert crl.signature_hash_algorithm is None
        assert crl.signature_algorithm_oid == SignatureAlgorithmOID.ED448
        assert (crl.extensions.get_extension_for_class(
            x509.IssuerAlternativeName).value == ian)
        assert crl[0].serial_number == revoked_cert0.serial_number
        assert crl[0].revocation_date == revoked_cert0.revocation_date
        assert len(crl[0].extensions) == 1
        ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate)
        assert ext.critical is False
        assert ext.value == invalidity_date

    def test_dsa_key_sign_md5(self, backend):
        private_key = DSA_KEY_2048.private_key(backend)
        last_time = datetime.datetime(2012, 1, 16, 22, 43)
        next_time = datetime.datetime(2022, 1, 17, 6, 43)
        builder = (x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([
                x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA")
            ])).last_update(last_time).next_update(next_time))

        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.MD5(), backend)

    def test_ec_key_sign_md5(self, backend):
        _skip_curve_unsupported(backend, ec.SECP256R1())
        private_key = EC_KEY_SECP256R1.private_key(backend)
        last_time = datetime.datetime(2012, 1, 16, 22, 43)
        next_time = datetime.datetime(2022, 1, 17, 6, 43)
        builder = (x509.CertificateRevocationListBuilder().issuer_name(
            x509.Name([
                x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA")
            ])).last_update(last_time).next_update(next_time))

        with pytest.raises(ValueError):
            builder.sign(private_key, hashes.MD5(), backend)

    def test_sign_with_revoked_certificates(self, backend):
        private_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)
        invalidity_date = x509.InvalidityDate(
            datetime.datetime(2002, 1, 1, 0, 0))
        revoked_cert0 = (
            x509.RevokedCertificateBuilder().serial_number(38).revocation_date(
                datetime.datetime(2011, 1, 1, 1, 1)).build(backend))
        revoked_cert1 = (
            x509.RevokedCertificateBuilder().serial_number(2).revocation_date(
                datetime.datetime(2012, 1, 1, 1, 1)).add_extension(
                    invalidity_date, False).add_extension(
                        x509.CRLReason(x509.ReasonFlags.ca_compromise),
                        False).build(backend))
        ci = x509.CertificateIssuer([x509.DNSName("cryptography.io")])
        revoked_cert2 = (
            x509.RevokedCertificateBuilder().serial_number(40).revocation_date(
                datetime.datetime(2011, 1, 1, 1,
                                  1)).add_extension(ci, False).build(backend))
        builder = (
            x509.CertificateRevocationListBuilder().issuer_name(
                x509.Name([
                    x509.NameAttribute(NameOID.COMMON_NAME,
                                       "cryptography.io CA")
                ])).last_update(last_update).next_update(next_update).
            add_revoked_certificate(revoked_cert0).add_revoked_certificate(
                revoked_cert1).add_revoked_certificate(revoked_cert2))

        crl = builder.sign(private_key, hashes.SHA256(), backend)
        assert len(crl) == 3
        assert crl.last_update == last_update
        assert crl.next_update == next_update
        assert crl[0].serial_number == revoked_cert0.serial_number
        assert crl[0].revocation_date == revoked_cert0.revocation_date
        assert len(crl[0].extensions) == 0
        assert crl[1].serial_number == revoked_cert1.serial_number
        assert crl[1].revocation_date == revoked_cert1.revocation_date
        assert len(crl[1].extensions) == 2
        ext = crl[1].extensions.get_extension_for_class(x509.InvalidityDate)
        assert ext.critical is False
        assert ext.value == invalidity_date
        assert (crl[2].extensions.get_extension_for_class(
            x509.CertificateIssuer).value == ci)
Exemplo n.º 20
0
def parse_access_desc(desc):
    if desc['method'] == 'OCSP':
        method = x509.AuthorityInformationAccessOID.OCSP
    else:
        method = x509.AuthorityInformationAccessOID.CA_ISSUERS
    return x509.AccessDescription(method, parse_general_name(desc['value']))
Exemplo n.º 21
0
    def install_extensions(self, builder):
        """Add common extensions to Cert- or CSR builder.
        """

        # BasicConstraints, critical
        if self.ca:
            ext = x509.BasicConstraints(ca=True, path_length=self.path_length)
        else:
            ext = x509.BasicConstraints(ca=False, path_length=None)
        builder = builder.add_extension(ext, critical=True)

        # KeyUsage, critical
        ku_args = {k: k in self.usage for k in KU_FIELDS}
        if self.ca:
            ku_args['key_cert_sign'] = True
            ku_args['crl_sign'] = True
            ext = make_key_usage(**ku_args)
        else:
            ku_args['digital_signature'] = True
            ku_args['key_encipherment'] = True
            ext = make_key_usage(**ku_args)
        builder = builder.add_extension(ext, critical=True)

        # ExtendedKeyUsage, critical
        xku = [x for x in self.usage if x not in KU_FIELDS]
        xku_bad = [x for x in xku if x not in XKU_CODE_TO_OID]
        if xku_bad:
            die("Unknown usage keywords: %s", ','.join(xku_bad))
        if xku:
            xku_oids = [XKU_CODE_TO_OID[x] for x in xku]
            ext = x509.ExtendedKeyUsage(xku_oids)
            builder = builder.add_extension(ext, critical=True)

        # NameConstraints, critical
        if (self.exclude_subtrees or self.permit_subtrees) and self.ca:
            allow = self.load_gnames(self.permit_subtrees) or None
            disallow = self.load_gnames(self.exclude_subtrees) or None
            ext = x509.NameConstraints(allow, disallow)
            builder = builder.add_extension(ext, critical=True)

        # SubjectAlternativeName
        if self.san:
            ext = x509.SubjectAlternativeName(self.get_san_gnames())
            builder = builder.add_extension(ext, critical=False)

        # CRLDistributionPoints
        if self.crl_urls:
            full_names = self.get_crl_gnames()
            reasons = None
            crl_issuer = None
            point = x509.DistributionPoint(full_names, None, reasons, crl_issuer)
            ext = x509.CRLDistributionPoints([point])
            builder = builder.add_extension(ext, critical=False)

        # AuthorityInformationAccess
        if self.ocsp_urls or self.issuer_urls:
            oid = AuthorityInformationAccessOID.OCSP
            ocsp_list = [x509.AccessDescription(oid, gn) for gn in self.get_ocsp_gnames()]
            oid = AuthorityInformationAccessOID.CA_ISSUERS
            ca_list = [x509.AccessDescription(oid, gn) for gn in self.get_issuer_urls_gnames()]
            ext = x509.AuthorityInformationAccess(ocsp_list + ca_list)
            builder = builder.add_extension(ext, critical=False)

        # OCSPNoCheck
        if self.ocsp_nocheck:
            ext = x509.OCSPNoCheck()
            builder = builder.add_extension(ext, critical=False)

        # configured builder
        return builder
    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
Exemplo n.º 23
0
def create_ca_issuer(url):
    return x509.AccessDescription(
        x509.AuthorityInformationAccessOID.CA_ISSUERS,
        x509.UniformResourceIdentifier(url))
Exemplo n.º 24
0
def create_certificate(common_name,
                       not_valid_before,
                       not_valid_after,
                       issuer_common_name=None,
                       issuer_private_key=None,
                       crl_distribution_point=None,
                       authority_info_uri=None,
                       is_ca_certificate=False):

    private_key = rsa.generate_private_key(public_exponent=65537,
                                           key_size=2048,
                                           backend=default_backend())

    public_key = private_key.public_key()

    if not issuer_common_name:
        issuer_common_name = common_name

    if not issuer_private_key:
        issuer_private_key = private_key
        is_ca_certificate = True

    builder = x509.CertificateBuilder()
    builder = builder.subject_name(
        x509.Name(
            [x509.NameAttribute(NameOID.COMMON_NAME, unicode(common_name))]))

    builder = builder.issuer_name(
        x509.Name([
            x509.NameAttribute(NameOID.COMMON_NAME,
                               unicode(issuer_common_name))
        ]))

    builder = builder.not_valid_before(not_valid_before)
    builder = builder.not_valid_after(not_valid_after)
    builder = builder.serial_number(int(uuid.uuid4()))
    builder = builder.public_key(public_key)
    builder = builder.add_extension(x509.BasicConstraints(ca=is_ca_certificate,
                                                          path_length=None),
                                    critical=True)

    if crl_distribution_point:
        builder = builder.add_extension(x509.CRLDistributionPoints([
            x509.DistributionPoint(full_name=[
                x509.UniformResourceIdentifier(unicode(crl_distribution_point))
            ],
                                   relative_name=None,
                                   reasons=None,
                                   crl_issuer=None)
        ]),
                                        critical=True)

    if authority_info_uri:
        builder = builder.add_extension(
            x509.AuthorityInformationAccess([
                x509.AccessDescription(
                    access_method = \
                        x509.oid.AuthorityInformationAccessOID.CA_ISSUERS,
                    access_location = x509.UniformResourceIdentifier(
                        unicode(authority_info_uri))
                )
            ]),
            critical = True)

    certificate = builder.sign(private_key=issuer_private_key,
                               algorithm=hashes.SHA256(),
                               backend=default_backend())

    return private_key, certificate
    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_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
Exemplo n.º 27
0
    def signing_publickey(self,
                          user: User,
                          service: Service,
                          publickey: str,
                          valid_time=DAY * 365):
        _public_key = serialization.load_pem_public_key(
            publickey.encode(), backend=default_backend())

        ca_private_key, ca_cert = self._init_ca(service)
        ca_name = service.name
        username = str(user.username)
        config = service.pki_config  #TODO use this config
        domain = self._domain
        not_valid_before = datetime.datetime.utcnow()

        ca_public_key = ca_private_key.public_key()
        end_entity_cert_builder = x509.CertificateBuilder().\
            subject_name(x509.Name([
                x509.NameAttribute(NameOID.COMMON_NAME, config['cn'].format(username=username, domain=domain)),
                x509.NameAttribute(NameOID.EMAIL_ADDRESS, config['email'].format(username=username, domain=domain)),
            ])).\
            issuer_name(ca_cert.subject).\
            not_valid_before(not_valid_before).\
            not_valid_after(not_valid_before + valid_time).\
            serial_number(x509.random_serial_number()).\
            public_key(_public_key).\
            add_extension(
                x509.SubjectAlternativeName([
                    x509.DNSName(f'{username}'),
                    ]),
                critical=False).\
            add_extension(
                x509.BasicConstraints(ca=False, path_length=None),
                critical=True).\
            add_extension(
                x509.KeyUsage(digital_signature=True,
                              content_commitment=True,  # False
                              key_encipherment=True,
                              data_encipherment=False,
                              key_agreement=False,
                              key_cert_sign=False,
                              crl_sign=False,
                              encipher_only=False,
                              decipher_only=False),
                critical=True).\
            add_extension(
                x509.ExtendedKeyUsage([
                    ExtendedKeyUsageOID.CLIENT_AUTH,
                    ExtendedKeyUsageOID.SERVER_AUTH,
                ]), critical=False).\
            add_extension(
                x509.AuthorityKeyIdentifier.from_issuer_public_key(ca_public_key),
                critical=False).\
            add_extension(
                x509.SubjectKeyIdentifier.from_public_key(_public_key),
                critical=False).\
            add_extension(
                x509.CRLDistributionPoints([
                    x509.DistributionPoint(
                        full_name=[x509.UniformResourceIdentifier(f'http://crl.{self._domain}/{ca_name}.crl')],
                        relative_name=None,
                        crl_issuer=None,
                        reasons=None)
                    ]),
                critical=False).\
            add_extension(
                x509.AuthorityInformationAccess([
                    x509.AccessDescription(
                        access_method=x509.AuthorityInformationAccessOID.CA_ISSUERS,
                        access_location=x509.UniformResourceIdentifier(f'https://www.{self._domain}')),
                    x509.AccessDescription(
                        access_method=x509.AuthorityInformationAccessOID.OCSP,
                        access_location=x509.UniformResourceIdentifier(f'http://ocsp.{self._domain}/{ca_name}/'))
                    ]),
                critical=False)

        end_entity_cert = end_entity_cert_builder.\
            sign(
                private_key=ca_private_key,
                algorithm=hashes.SHA256(),
                backend=default_backend()
            )

        serial_number = f'{end_entity_cert.serial_number:X}'
        end_entity_cert_filename = self._pki_path / ca_name / \
            f'{safe_filename(username)}-{serial_number}.crt.pem'
        # save cert
        with end_entity_cert_filename.open("wb") as end_entity_cert_file:
            end_entity_cert_file.write(
                end_entity_cert.public_bytes(
                    encoding=serialization.Encoding.PEM))

        return Certificate(user.username, service.name, end_entity_cert)