コード例 #1
0
    def delta_crl_url(self, value):
        if value is None:
            self._freshest_crl = None
            return

        if self._delta_crl_indicator is not None:
            raise ValueError(
                _pretty_message('''
                delta_crl_url can not be set if delta_of is set
                '''))

        if not isinstance(value, str_cls):
            raise TypeError(
                _pretty_message(
                    '''
                delta_crl_url must be a unicode string, not %s
                ''', _type_name(value)))

        general_names = x509.GeneralNames([
            x509.GeneralName(name='uniform_resource_identifier', value=value)
        ])
        distribution_point_name = x509.DistributionPointName(
            name='full_name', value=general_names)
        distribution_point = x509.DistributionPoint(
            {'distribution_point': distribution_point_name})

        self._freshest_crl = x509.CRLDistributionPoints([distribution_point])
コード例 #2
0
ファイル: __init__.py プロジェクト: hisherear/csrbuilder
    def _set_subject_alt(self, name, values):
        """
        Replaces all existing asn1crypto.x509.GeneralName objects of the choice
        represented by the name parameter with the values

        :param name:
            A unicode string of the choice name of the x509.GeneralName object

        :param values:
            A list of unicode strings to use as the values for the new
            x509.GeneralName objects
        """

        if self._subject_alt_name is not None:
            filtered_general_names = []
            for general_name in self._subject_alt_name:
                if general_name.name != name:
                    filtered_general_names.append(general_name)
            self._subject_alt_name = x509.GeneralNames(filtered_general_names)
        else:
            self._subject_alt_name = x509.GeneralNames()

        if values is not None:
            for value in values:
                new_general_name = x509.GeneralName(name=name, value=value)
                self._subject_alt_name.append(new_general_name)

        if len(self._subject_alt_name) == 0:
            self._subject_alt_name = None
コード例 #3
0
    def issuer_certificate_url(self, value):
        if value is not None and not isinstance(value, str_cls):
            raise TypeError(
                _pretty_message(
                    '''
                issuer_certificate_url must be a unicode string, not %s
                ''', _type_name(value)))

        self._authority_information_access = x509.AuthorityInfoAccessSyntax([{
            'access_method':
            'ca_issuers',
            'access_location':
            x509.GeneralName(name='uniform_resource_identifier', value=value)
        }])
コード例 #4
0
    def url(self, value):
        if not isinstance(value, str_cls):
            raise TypeError(
                _pretty_message(
                    '''
                url must be a unicode string, not %s
                ''', _type_name(value)))

        if self._issuing_distribution_point is None:
            general_names = x509.GeneralNames([
                x509.GeneralName(name='uniform_resource_identifier',
                                 value=value)
            ])
            distribution_point_name = x509.DistributionPointName(
                name='full_name', value=general_names)
            self._issuing_distribution_point = crl.IssuingDistributionPoint(
                {'distribution_point': distribution_point_name})
        else:
            distribution_point_name = self._issuing_distribution_point[
                'distribution_point']
            general_names = distribution_point_name.chosen
            general_names[0] = x509.GeneralName(
                name='uniform_resource_identifier', value=value)
コード例 #5
0
def test_signing_cert_attr_malformed_issuer():
    from asn1crypto import x509
    cert = TESTING_CA.get_cert(CertLabel('signer1'))
    bogus_attr = as_signing_certificate_v2(cert)
    bogus_attr['certs'][0]['issuer_serial']['issuer'][0] = x509.GeneralName(
        {'dns_name': 'www.example.com'})
    output = _tamper_with_signed_attrs('signing_certificate_v2',
                                       resign=True,
                                       replace_with=bogus_attr)
    r = PdfFileReader(output)
    emb = r.embedded_signatures[0]
    digest = emb.compute_digest()
    with pytest.raises(SignatureValidationError,
                       match="Signing certificate attribute does not match "):
        validate_sig_integrity(emb.signer_info, emb.signer_cert, 'data',
                               digest)
コード例 #6
0
    def _csr_info(self, subject, public_key, sans):
        """
        Create the csr info portion of the certificate request"s ASN.1
        structure

        :param X509Name subject: subject to add to the certificate request
        :param asymmetric.PublicKey public_key: public key to use when creating
            the certificate request"s signature
        :param sans: collection of dns names to insert into a subjAltName
            extension for the certificate request
        :type sans: None or list(str) or tuple(str) or set(str)
        :return: the certificate request info structure
        :rtype: csr.CertificationRequestInfo
        """
        x509_subject = x509.Name.build(self._subject_as_dict(subject))
        extensions = [(u"basic_constraints",
                       x509.BasicConstraints({"ca": False}), False),
                      (u"key_usage",
                       x509.KeyUsage({"digital_signature",
                                      "key_encipherment"}), True),
                      (u"extended_key_usage",
                       x509.ExtKeyUsageSyntax([u"client_auth"]), False)]
        if sans:
            names = x509.GeneralNames()
            for san in sans:
                names.append(
                    x509.GeneralName("dns_name", _bytes_to_unicode(san)))
            extensions.append((u"subject_alt_name", names, False))

        return csr.CertificationRequestInfo({
            "version":
            u"v1",
            "subject":
            x509_subject,
            "subject_pk_info":
            public_key.asn1,
            "attributes": [{
                "type":
                u"extension_request",
                "values": [[self._create_extension(x) for x in extensions]]
            }]
        })
コード例 #7
0
ファイル: __init__.py プロジェクト: Arbitrage0/certbuilder
    def ocsp_url(self, value):
        if value is None:
            self._authority_information_access = None
            return

        if not isinstance(value, str_cls):
            raise TypeError(
                _pretty_message(
                    '''
                ocsp_url must be a unicode string, not %s
                ''', _type_name(value)))

        access_description = x509.AccessDescription({
            'access_method':
            'ocsp',
            'access_location':
            x509.GeneralName(name='uniform_resource_identifier', value=value)
        })

        self._authority_information_access = x509.AuthorityInfoAccessSyntax(
            [access_description])
コード例 #8
0
def test_signing_cert_attr_malformed_issuer():
    from asn1crypto import x509
    cert = TESTING_CA.get_cert(CertLabel('signer1'))
    bogus_attr = as_signing_certificate_v2(cert)
    bogus_attr['certs'][0]['issuer_serial']['issuer'][0] = x509.GeneralName(
        {'dns_name': 'www.example.com'}
    )
    output = _tamper_with_signed_attrs(
        'signing_certificate_v2', resign=True,
        replace_with=bogus_attr
    )
    r = PdfFileReader(output)
    emb = r.embedded_signatures[0]
    digest = emb.compute_digest()
    with pytest.raises(
            SignatureValidationError,
            match="Signing certificate attribute does not match ") as exc_info:
        validate_sig_integrity(
            emb.signer_info, emb.signer_cert, 'data', digest
        )
    assert exc_info.value.ades_status == AdESStatus.INDETERMINATE
    assert exc_info.value.ades_subindication \
           == AdESIndeterminate.NO_SIGNING_CERTIFICATE_FOUND
