コード例 #1
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,
                }
            }
        })
コード例 #2
0
    def __call__(self, req, resp):
        try:
            if req.method == "GET":
                _, _, _, tail = req.path.split("/", 3)
                body = b64decode(tail)
            elif req.method == "POST":
                body = req.stream.read(req.content_length or 0)
            else:
                raise falcon.HTTPMethodNotAllowed()
            ocsp_req = ocsp.OCSPRequest.load(body)
        except ValueError:
            raise falcon.HTTPBadRequest()

        fh = open(config.AUTHORITY_CERTIFICATE_PATH,
                  "rb")  # TODO: import from authority
        server_certificate = asymmetric.load_certificate(fh.read())
        fh.close()

        now = datetime.now(timezone.utc)
        response_extensions = []

        try:
            for ext in ocsp_req["tbs_request"]["request_extensions"]:
                if ext["extn_id"].native == "nonce":
                    response_extensions.append(
                        ocsp.ResponseDataExtension({
                            'extn_id':
                            "nonce",
                            'critical':
                            False,
                            'extn_value':
                            ext["extn_value"]
                        }))
        except ValueError:  # https://github.com/wbond/asn1crypto/issues/56
            pass

        responses = []
        for item in ocsp_req["tbs_request"]["request_list"]:
            serial = item["req_cert"]["serial_number"].native
            assert serial > 0, "Serial number correctness check failed"

            try:
                link_target = os.readlink(
                    os.path.join(config.SIGNED_BY_SERIAL_DIR,
                                 "%x.pem" % serial))
                assert link_target.startswith("../")
                assert link_target.endswith(".pem")
                path, buf, cert, signed, expires = self.authority.get_signed(
                    link_target[3:-4])
                if serial != cert.serial_number:
                    logger.error(
                        "Certificate store integrity check failed, %s refers to certificate with serial %x"
                        % (link_target, cert.serial_number))
                    raise EnvironmentError("Integrity check failed")
                status = ocsp.CertStatus(name='good', value=None)
            except EnvironmentError:
                try:
                    path, buf, cert, signed, expires, revoked = self.authority.get_revoked(
                        serial)
                    status = ocsp.CertStatus(name='revoked',
                                             value={
                                                 'revocation_time':
                                                 revoked,
                                                 'revocation_reason':
                                                 "key_compromise",
                                             })
                except EnvironmentError:
                    status = ocsp.CertStatus(name="unknown", value=None)

            responses.append({
                'cert_id': {
                    'hash_algorithm': {
                        'algorithm': "sha1"
                    },
                    'issuer_name_hash': server_certificate.asn1.subject.sha1,
                    'issuer_key_hash': server_certificate.public_key.asn1.sha1,
                    'serial_number': serial,
                },
                'cert_status': status,
                'this_update': now,
                'single_extensions': []
            })

        response_data = ocsp.ResponseData({
            'responder_id':
            ocsp.ResponderId(name='by_key',
                             value=server_certificate.public_key.asn1.sha1),
            'produced_at':
            now,
            'responses':
            responses,
            'response_extensions':
            response_extensions
        })

        resp.body = ocsp.OCSPResponse({
            'response_status': "successful",
            'response_bytes': {
                'response_type': "basic_ocsp_response",
                'response': {
                    'tbs_response_data':
                    response_data,
                    'certs': [server_certificate.asn1],
                    'signature_algorithm': {
                        'algorithm':
                        "sha1_ecdsa" if self.authority.public_key.algorithm
                        == "ec" else "sha1_rsa"
                    },
                    'signature':
                    (asymmetric.ecdsa_sign
                     if self.authority.public_key.algorithm == "ec" else
                     asymmetric.rsa_pkcs1v15_sign)(self.authority.private_key,
                                                   response_data.dump(),
                                                   "sha1")
                }
            }
        }).dump()
コード例 #3
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
                }
            }
        })
コード例 #4
0
    def build_ocsp_response(self, req: ocsp.OCSPRequest) -> ocsp.OCSPResponse:
        nonce = req.nonce_value.native
        requests = req['tbs_request']['request_list']
        issuer_cert = self.revinfo_interface.get_issuer_cert()
        err = SimpleOCSPResponder.build_error_response

        if len(requests) == 0:
            return err('malformed_request')

        responses = []
        for req_item in requests:
            cid: ocsp.CertId = req_item['req_cert']

            if not issuer_match(cid, issuer_cert):
                return err('unauthorized')

            revinfo_interface = self.revinfo_interface
            try:
                cert_status, exts = revinfo_interface.check_revocation_status(
                    cid, self.at_time
                )
            except NotImplementedError:
                return err('internal_error')
            except CertomancerServiceError:
                return err('unauthorized')

            responses.append(
                ocsp.SingleResponse({
                    'cert_id': cid,
                    'cert_status': cert_status,
                    'this_update': self.at_time,
                    'next_update': self.at_time + self.validity,
                    'single_extensions': exts or None
                })
            )

        rdata = ocsp.ResponseData({
            'responder_id': ocsp.ResponderId(
                name='by_key', value=self.responder_cert.public_key.sha1
            ),
            'produced_at': self.at_time,
            'responses': responses,
        })
        response_extensions = list(self.response_extensions)
        if nonce is not None:
            nonce_extension = ocsp.ResponseDataExtension({
                'extn_id': 'nonce', 'extn_value': nonce
            })
            response_extensions.append(nonce_extension)
        rdata['response_extensions'] = response_extensions

        signature = generic_sign(
            self.responder_key, rdata.dump(),
            signature_algo=self.signature_algo
        )
        basic_resp = ocsp.BasicOCSPResponse({
            'tbs_response_data': rdata,
            'signature_algorithm': self.signature_algo,
            'signature': signature,
            'certs': [self.responder_cert]
        })
        response_bytes = ocsp.ResponseBytes({
            'response_type': 'basic_ocsp_response',
            'response': core.ParsableOctetString(basic_resp.dump())
        })
        return ocsp.OCSPResponse({
            'response_status': 'successful',
            'response_bytes': response_bytes
        })
コード例 #5
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
                }
            }
        })