def test_build_delegated_good_response(self): responder_key = asymmetric.load_private_key( os.path.join(fixtures_dir, 'test-ocsp.key'), 'password') responder_cert = asymmetric.load_certificate( os.path.join(fixtures_dir, 'test-ocsp.crt')) issuer_cert = asymmetric.load_certificate( os.path.join(fixtures_dir, 'test.crt')) subject_cert = asymmetric.load_certificate( os.path.join(fixtures_dir, 'test-inter.crt')) builder = OCSPResponseBuilder('successful', [{ 'certificate': subject_cert, 'certificate_status': 'good' }]) builder.certificate_issuer = issuer_cert ocsp_response = builder.build(responder_key, responder_cert) der_bytes = ocsp_response.dump() new_response = asn1crypto.ocsp.OCSPResponse.load(der_bytes) basic_response = new_response['response_bytes']['response'].parsed response_data = basic_response['tbs_response_data'] self.assertEqual('sha256', basic_response['signature_algorithm'].hash_algo) self.assertEqual('rsassa_pkcs1v15', basic_response['signature_algorithm'].signature_algo) self.assertEqual('v1', response_data['version'].native) self.assertEqual('by_key', response_data['responder_id'].name) self.assertEqual(responder_cert.asn1.public_key.sha1, response_data['responder_id'].chosen.native) self.assertGreaterEqual(datetime.now(timezone.utc), response_data['produced_at'].native) self.assertEqual(1, len(response_data['responses'])) self.assertEqual(0, len(response_data['response_extensions'])) cert_response = response_data['responses'][0] self.assertEqual( 'sha1', cert_response['cert_id']['hash_algorithm']['algorithm'].native) self.assertEqual(issuer_cert.asn1.subject.sha1, cert_response['cert_id']['issuer_name_hash'].native) self.assertEqual(issuer_cert.asn1.public_key.sha1, cert_response['cert_id']['issuer_key_hash'].native) self.assertEqual(subject_cert.asn1.serial_number, cert_response['cert_id']['serial_number'].native) self.assertEqual('good', cert_response['cert_status'].name) self.assertGreaterEqual(datetime.now(timezone.utc), cert_response['this_update'].native) self.assertGreaterEqual(set(), cert_response.critical_extensions)
def test_build_delegated_good_response(self): responder_key = asymmetric.load_private_key(os.path.join(fixtures_dir, 'test-ocsp.key'), 'password') responder_cert = asymmetric.load_certificate(os.path.join(fixtures_dir, 'test-ocsp.crt')) issuer_cert = asymmetric.load_certificate(os.path.join(fixtures_dir, 'test.crt')) subject_cert = asymmetric.load_certificate(os.path.join(fixtures_dir, 'test-inter.crt')) builder = OCSPResponseBuilder('successful', subject_cert, 'good') builder.certificate_issuer = issuer_cert ocsp_response = builder.build(responder_key, responder_cert) der_bytes = ocsp_response.dump() new_response = asn1crypto.ocsp.OCSPResponse.load(der_bytes) basic_response = new_response['response_bytes']['response'].parsed response_data = basic_response['tbs_response_data'] self.assertEqual('sha256', basic_response['signature_algorithm'].hash_algo) self.assertEqual('rsassa_pkcs1v15', basic_response['signature_algorithm'].signature_algo) self.assertEqual('v1', response_data['version'].native) self.assertEqual('by_key', response_data['responder_id'].name) self.assertEqual( responder_cert.asn1.public_key.sha1, response_data['responder_id'].chosen.native ) self.assertGreaterEqual(datetime.now(timezone.utc), response_data['produced_at'].native) self.assertEqual(1, len(response_data['responses'])) self.assertEqual(0, len(response_data['response_extensions'])) cert_response = response_data['responses'][0] self.assertEqual('sha1', cert_response['cert_id']['hash_algorithm']['algorithm'].native) self.assertEqual(issuer_cert.asn1.subject.sha1, cert_response['cert_id']['issuer_name_hash'].native) self.assertEqual(issuer_cert.asn1.public_key.sha1, cert_response['cert_id']['issuer_key_hash'].native) self.assertEqual(subject_cert.asn1.serial_number, cert_response['cert_id']['serial_number'].native) self.assertEqual('good', cert_response['cert_status'].name) self.assertGreaterEqual(datetime.now(timezone.utc), cert_response['this_update'].native) self.assertGreaterEqual(set(), cert_response.critical_extensions)
def get_ocsp_response(self, data): try: ocsp_request = asn1crypto.ocsp.OCSPRequest.load(data) tbs_request = ocsp_request['tbs_request'] request_list = tbs_request['request_list'] if len(request_list) != 1: log.error('Received OCSP request with multiple sub requests') raise NotImplemented('Combined requests not yet supported') single_request = request_list[0] # TODO: Support more than one request req_cert = single_request['req_cert'] serial = serial_from_int(req_cert['serial_number'].native) except Exception as e: log.exception('Error parsing OCSP request: %s', e) return self.fail('malformed_request') ca = CertificateAuthority.objects.get(serial=self.ca_serial) try: cert = Certificate.objects.filter(ca=ca).get(serial=serial) except Certificate.DoesNotExist: log.warn('OCSP request for unknown cert received.') return self.fail('internal_error') # TODO: return a 'unkown' response instead builder = OCSPResponseBuilder( response_status='successful', # ResponseStatus.successful.value, certificate=load_certificate(force_bytes(cert.pub)), certificate_status=cert.ocsp_status, revocation_date=cert.revoked_date, ) # Parse extensions for extension in tbs_request['request_extensions']: extn_id = extension['extn_id'].native critical = extension['critical'].native value = extension['extn_value'].parsed # This variable tracks whether any unknown extensions were encountered unknown = False # Handle nonce extension if extn_id == 'nonce': builder.nonce = value.native # That's all we know else: unknown = True # If an unknown critical extension is encountered (which should not # usually happen, according to RFC 6960 4.1.2), we should throw our # hands up in despair and run. if unknown is True and critical is True: log.warning('Could not parse unknown critical extension: %r', dict(extension.native)) return self._fail('internal_error') # If it's an unknown non-critical extension, we can safely ignore it. elif unknown is True: log.info('Ignored unknown non-critical extension: %r', dict(extension.native)) builder.certificate_issuer = load_certificate(force_bytes(ca.pub)) builder.next_update = timezone.now() + timedelta(days=1) responder_cert = self.get_responder_cert() return builder.build(self.responder_key, responder_cert)
def get_ocsp_response(self, data): try: ocsp_request = asn1crypto.ocsp.OCSPRequest.load(data) tbs_request = ocsp_request['tbs_request'] request_list = tbs_request['request_list'] if len(request_list) != 1: log.error('Received OCSP request with multiple sub requests') raise NotImplemented('Combined requests not yet supported') single_request = request_list[ 0] # TODO: Support more than one request req_cert = single_request['req_cert'] serial = serial_from_int(req_cert['serial_number'].native) except Exception as e: log.exception('Error parsing OCSP request: %s', e) return self.fail(u'malformed_request') # Get CA and certificate ca = CertificateAuthority.objects.get(serial=self.ca) try: cert = Certificate.objects.filter(ca=ca).get(serial=serial) except Certificate.DoesNotExist: log.warn('OCSP request for unknown cert received.') return self.fail(u'internal_error') # load ca cert and responder key/cert ca_cert = load_certificate(force_bytes(ca.pub)) responder_key = load_private_key(self.responder_key) responder_cert = load_certificate(self.responder_cert) builder = OCSPResponseBuilder( response_status=u'successful', # ResponseStatus.successful.value, certificate=load_certificate(force_bytes(cert.pub)), certificate_status=force_text(cert.ocsp_status), revocation_date=cert.revoked_date, ) # Parse extensions for extension in tbs_request['request_extensions']: extn_id = extension['extn_id'].native critical = extension['critical'].native value = extension['extn_value'].parsed # This variable tracks whether any unknown extensions were encountered unknown = False # Handle nonce extension if extn_id == 'nonce': builder.nonce = value.native # That's all we know else: # pragma: no cover unknown = True # If an unknown critical extension is encountered (which should not # usually happen, according to RFC 6960 4.1.2), we should throw our # hands up in despair and run. if unknown is True and critical is True: # pragma: no cover log.warning('Could not parse unknown critical extension: %r', dict(extension.native)) return self._fail('internal_error') # If it's an unknown non-critical extension, we can safely ignore it. elif unknown is True: # pragma: no cover log.info('Ignored unknown non-critical extension: %r', dict(extension.native)) builder.certificate_issuer = ca_cert builder.next_update = datetime.utcnow() + timedelta( seconds=self.expires) return builder.build(responder_key, responder_cert)
def _build_ocsp_response(self, ocsp_request: OCSPRequest) -> OCSPResponse: """ Create and return an OCSP response from an OCSP request. """ # Get the certificate serial tbs_request = ocsp_request['tbs_request'] request_list = tbs_request['request_list'] if len(request_list) != 1: logger.warning('Received OCSP request with multiple sub requests') raise NotImplemented('Combined requests not yet supported') single_request = request_list[0] # TODO: Support more than one request req_cert = single_request['req_cert'] serial = req_cert['serial_number'].native # Check certificate status try: certificate_status, revocation_date = self._validate(serial) except Exception as e: logger.exception('Could not determine certificate status: %s', e) return self._fail(ResponseStatus.internal_error) # Retrieve certificate try: subject_cert_contents = self._cert_retrieve(serial) except Exception as e: logger.exception('Could not retrieve certificate with serial %s: %s', serial, e) return self._fail(ResponseStatus.internal_error) # Parse certificate try: subject_cert = asymmetric.load_certificate(subject_cert_contents.encode('utf8')) except Exception as e: logger.exception('Returned certificate with serial %s is invalid: %s', serial, e) return self._fail(ResponseStatus.internal_error) # Build the response builder = OCSPResponseBuilder(**{ 'response_status': ResponseStatus.successful.value, 'certificate': subject_cert, 'certificate_status': certificate_status.value, 'revocation_date': revocation_date, }) # Parse extensions for extension in tbs_request['request_extensions']: extn_id = extension['extn_id'].native critical = extension['critical'].native value = extension['extn_value'].parsed # This variable tracks whether any unknown extensions were encountered unknown = False # Handle nonce extension if extn_id == 'nonce': builder.nonce = value.native # That's all we know else: unknown = True # If an unknown critical extension is encountered (which should not # usually happen, according to RFC 6960 4.1.2), we should throw our # hands up in despair and run. if unknown is True and critical is True: logger.warning('Could not parse unknown critical extension: %r', dict(extension.native)) return self._fail(ResponseStatus.internal_error) # If it's an unknown non-critical extension, we can safely ignore it. elif unknown is True: logger.info('Ignored unknown non-critical extension: %r', dict(extension.native)) # Set certificate issuer builder.certificate_issuer = self._issuer_cert # Set next update date builder.next_update = datetime.now(timezone.utc) + timedelta(days=self._next_update_days) return builder.build(self._responder_key, self._responder_cert)
def build_ocsp_response(self, ocsp_request: OCSPRequest) -> OCSPResponse: """ Create and return an OCSP response from an OCSP request. """ # Get the certificate serial req_cert_id = _get_req_cert_id(ocsp_request) #serial = req_cert_id['serial_number'].native #issuer_key_hash = req_cert_id['issuer_key_hash'].native #issuer_name_hash = req_cert_id['issuer_name_hash'].native #hash_algorithm = req_cert_id['hash_algorithm'] #hash_algo_name = hash_algorithm['algorithm'].native #hash_algo_params = hash_algorithm['parameters'].native # Check certificate status try: certificate_status, revocation_date = self._validate(req_cert_id, self.issuer_cert) except Exception as e: logger.exception('Could not determine certificate status: %s', e) return _fail(ResponseStatus.internal_error) # Retrieve certificate try: subject_cert_contents = self._cert_retrieve(req_cert_id, self.issuer_cert) except Exception as e: logger.exception('Could not retrieve certificate with serial %s: %s', serial, e) return _fail(ResponseStatus.internal_error) # Parse certificate if needed if isinstance(subject_cert_contents, x509.Certificate): subject_cert = subject_cert_contents elif isinstance(subject_cert_contents, asymmetric.Certificate): subject_cert = subject_cert_contents.asn1 else: try: subject_cert = asymmetric.load_certificate(subject_cert_contents.encode('utf8')) except Exception as e: logger.exception('Returned certificate with serial %s is invalid: %s', serial, e) return _fail(ResponseStatus.internal_error) # Build the response builder = OCSPResponseBuilder(**{ 'response_status': ResponseStatus.successful.value, 'certificate': subject_cert, 'certificate_status': certificate_status.value, 'revocation_date': revocation_date, }) # Parse extensions tbs_request = ocsp_request['tbs_request'] for extension in tbs_request['request_extensions']: extn_id = extension['extn_id'].native critical = extension['critical'].native value = extension['extn_value'].parsed # This variable tracks whether any unknown extensions were encountered unknown = False # Handle nonce extension if extn_id == 'nonce': builder.nonce = value.native # That's all we know else: unknown = True # If an unknown critical extension is encountered (which should not # usually happen, according to RFC 6960 4.1.2), we should throw our # hands up in despair and run. if unknown is True and critical is True: logger.warning('Could not parse unknown critical extension: %r', dict(extension.native)) return _fail(ResponseStatus.internal_error) # If it's an unknown non-critical extension, we can safely ignore it. elif unknown is True: logger.info('Ignored unknown non-critical extension: %r', dict(extension.native)) # Set certificate issuer builder.certificate_issuer = self._issuer_cert # Set next update date builder.next_update = datetime.now(timezone.utc) + timedelta(days=self._next_update_days) return builder.build(self._responder_key, self._responder_cert)