コード例 #9
0
ファイル: general.py プロジェクト: MatthiasValvekens/pyHanko
def as_signing_certificate_v2(cert: x509.Certificate, hash_algo='sha256') \
        -> tsp.SigningCertificateV2:
    """
    Format an ASN.1 ``SigningCertificateV2`` value, where the certificate
    is identified by the hash algorithm specified.

    :param cert:
        An X.509 certificate.
    :param hash_algo:
        Hash algorithm to use to digest the certificate.
        Default is SHA-256.
    :return:
        A :class:`tsp.SigningCertificateV2` object referring to the original
        certificate.
    """

    # see RFC 5035
    hash_spec = get_pyca_cryptography_hash(hash_algo)
    md = hashes.Hash(hash_spec)
    md.update(cert.dump())
    digest_value = md.finalize()
    return tsp.SigningCertificateV2({
        'certs': [
            tsp.ESSCertIDv2({
                'hash_algorithm': {
                    'algorithm': hash_algo
                },
                'cert_hash': digest_value,
                'issuer_serial': {
                    'issuer':
                    [x509.GeneralName({'directory_name': cert.issuer})],
                    'serial_number': cert['tbs_certificate']['serial_number']
                }
            })
        ]
    })
コード例 #10
0
ファイル: general.py プロジェクト: MatthiasValvekens/pyHanko
def as_signing_certificate(cert: x509.Certificate) -> tsp.SigningCertificate:
    """
    Format an ASN.1 ``SigningCertificate`` object, where the certificate
    is identified by its SHA-1 digest.

    :param cert:
        An X.509 certificate.
    :return:
        A :class:`tsp.SigningCertificate` object referring to the original
        certificate.
    """
    # see RFC 2634, § 5.4.1
    return tsp.SigningCertificate({
        'certs': [
            tsp.ESSCertID({
                'cert_hash': hashlib.sha1(cert.dump()).digest(),
                'issuer_serial': {
                    'issuer':
                    [x509.GeneralName({'directory_name': cert.issuer})],
                    'serial_number': cert['tbs_certificate']['serial_number']
                }
            })
        ]
    })
コード例 #11
0
ファイル: __init__.py プロジェクト: Arbitrage0/certbuilder
    def _make_crl_distribution_points(self, name, value):
        """
        Constructs an asn1crypto.x509.CRLDistributionPoints object

        :param name:
            A unicode string of the attribute name to use in exceptions

        :param value:
            Either a unicode string of a URL, or a 2-element tuple of a
            unicode string of a URL, plus an asn1crypto.x509.Certificate
            object that will be signing the CRL (for indirect CRLs).

        :return:
            None or an asn1crypto.x509.CRLDistributionPoints object
        """

        if value is None:
            return None

        is_tuple = isinstance(value, tuple)
        if not is_tuple and not isinstance(value, str_cls):
            raise TypeError(
                _pretty_message(
                    '''
                %s must be a unicode string or tuple of (unicode string,
                asn1crypto.x509.Certificate), not %s
                ''', name, _type_name(value)))

        issuer = None
        if is_tuple:
            if len(value) != 2:
                raise ValueError(
                    _pretty_message(
                        '''
                    %s must be a unicode string or 2-element tuple, not a
                    %s-element tuple
                    ''', name, len(value)))

            if not isinstance(value[0], str_cls) or not isinstance(
                    value[1], x509.Certificate):
                raise TypeError(
                    _pretty_message(
                        '''
                    %s must be a tuple of (unicode string,
                    ans1crypto.x509.Certificate), not (%s, %s)
                    ''', name, _type_name(value[0]), _type_name(value[1])))

            url = value[0]
            issuer = value[1].subject
        else:
            url = value

        general_names = x509.GeneralNames(
            [x509.GeneralName(name='uniform_resource_identifier', value=url)])
        distribution_point_name = x509.DistributionPointName(
            name='full_name', value=general_names)
        distribution_point = x509.DistributionPoint(
            {'distribution_point': distribution_point_name})
        if issuer:
            distribution_point['crl_issuer'] = x509.GeneralNames(
                [x509.GeneralName(name='directory_name', value=issuer)])

        return x509.CRLDistributionPoints([distribution_point])
コード例 #12
0
ファイル: timestamps.py プロジェクト: ooguz/pyHanko
    def request_tsa_response(self, req: tsp.TimeStampReq) -> tsp.TimeStampResp:
        # We pretend that certReq is always true in the request

        # TODO generalise my detached signature logic to include cases like this
        #  (see § 5.4 in RFC 5652)
        # TODO does the RFC
        status = tsp.PKIStatusInfo({'status': tsp.PKIStatus('granted')})
        message_imprint: tsp.MessageImprint = req['message_imprint']
        md_algorithm = message_imprint['hash_algorithm']['algorithm'].native
        digest_algorithm_obj = algos.DigestAlgorithm({
            'algorithm': md_algorithm
        })
        dt = self.fixed_dt or datetime.now(tz=tzlocal.get_localzone())
        tst_info = {
            'version': 'v1',
            # See http://oidref.com/1.3.6.1.4.1.4146.2.2
            # I don't really care too much, this is a testing device anyway
            'policy': tsp.ObjectIdentifier('1.3.6.1.4.1.4146.2.2'),
            'message_imprint': message_imprint,
            # should be sufficiently random (again, this is a testing class)
            'serial_number': get_nonce(),
            'gen_time': dt,
            'tsa': x509.GeneralName(
                name='directory_name', value=self.tsa_cert.subject
            )
        }
        try:
            tst_info['nonce'] = req['nonce']
        except KeyError:
            pass

        tst_info = tsp.TSTInfo(tst_info)
        tst_info_data = tst_info.dump()
        message_digest = getattr(hashlib, md_algorithm)(tst_info_data).digest()
        signed_attrs = cms.CMSAttributes([
            simple_cms_attribute('content_type', 'tst_info'),
            simple_cms_attribute(
                'signing_time', cms.Time({'utc_time': core.UTCTime(dt)})
            ),
            simple_cms_attribute(
                'signing_certificate',
                general.as_signing_certificate(self.tsa_cert)
            ),
            simple_cms_attribute('message_digest', message_digest),
        ])
        signature = asymmetric.rsa_pkcs1v15_sign(
            asymmetric.load_private_key(self.tsa_key),
            signed_attrs.dump(), md_algorithm
        )
        sig_info = cms.SignerInfo({
            'version': 'v1',
            'sid': cms.SignerIdentifier({
                'issuer_and_serial_number': cms.IssuerAndSerialNumber({
                    'issuer': self.tsa_cert.issuer,
                    'serial_number': self.tsa_cert.serial_number,
                })
            }),
            'digest_algorithm': digest_algorithm_obj,
            'signature_algorithm': algos.SignedDigestAlgorithm(
                {'algorithm': 'rsassa_pkcs1v15'}
            ),
            'signed_attrs': signed_attrs,
            'signature': signature
        })
        certs = set(self.certs_to_embed)
        certs.add(self.tsa_cert)
        signed_data = {
            # must use v3 to get access to the EncapsulatedContentInfo construct
            'version': 'v3',
            'digest_algorithms': cms.DigestAlgorithms((digest_algorithm_obj,)),
            'encap_content_info': cms.EncapsulatedContentInfo({
                'content_type': cms.ContentType('tst_info'),
                'content': cms.ParsableOctetString(tst_info_data)
            }),
            'certificates': certs,
            'signer_infos': [sig_info]
        }
        tst = cms.ContentInfo({
            'content_type': cms.ContentType('signed_data'),
            'content': cms.SignedData(signed_data)
        })
        return tsp.TimeStampResp({'status': status, 'time_stamp_token': tst})
コード例 #13
0
    def request_tsa_response(self, req: tsp.TimeStampReq) -> tsp.TimeStampResp:
        # We pretend that certReq is always true in the request

        status = tsp.PKIStatusInfo({'status': tsp.PKIStatus('granted')})
        message_imprint: tsp.MessageImprint = req['message_imprint']
        md_algorithm = self.md_algorithm
        digest_algorithm_obj = algos.DigestAlgorithm({
            'algorithm': md_algorithm
        })
        dt = self.fixed_dt or datetime.now(tz=tzlocal.get_localzone())
        tst_info = {
            'version': 'v1',
            'policy': self.policy,
            'message_imprint': message_imprint,
            'serial_number': get_nonce(),
            'gen_time': dt,
            'tsa': x509.GeneralName(
                name='directory_name', value=self.tsa_cert.subject
            )
        }
        try:
            tst_info['nonce'] = req['nonce']
        except KeyError:
            pass

        tst_info = tsp.TSTInfo(tst_info)
        tst_info_data = tst_info.dump()
        message_digest = getattr(hashlib, md_algorithm)(tst_info_data).digest()
        signing_cert_id = tsp.ESSCertID({
            'cert_hash': hashlib.sha1(self.tsa_cert.dump()).digest()
        })
        signed_attrs = cms.CMSAttributes([
            simple_cms_attribute('content_type', 'tst_info'),
            simple_cms_attribute(
                'signing_time', cms.Time({'utc_time': core.UTCTime(dt)})
            ),
            simple_cms_attribute(
                'signing_certificate',
                tsp.SigningCertificate({'certs': [signing_cert_id]})
            ),
            simple_cms_attribute('message_digest', message_digest),
        ])
        signature = generic_sign(
            self.tsa_key, signed_attrs.dump(), self.signature_algo
        )
        sig_info = cms.SignerInfo({
            'version': 'v1',
            'sid': cms.SignerIdentifier({
                'issuer_and_serial_number': cms.IssuerAndSerialNumber({
                    'issuer': self.tsa_cert.issuer,
                    'serial_number': self.tsa_cert.serial_number,
                })
            }),
            'digest_algorithm': digest_algorithm_obj,
            'signature_algorithm': self.signature_algo,
            'signed_attrs': signed_attrs,
            'signature': signature
        })
        certs = set(self.certs_to_embed)
        certs.add(self.tsa_cert)
        signed_data = {
            # must use v3 to get access to the EncapsulatedContentInfo construct
            'version': 'v3',
            'digest_algorithms': cms.DigestAlgorithms((digest_algorithm_obj,)),
            'encap_content_info': cms.EncapsulatedContentInfo({
                'content_type': cms.ContentType('tst_info'),
                'content': cms.ParsableOctetString(tst_info_data)
            }),
            'certificates': certs,
            'signer_infos': [sig_info]
        }
        tst = cms.ContentInfo({
            'content_type': cms.ContentType('signed_data'),
            'content': cms.SignedData(signed_data)
        })
        return tsp.TimeStampResp({'status': status, 'time_stamp_token': tst})
コード例 #14
0
 def _wrap(x):
     return x509.GeneralName({'uniform_resource_identifier': x})
コード例 #15
0
    def build(self, responder_private_key=None, responder_certificate=None):

        if self._response_status != 'successful':
            return ocsp.OCSPResponse(
                {'response_status': self._response_status})

        is_oscrypto = isinstance(responder_private_key, asymmetric.PrivateKey)
        if not isinstance(responder_private_key,
                          keys.PrivateKeyInfo) and not is_oscrypto:
            raise TypeError(
                _pretty_message(
                    '''
                responder_private_key must be an instance of
                asn1crypto.keys.PrivateKeyInfo or
                oscrypto.asymmetric.PrivateKey, not %s
                ''', _type_name(responder_private_key)))

        cert_is_oscrypto = isinstance(responder_certificate,
                                      asymmetric.Certificate)
        if not isinstance(responder_certificate,
                          x509.Certificate) and not cert_is_oscrypto:
            raise TypeError(
                _pretty_message(
                    '''
                responder_certificate must be an instance of
                asn1crypto.x509.Certificate or
                oscrypto.asymmetric.Certificate, not %s
                ''', _type_name(responder_certificate)))

        if cert_is_oscrypto:
            responder_certificate = responder_certificate.asn1

        if self._certificate is None:
            raise ValueError(
                _pretty_message('''
                certificate must be set if the response_status is
                "successful"
                '''))
        if self._certificate_status is None:
            raise ValueError(
                _pretty_message('''
                certificate_status must be set if the response_status is
                "successful"
                '''))

        def _make_extension(name, value):
            return {'extn_id': name, 'critical': False, 'extn_value': value}

        response_data_extensions = []
        single_response_extensions = []

        for name, value in self._response_data_extensions.items():
            response_data_extensions.append(_make_extension(name, value))
        if self._nonce:
            response_data_extensions.append(
                _make_extension('nonce', self._nonce))

        if not response_data_extensions:
            response_data_extensions = None

        for name, value in self._single_response_extensions.items():
            single_response_extensions.append(_make_extension(name, value))

        if self._certificate_issuer:
            single_response_extensions.append(
                _make_extension('certificate_issuer', [
                    x509.GeneralName(name='directory_name',
                                     value=self._certificate_issuer.subject)
                ]))

        if not single_response_extensions:
            single_response_extensions = None

        responder_key_hash = getattr(responder_certificate.public_key,
                                     self._key_hash_algo)

        if self._certificate_status == 'good':
            cert_status = ocsp.CertStatus(name='good')
        elif self._certificate_status == 'unknown':
            cert_status = ocsp.CertStatus(name='unknown')
        else:
            status = self._certificate_status
            reason = status if status != 'revoked' else 'unspecified'
            revoked_info = ocsp.RevokedInfo({
                'revocation_time':
                datetime.now(timezone.utc),
                'revocation_reason':
                crl.CRLReason(0)
            })
            cert_status = ocsp.CertStatus(name='revoked', value=revoked_info)

        issuer = self._certificate_issuer

        produced_at = datetime.now(timezone.utc)

        if self._this_update is None:
            self._this_update = produced_at

        if self._next_update is None:
            self._next_update = self._this_update + timedelta(days=7)

        response_data = ocsp.ResponseData({
            'responder_id':
            ocsp.ResponderId(name='by_name', value=self._certificate.subject),
            'produced_at':
            produced_at,
            'responses': [{
                'cert_id': {
                    'hash_algorithm': {
                        'algorithm': self._key_hash_algo
                    },
                    'issuer_name_hash':
                    getattr(self.issuer.subject, self._key_hash_algo),
                    'issuer_key_hash':
                    getattr(self.issuer.public_key, self._key_hash_algo),
                    'serial_number':
                    self._certificate.serial_number,
                },
                'cert_status': cert_status,
                'this_update': self._this_update,
                'next_update': self._next_update,
                'single_extensions': single_response_extensions
            }],
            'response_extensions':
            response_data_extensions
        })

        signature_algo = responder_private_key.algorithm
        if signature_algo == 'ec':
            signature_algo = 'ecdsa'

        signature_algorithm_id = '%s_%s' % (self._hash_algo, signature_algo)

        if responder_private_key.algorithm == 'rsa':
            sign_func = asymmetric.rsa_pkcs1v15_sign
        elif responder_private_key.algorithm == 'dsa':
            sign_func = asymmetric.dsa_sign
        elif responder_private_key.algorithm == 'ec':
            sign_func = asymmetric.ecdsa_sign

        if not is_oscrypto:
            responder_private_key = asymmetric.load_private_key(
                responder_private_key)
        signature_bytes = sign_func(responder_private_key,
                                    response_data.dump(), self._hash_algo)

        certs = [responder_certificate]
        if self._certificate_issuer:
            certs = [responder_certificate]

        return ocsp.OCSPResponse({
            'response_status': self._response_status,
            'response_bytes': {
                'response_type': 'basic_ocsp_response',
                'response': {
                    'tbs_response_data': response_data,
                    'signature_algorithm': {
                        'algorithm': signature_algorithm_id
                    },
                    'signature': signature_bytes,
                    'certs': certs
                }
            }
        })
コード例 #16
0
ファイル: badecparams.py プロジェクト: tmnc/badecparams
def write_tls_certificate(
    ca_cert: x509.Certificate,
    ca_cert_orig: x509.Certificate,
    signing_key: ecdsa.keys.SigningKey,
    name: str,
    subject: x509.Name,
    subject_alt_names: Sequence[str],
) -> None:
    private_key, public_key = generate_private_key("rsa:4096")
    signed_digest_algorithm = x509.SignedDigestAlgorithm(
        {"algorithm": "sha256_ecdsa"})

    certificate = x509.Certificate({
        "tbs_certificate": {
            "version":
            "v3",
            "serial_number":
            random_serial_number(),
            "signature":
            signed_digest_algorithm,
            "issuer":
            ca_cert_orig.subject,
            "validity": {
                "not_before":
                x509.UTCTime(
                    datetime.datetime(2018, 1, 1,
                                      tzinfo=datetime.timezone.utc)),
                "not_after":
                x509.UTCTime(
                    datetime.datetime(2021, 1, 1,
                                      tzinfo=datetime.timezone.utc)),
            },
            "subject":
            subject,
            "subject_public_key_info":
            public_key,
            "extensions": [
                {
                    "extn_id": "basic_constraints",
                    "critical": True,
                    "extn_value": {
                        "ca": False
                    },
                },
                {
                    "extn_id":
                    "subject_alt_name",
                    "critical":
                    False,
                    "extn_value": [
                        x509.GeneralName({"dns_name": dns_name})
                        for dns_name in subject_alt_names
                    ],
                },
                {
                    "extn_id":
                    "certificate_policies",
                    "critical":
                    False,
                    "extn_value": [
                        {
                            "policy_identifier": "1.3.6.1.4.1.6449.1.2.1.5.1"
                        },
                    ],
                },
            ],
        },
        "signature_algorithm":
        signed_digest_algorithm,
    })

    sign_certificate(signing_key, certificate)

    with open(name + ".crt", "wb") as f:
        write_pem(f, certificate, "CERTIFICATE")
        write_pem(f, ca_cert_orig, "CERTIFICATE")
        write_pem(f, ca_cert, "CERTIFICATE")

    with open(name + ".key", "wb") as f:
        write_pem(f, private_key, "PRIVATE KEY")
        write_pem(f, certificate, "CERTIFICATE")
        write_pem(f, ca_cert_orig, "CERTIFICATE")
        write_pem(f, ca_cert, "CERTIFICATE")
コード例 #17
0
    def build(self, issuer_private_key):
        """
        Validates the certificate list information, constructs the ASN.1
        structure and then signs it

        :param issuer_private_key:
            An asn1crypto.keys.PrivateKeyInfo or oscrypto.asymmetric.PrivateKey
            object for the private key of the CRL issuer

        :return:
            An asn1crypto.crl.CertificateList object of the newly signed CRL
        """

        is_oscrypto = isinstance(issuer_private_key, asymmetric.PrivateKey)
        if not isinstance(issuer_private_key,
                          keys.PrivateKeyInfo) and not is_oscrypto:
            raise TypeError(
                _pretty_message(
                    '''
                issuer_private_key must be an instance of
                asn1crypto.keys.PrivateKeyInfo or
                oscrypto.asymmetric.PrivateKey, not %s
                ''', _type_name(issuer_private_key)))

        if self._this_update is None:
            self._this_update = datetime.now(timezone.utc)

        if self._next_update is None:
            self._next_update = self._this_update + timedelta(days=7)

        signature_algo = issuer_private_key.algorithm
        if signature_algo == 'ec':
            signature_algo = 'ecdsa'

        signature_algorithm_id = '%s_%s' % (self._hash_algo, signature_algo)

        def _make_extension(name, value):
            return {
                'extn_id': name,
                'critical': self._determine_critical(name),
                'extn_value': value
            }

        extensions = []
        for name in sorted(self._special_extensions):
            value = getattr(self, '_%s' % name)
            if value is not None:
                extensions.append(_make_extension(name, value))

        for name in sorted(self._other_extensions.keys()):
            extensions.append(
                _make_extension(name, self._other_extensions[name]))

        # For an indirect CRL we need to set the first
        if self._certificate_issuer and len(self._revoked_certificates) > 0:
            self._revoked_certificates[0]['crl_entry_extensions'].append({
                'extn_id':
                'certificate_issuer',
                'critical':
                True,
                'extn_value':
                x509.GeneralNames([
                    x509.GeneralName(name='directory_name',
                                     value=self._certificate_issuer.subject)
                ])
            })

        tbs_cert_list = crl.TbsCertList({
            'version':
            'v3',
            'signature': {
                'algorithm': signature_algorithm_id
            },
            'issuer':
            self._issuer.subject,
            'this_update':
            x509.Time(name='utc_time', value=self._this_update),
            'next_update':
            x509.Time(name='utc_time', value=self._next_update),
            'revoked_certificates':
            crl.RevokedCertificates(self._revoked_certificates),
            'crl_extensions':
            extensions
        })

        if issuer_private_key.algorithm == 'rsa':
            sign_func = asymmetric.rsa_pkcs1v15_sign
        elif issuer_private_key.algorithm == 'dsa':
            sign_func = asymmetric.dsa_sign
        elif issuer_private_key.algorithm == 'ec':
            sign_func = asymmetric.ecdsa_sign

        if not is_oscrypto:
            issuer_private_key = asymmetric.load_private_key(
                issuer_private_key)
        signature = sign_func(issuer_private_key, tbs_cert_list.dump(),
                              self._hash_algo)

        return crl.CertificateList({
            'tbs_cert_list': tbs_cert_list,
            'signature_algorithm': {
                'algorithm': signature_algorithm_id
            },
            'signature': signature
        })
コード例 #18
0
    def request_tsa_response(self, req: tsp.TimeStampReq) \
            -> tsp.TimeStampResp:
        # We pretend that certReq is always true in the request

        # TODO generalise my detached signature logic to include cases like this
        #  (see § 5.4 in RFC 5652)
        # TODO does the RFC
        status = tsp.PKIStatusInfo({'status': tsp.PKIStatus('granted')})
        message_imprint: tsp.MessageImprint = req['message_imprint']
        md_algorithm = self.override_md
        if md_algorithm is None:
            md_algorithm = message_imprint['hash_algorithm'][
                'algorithm'].native
        digest_algorithm_obj = algos.DigestAlgorithm(
            {'algorithm': md_algorithm})
        dt = self.fixed_dt or datetime.now(tz=tzlocal.get_localzone())
        tst_info = {
            'version':
            'v1',
            # See http://oidref.com/1.3.6.1.4.1.4146.2.2
            # I don't really care too much, this is a testing device anyway
            'policy':
            tsp.ObjectIdentifier('1.3.6.1.4.1.4146.2.2'),
            'message_imprint':
            message_imprint,
            # should be sufficiently random (again, this is a testing class)
            'serial_number':
            get_nonce(),
            'gen_time':
            dt,
            'tsa':
            x509.GeneralName(name='directory_name',
                             value=self.tsa_cert.subject)
        }
        if req['nonce'].native is not None:
            tst_info['nonce'] = req['nonce']

        tst_info = tsp.TSTInfo(tst_info)
        tst_info_data = tst_info.dump()
        md_spec = get_pyca_cryptography_hash(md_algorithm)
        md = hashes.Hash(md_spec)
        md.update(tst_info_data)
        message_digest_value = md.finalize()
        signed_attrs = cms.CMSAttributes([
            simple_cms_attribute('content_type', 'tst_info'),
            simple_cms_attribute('signing_time',
                                 cms.Time({'utc_time': core.UTCTime(dt)})),
            simple_cms_attribute('signing_certificate',
                                 general.as_signing_certificate(
                                     self.tsa_cert)),
            simple_cms_attribute('message_digest', message_digest_value),
        ])
        priv_key = serialization.load_der_private_key(self.tsa_key.dump(),
                                                      password=None)
        if not isinstance(priv_key, RSAPrivateKey):
            raise NotImplementedError("Dummy timestamper is RSA-only.")
        signature = priv_key.sign(
            signed_attrs.dump(), PKCS1v15(),
            get_pyca_cryptography_hash(md_algorithm.upper()))
        sig_info = cms.SignerInfo({
            'version':
            'v1',
            'sid':
            cms.SignerIdentifier({
                'issuer_and_serial_number':
                cms.IssuerAndSerialNumber({
                    'issuer':
                    self.tsa_cert.issuer,
                    'serial_number':
                    self.tsa_cert.serial_number,
                })
            }),
            'digest_algorithm':
            digest_algorithm_obj,
            'signature_algorithm':
            algos.SignedDigestAlgorithm({'algorithm': 'rsassa_pkcs1v15'}),
            'signed_attrs':
            signed_attrs,
            'signature':
            signature
        })
        certs = set(self.certs_to_embed)
        certs.add(self.tsa_cert)
        signed_data = {
            # must use v3 to get access to the EncapsulatedContentInfo construct
            'version':
            'v3',
            'digest_algorithms':
            cms.DigestAlgorithms((digest_algorithm_obj, )),
            'encap_content_info':
            cms.EncapsulatedContentInfo({
                'content_type':
                cms.ContentType('tst_info'),
                'content':
                cms.ParsableOctetString(tst_info_data)
            }),
            'certificates':
            certs,
            'signer_infos': [sig_info]
        }
        tst = cms.ContentInfo({
            'content_type': cms.ContentType('signed_data'),
            'content': cms.SignedData(signed_data)
        })
        return tsp.TimeStampResp({'status': status, 'time_stamp_token': tst})
コード例 #19
0
    def build(self, responder_private_key=None, responder_certificate=None):
        """
        Validates the request information, constructs the ASN.1 structure and
        signs it.
        The responder_private_key and responder_certificate parameters are onlystr
        required if the response_status is "successful".
        :param responder_private_key:
            An asn1crypto.keys.PrivateKeyInfo or oscrypto.asymmetric.PrivateKey
            object for the private key to sign the response with
        :param responder_certificate:
            An asn1crypto.x509.Certificate or oscrypto.asymmetric.Certificate
            object of the certificate associated with the private key
        :return:
            An asn1crypto.ocsp.OCSPResponse object of the response
        """
        if self._response_status != 'successful':
            return ocsp.OCSPResponse({
                'response_status': self._response_status
            })

        is_oscrypto = isinstance(responder_private_key, asymmetric.PrivateKey)
        if not isinstance(responder_private_key, keys.PrivateKeyInfo) and not is_oscrypto:
            raise TypeError(_pretty_message(
                '''
                responder_private_key must be an instance ofthe c
                asn1crypto.keys.PrivateKeyInfo or
                oscrypto.asymmetric.PrivateKey, not %s
                ''',
                _type_name(responder_private_key)
            ))

        cert_is_oscrypto = isinstance(responder_certificate, asymmetric.Certificate)
        if not isinstance(responder_certificate, x509.Certificate) and not cert_is_oscrypto:
            raise TypeError(_pretty_message(
                '''
                responder_certificate must be an instance of
                asn1crypto.x509.Certificate or
                oscrypto.asymmetric.Certificate, not %s
                ''',
                _type_name(responder_certificate)
            ))

        if cert_is_oscrypto:
            responder_certificate = responder_certificate.asn1

        if self._certificate_status_list is None:
            raise ValueError(_pretty_message(
                '''
                certificate_status_list must be set if the response_status is
                "successful"
                '''
            ))

        def _make_extension(name, value):
            return {
                'extn_id': name,
                'critical': False,
                'extn_value': value
            }

        responses = []
        for serial, status in self._certificate_status_list:
            response_data_extensions = []
            single_response_extensions = []
            for name, value in self._response_data_extensions.items():
                response_data_extensions.append(_make_extension(name, value))
            if self._nonce:
                response_data_extensions.append(
                    _make_extension('nonce', self._nonce)
                )

            if not response_data_extensions:
                response_data_extensions = None

            for name, value in self._single_response_extensions.items():
                single_response_extensions.append(_make_extension(name, value))

            if self._certificate_issuer:
                single_response_extensions.append(
                    _make_extension(
                        'certificate_issuer',
                        [
                            x509.GeneralName(
                                name='directory_name',
                                value=self._certificate_issuer.subject
                            )
                        ]
                    )
                )

            if not single_response_extensions:
                single_response_extensions = None

            responder_key_hash = getattr(responder_certificate.public_key, self._key_hash_algo)

            if status == 'good':
                cert_status = ocsp.CertStatus(
                    name='good',
                    value=core.Null()
                )
            elif status == 'unknown':
                cert_status = ocsp.CertStatus(
                    name='unknown',
                    value=core.Null()
                )
            else:
                reason = status if status != 'revoked' else 'unspecified'
                cert_status = ocsp.CertStatus(
                    name='revoked',
                    value={
                        'revocation_time': self._revocation_date,
                        'revocation_reason': reason,
                    }
                )

            issuer = self._certificate_issuer if self._certificate_issuer else responder_certificate

            produced_at = datetime.now(timezone.utc).replace(microsecond=0)

            if self._this_update is None:
                self._this_update = produced_at

            if self._next_update is None:
                self._next_update = (self._this_update + timedelta(days=7)).replace(microsecond=0)

            response = {
                    'cert_id': {
                        'hash_algorithm': {
                            'algorithm': self._key_hash_algo
                        },
                        'issuer_name_hash': getattr(issuer.subject, self._key_hash_algo),
                        'issuer_key_hash': getattr(issuer.public_key, self._key_hash_algo),
                        'serial_number': serial,
                    },
                    'cert_status': cert_status,
                    'this_update': self._this_update,
                    'next_update': self._next_update,
                    'single_extensions': single_response_extensions
                }
            responses.append(response)

        response_data = ocsp.ResponseData({
            'responder_id': ocsp.ResponderId(name='by_key', value=responder_key_hash),
            'produced_at': produced_at,
            'responses': responses,
            'response_extensions': response_data_extensions
        })

        signature_algo = responder_private_key.algorithm
        if signature_algo == 'ec':
            signature_algo = 'ecdsa'

        signature_algorithm_id = '%s_%s' % (self._hash_algo, signature_algo)

        if responder_private_key.algorithm == 'rsa':
            sign_func = asymmetric.rsa_pkcs1v15_sign
        elif responder_private_key.algorithm == 'dsa':
            sign_func = asymmetric.dsa_sign
        elif responder_private_key.algorithm == 'ec':
            sign_func = asymmetric.ecdsa_sign

        if not is_oscrypto:
            responder_private_key = asymmetric.load_private_key(responder_private_key)
        signature_bytes = sign_func(responder_private_key, response_data.dump(), self._hash_algo)

        certs = None
        if self._certificate_issuer and getattr(self._certificate_issuer.public_key, self._key_hash_algo) != responder_key_hash:
            certs = [responder_certificate]

        return ocsp.OCSPResponse({
            'response_status': self._response_status,
            'response_bytes': {
                'response_type': 'basic_ocsp_response',
                'response': {
                    'tbs_response_data': response_data,
                    'signature_algorithm': {'algorithm': signature_algorithm_id},
                    'signature': signature_bytes,
                    'certs': certs,
                }
            }
        })
コード例 #20
0
ファイル: __init__.py プロジェクト: andrea-f/ocspbuilder
    def build(self,
              requestor_private_key=None,
              requestor_certificate=None,
              other_certificates=None):
        """
        Validates the request information, constructs the ASN.1 structure and
        then optionally signs it.

        The requestor_private_key, requestor_certificate and other_certificates
        params are all optional and only necessary if the request needs to be
        signed. Signing a request is uncommon for OCSP requests related to web
        TLS connections.

        :param requestor_private_key:
            An asn1crypto.keys.PrivateKeyInfo or oscrypto.asymmetric.PrivateKey
            object for the private key to sign the request with

        :param requestor_certificate:
            An asn1crypto.x509.Certificate or oscrypto.asymmetric.Certificate
            object of the certificate associated with the private key

        :param other_certificates:
            A list of asn1crypto.x509.Certificate or
            oscrypto.asymmetric.Certificate objects that may be useful for the
            OCSP server to verify the request signature. Intermediate
            certificates would be specified here.

        :return:
            An asn1crypto.ocsp.OCSPRequest object of the request
        """
        def _make_extension(name, value):
            return {'extn_id': name, 'critical': False, 'extn_value': value}

        tbs_request_extensions = []
        request_extensions = []
        has_nonce = False

        for name, value in self._tbs_request_extensions.items():
            if name == 'nonce':
                has_nonce = True
            tbs_request_extensions.append(_make_extension(name, value))
        if self._nonce and not has_nonce:
            tbs_request_extensions.append(
                _make_extension('nonce', util.rand_bytes(16)))

        if not tbs_request_extensions:
            tbs_request_extensions = None

        for name, value in self._request_extensions.items():
            request_extensions.append(_make_extension(name, value))

        if not request_extensions:
            request_extensions = None

        tbs_request = ocsp.TBSRequest({
            'request_list': [{
                'req_cert': {
                    'hash_algorithm': {
                        'algorithm': self._key_hash_algo
                    },
                    'issuer_name_hash':
                    getattr(cert.issuer, self._key_hash_algo),
                    'issuer_key_hash':
                    getattr(self._issuer.public_key, self._key_hash_algo),
                    'serial_number':
                    cert.serial_number,
                },
                'single_request_extensions': request_extensions
            } for cert in self._certificates],
            'request_extensions':
            tbs_request_extensions
        })
        signature = None

        if requestor_private_key or requestor_certificate or other_certificates:
            is_oscrypto = isinstance(requestor_private_key,
                                     asymmetric.PrivateKey)
            if not isinstance(requestor_private_key,
                              keys.PrivateKeyInfo) and not is_oscrypto:
                raise TypeError(
                    _pretty_message(
                        '''
                    requestor_private_key must be an instance of
                    asn1crypto.keys.PrivateKeyInfo or
                    oscrypto.asymmetric.PrivateKey, not %s
                    ''', _type_name(requestor_private_key)))

            cert_is_oscrypto = isinstance(requestor_certificate,
                                          asymmetric.Certificate)
            if not isinstance(requestor_certificate,
                              x509.Certificate) and not cert_is_oscrypto:
                raise TypeError(
                    _pretty_message(
                        '''
                    requestor_certificate must be an instance of
                    asn1crypto.x509.Certificate or
                    oscrypto.asymmetric.Certificate, not %s
                    ''', _type_name(requestor_certificate)))

            if other_certificates is not None and not isinstance(
                    other_certificates, list):
                raise TypeError(
                    _pretty_message(
                        '''
                    other_certificates must be a list of
                    asn1crypto.x509.Certificate or
                    oscrypto.asymmetric.Certificate objects, not %s
                    ''', _type_name(other_certificates)))

            if cert_is_oscrypto:
                requestor_certificate = requestor_certificate.asn1

            tbs_request['requestor_name'] = x509.GeneralName(
                name='directory_name', value=requestor_certificate.subject)

            certificates = [requestor_certificate]

            for other_certificate in other_certificates:
                other_cert_is_oscrypto = isinstance(other_certificate,
                                                    asymmetric.Certificate)
                if not isinstance(
                        other_certificate,
                        x509.Certificate) and not other_cert_is_oscrypto:
                    raise TypeError(
                        _pretty_message(
                            '''
                        other_certificate must be an instance of
                        asn1crypto.x509.Certificate or
                        oscrypto.asymmetric.Certificate, not %s
                        ''', _type_name(other_certificate)))
                if other_cert_is_oscrypto:
                    other_certificate = other_certificate.asn1
                certificates.append(other_certificate)

            signature_algo = requestor_private_key.algorithm
            if signature_algo == 'ec':
                signature_algo = 'ecdsa'

            signature_algorithm_id = '%s_%s' % (self._hash_algo,
                                                signature_algo)

            if requestor_private_key.algorithm == 'rsa':
                sign_func = asymmetric.rsa_pkcs1v15_sign
            elif requestor_private_key.algorithm == 'dsa':
                sign_func = asymmetric.dsa_sign
            elif requestor_private_key.algorithm == 'ec':
                sign_func = asymmetric.ecdsa_sign

            if not is_oscrypto:
                requestor_private_key = asymmetric.load_private_key(
                    requestor_private_key)
            signature_bytes = sign_func(requestor_private_key,
                                        tbs_request.dump(), self._hash_algo)

            signature = ocsp.Signature({
                'signature_algorithm': {
                    'algorithm': signature_algorithm_id
                },
                'signature': signature_bytes,
                'certs': certificates
            })

        return ocsp.OCSPRequest({
            'tbs_request': tbs_request,
            'optional_signature': signature
        })
コード例 #21
0
ファイル: __init__.py プロジェクト: andrea-f/ocspbuilder
    def build(self, responder_private_key=None, responder_certificate=None):
        """
        Validates the request information, constructs the ASN.1 structure and
        signs it.

        The responder_private_key and responder_certificate parameters are only
        required if the response_status is "successful".

        :param responder_private_key:
            An asn1crypto.keys.PrivateKeyInfo or oscrypto.asymmetric.PrivateKey
            object for the private key to sign the response with

        :param responder_certificate:
            An asn1crypto.x509.Certificate or oscrypto.asymmetric.Certificate
            object of the certificate associated with the private key

        :return:
            An asn1crypto.ocsp.OCSPResponse object of the response
        """

        if self._response_status != 'successful':
            return ocsp.OCSPResponse(
                {'response_status': self._response_status})

        is_oscrypto = isinstance(responder_private_key, asymmetric.PrivateKey)
        if not isinstance(responder_private_key,
                          keys.PrivateKeyInfo) and not is_oscrypto:
            raise TypeError(
                _pretty_message(
                    '''
                responder_private_key must be an instance of
                asn1crypto.keys.PrivateKeyInfo or
                oscrypto.asymmetric.PrivateKey, not %s
                ''', _type_name(responder_private_key)))

        cert_is_oscrypto = isinstance(responder_certificate,
                                      asymmetric.Certificate)
        if not isinstance(responder_certificate,
                          x509.Certificate) and not cert_is_oscrypto:
            raise TypeError(
                _pretty_message(
                    '''
                responder_certificate must be an instance of
                asn1crypto.x509.Certificate or
                oscrypto.asymmetric.Certificate, not %s
                ''', _type_name(responder_certificate)))

        if cert_is_oscrypto:
            responder_certificate = responder_certificate.asn1

        for cert in self._certificates:
            if not cert:
                raise ValueError(
                    _pretty_message('''
                    certificates must be set if the response_status is
                    "successful"
                    '''))
        for cert_status in self._certificates_status:
            if not cert_status:
                raise ValueError(
                    _pretty_message('''
                    certificates_status for all certificates must be set if the response_status is
                    "successful"
                    '''))

        def _make_extension(name, value):
            return {'extn_id': name, 'critical': False, 'extn_value': value}

        issuer = self._certificate_issuer if self._certificate_issuer else responder_certificate
        for x in range(len(self._certificates)):
            if issuer.subject != self._certificates[x].issuer:
                raise ValueError(
                    _pretty_message('''
                    responder_certificate does not appear to be the issuer for
                    the certificate. Perhaps set the .certificate_issuer attribute?
                    '''))
        total_issuers = len(self._certificates)
        response_data_extensions = []
        single_response_extensions = [[]] * total_issuers
        for x in range(len(self._certificates)):
            for name, value in self._response_data_extensions[x].items():
                response_data_extensions.append(_make_extension(name, value))
            for name, value in self._single_response_extensions[x].items():
                single_response_extensions[x].append(
                    _make_extension(name, value))
            # This means single_response_extensions can never be empty
            single_response_extensions[x].append(
                _make_extension('certificate_issuer', [
                    x509.GeneralName(name='directory_name',
                                     value=issuer.subject)
                ]))

        if self._nonce:
            response_data_extensions.append(
                _make_extension('nonce', self._nonce))

        if len(response_data_extensions) == 0:
            response_data_extensions = None

        responder_key_hash = getattr(responder_certificate.public_key,
                                     self._key_hash_algo)

        certs_status = []
        for x in range(len(self._certificates_status)):
            c_stat = self._certificates_status[x]
            if c_stat == 'good':
                cert_status = ocsp.CertStatus(name='good', value=core.Null())
            elif c_stat == 'unknown':
                cert_status = ocsp.CertStatus(name='unknown',
                                              value=core.Null())
            else:
                status = c_stat
                reason = status if status != 'revoked' else 'unspecified'
                cert_status = ocsp.CertStatus(name='revoked',
                                              value={
                                                  'revocation_time':
                                                  self._revocation_dates[x],
                                                  'revocation_reason':
                                                  reason,
                                              })
            certs_status.append(cert_status)

        produced_at = datetime.now(timezone.utc)
        # Construct the multiple certs response
        responses = []
        for x in range(len(self._certificates)):
            if self._this_updates[x] is None:
                self._this_updates[x] = produced_at
            if self._next_updates[x] is None:
                self._next_updates[x] = self._this_updates[x] + timedelta(
                    days=7)
            item = {
                'cert_id': {
                    'hash_algorithm': {
                        'algorithm': self._key_hash_algo
                    },
                    'issuer_name_hash':
                    getattr(self._certificates[x].issuer, self._key_hash_algo),
                    'issuer_key_hash':
                    getattr(issuer.public_key, self._key_hash_algo),
                    'serial_number':
                    self._certificates[x].serial_number
                },
                'cert_status': certs_status[x],
                'this_update': self._this_updates[x],
                'next_update': self._next_updates[x],
                'single_extensions': single_response_extensions[x]
            }
            responses.append(item)

        signature_algo = responder_private_key.algorithm
        if signature_algo == 'ec':
            signature_algo = 'ecdsa'

        signature_algorithm_id = '%s_%s' % (self._hash_algo, signature_algo)

        if responder_private_key.algorithm == 'rsa':
            sign_func = asymmetric.rsa_pkcs1v15_sign
        elif responder_private_key.algorithm == 'dsa':
            sign_func = asymmetric.dsa_sign
        elif responder_private_key.algorithm == 'ec':
            sign_func = asymmetric.ecdsa_sign

        if not is_oscrypto:
            responder_private_key = asymmetric.load_private_key(
                responder_private_key)
        # Set response_data for use in ocsp-service
        response_data = ocsp.ResponseData({
            'responder_id':
            ocsp.ResponderId(name='by_key', value=responder_key_hash),
            'produced_at':
            produced_at,
            'responses':
            responses,
            'response_extensions':
            response_data_extensions
        })
        signature_bytes = sign_func(responder_private_key,
                                    response_data.dump(), self._hash_algo)
        certs = None
        if self._certificate_issuer:
            certs = [responder_certificate]
        return ocsp.OCSPResponse({
            'response_status': self._response_status,
            'response_bytes': {
                'response_type': 'basic_ocsp_response',
                'response': {
                    'tbs_response_data': response_data,
                    'signature_algorithm': {
                        'algorithm': signature_algorithm_id
                    },
                    'signature': signature_bytes,
                    'certs': certs
                }
            }
        })
コード例 #22
0
    def build(self,
              requestor_private_key=None,
              requestor_certificate=None,
              other_certificates=None):
        def _make_extension(name, value):
            return {'extn_id': name, 'critical': False, 'extn_value': value}

        tbs_request_extensions = []
        request_extensions = []
        has_nonce = False

        for name, value in self._tbs_request_extensions.items():
            if name == 'nonce':
                has_nonce = True
            tbs_request_extensions.append(_make_extension(name, value))
        if self._nonce and not has_nonce:
            tbs_request_extensions.append(
                _make_extension('nonce', util.rand_bytes(16)))

        if not tbs_request_extensions:
            tbs_request_extensions = None

        for name, value in self._request_extensions.items():
            request_extensions.append(_make_extension(name, value))

        if not request_extensions:
            request_extensions = None

        tbs_request = ocsp.TBSRequest({
            'request_list': [{
                'req_cert': {
                    'hash_algorithm': {
                        'algorithm': self._key_hash_algo
                    },
                    'issuer_name_hash':
                    getattr(self._certificate.issuer, self._key_hash_algo),
                    'issuer_key_hash':
                    getattr(self._issuer.public_key, self._key_hash_algo),
                    'serial_number':
                    self._certificate.serial_number,
                },
                'single_request_extensions': request_extensions
            }],
            'request_extensions':
            tbs_request_extensions
        })
        signature = None

        if requestor_private_key or requestor_certificate or other_certificates:
            is_oscrypto = isinstance(requestor_private_key,
                                     asymmetric.PrivateKey)
            if not isinstance(requestor_private_key,
                              keys.PrivateKeyInfo) and not is_oscrypto:
                raise TypeError(
                    _pretty_message(
                        '''
                    requestor_private_key must be an instance of
                    asn1crypto.keys.PrivateKeyInfo or
                    oscrypto.asymmetric.PrivateKey, not %s
                    ''', _type_name(requestor_private_key)))

            cert_is_oscrypto = isinstance(requestor_certificate,
                                          asymmetric.Certificate)
            if not isinstance(requestor_certificate,
                              x509.Certificate) and not cert_is_oscrypto:
                raise TypeError(
                    _pretty_message(
                        '''
                    requestor_certificate must be an instance of
                    asn1crypto.x509.Certificate or
                    oscrypto.asymmetric.Certificate, not %s
                    ''', _type_name(requestor_certificate)))

            if other_certificates is not None and not isinstance(
                    other_certificates, list):
                raise TypeError(
                    _pretty_message(
                        '''
                    other_certificates must be a list of
                    asn1crypto.x509.Certificate or
                    oscrypto.asymmetric.Certificate objects, not %s
                    ''', _type_name(other_certificates)))

            if cert_is_oscrypto:
                requestor_certificate = requestor_certificate.asn1

            tbs_request['requestor_name'] = x509.GeneralName(
                name='directory_name', value=requestor_certificate.subject)

            certificates = [requestor_certificate]

            for other_certificate in other_certificates:
                other_cert_is_oscrypto = isinstance(other_certificate,
                                                    asymmetric.Certificate)
                if not isinstance(
                        other_certificate,
                        x509.Certificate) and not other_cert_is_oscrypto:
                    raise TypeError(
                        _pretty_message(
                            '''
                        other_certificate must be an instance of
                        asn1crypto.x509.Certificate or
                        oscrypto.asymmetric.Certificate, not %s
                        ''', _type_name(other_certificate)))
                if other_cert_is_oscrypto:
                    other_certificate = other_certificate.asn1
                certificates.append(other_certificate)

            signature_algo = requestor_private_key.algorithm
            if signature_algo == 'ec':
                signature_algo = 'ecdsa'

            signature_algorithm_id = '%s_%s' % (self._hash_algo,
                                                signature_algo)

            if requestor_private_key.algorithm == 'rsa':
                sign_func = asymmetric.rsa_pkcs1v15_sign
            elif requestor_private_key.algorithm == 'dsa':
                sign_func = asymmetric.dsa_sign
            elif requestor_private_key.algorithm == 'ec':
                sign_func = asymmetric.ecdsa_sign

            if not is_oscrypto:
                requestor_private_key = asymmetric.load_private_key(
                    requestor_private_key)
            signature_bytes = sign_func(requestor_private_key,
                                        tbs_request.dump(), self._hash_algo)

            signature = ocsp.Signature({
                'signature_algorithm': {
                    'algorithm': signature_algorithm_id
                },
                'signature': signature_bytes,
                'certs': certificates
            })

        return ocsp.OCSPRequest({
            'tbs_request': tbs_request,
            'optional_signature': signature
        })