def is_valid_time(self, cert_id, ocsp_response): res = OCSPResponse.load(ocsp_response) if res['response_status'].native != 'successful': raise RevocationCheckError(msg="Invalid Status: {0}".format( res['response_status'].native), errno=ER_INVALID_OCSP_RESPONSE) basic_ocsp_response = res.basic_ocsp_response if basic_ocsp_response['certs'].native: logger.debug("Certificate is attached in Basic OCSP Response") ocsp_cert = basic_ocsp_response['certs'][0] logger.debug("Verifying the attached certificate is signed by " "the issuer") logger.debug( "Valid Not After: %s", ocsp_cert['tbs_certificate']['validity']['not_after'].native) cur_time = datetime.now(timezone.utc) """ Note: We purposefully do not verify certificate signature here. The OCSP Response is extracted from the OCSP Response Cache which is expected to have OCSP Responses with verified attached signature. Moreover this OCSP Response is eventually going to be processed by the driver before being consumed by the driver. This step ensures that the OCSP Response cache does not have any invalid entries. """ cert_valid, debug_msg = self.check_cert_time_validity( cur_time, ocsp_cert) if not cert_valid: logger.debug(debug_msg) return False tbs_response_data = basic_ocsp_response['tbs_response_data'] single_response = tbs_response_data['responses'][0] cert_status = single_response['cert_status'].name try: if cert_status == 'good': self._process_good_status(single_response, cert_id, ocsp_response) except Exception as ex: logger.debug("Failed to validate ocsp response %s", ex) return False return True
def process_ocsp_response(self, issuer, cert_id, ocsp_response): try: res = OCSPResponse.load(ocsp_response) except Exception: raise OperationalError(msg='Invalid OCSP Response', errno=ER_INVALID_OCSP_RESPONSE) if res['response_status'].native != 'successful': raise OperationalError(msg="Invalid Status: {0}".format( res['response_status'].native), errno=ER_INVALID_OCSP_RESPONSE) basic_ocsp_response = res.basic_ocsp_response if basic_ocsp_response['certs'].native: logger.debug("Certificate is attached in Basic OCSP Response") ocsp_cert = basic_ocsp_response['certs'][0] logger.debug("Verifying the attached certificate is signed by " "the issuer") logger.debug( "Valid Not After: %s", ocsp_cert['tbs_certificate']['validity']['not_after'].native) self.verify_signature(ocsp_cert.hash_algo, ocsp_cert.signature, issuer, ocsp_cert['tbs_certificate']) else: logger.debug("Certificate is NOT attached in Basic OCSP Response. " "Using issuer's certificate") ocsp_cert = issuer tbs_response_data = basic_ocsp_response['tbs_response_data'] logger.debug("Verifying the OCSP response is signed by the issuer.") self.verify_signature( basic_ocsp_response['signature_algorithm'].hash_algo, basic_ocsp_response['signature'].native, ocsp_cert, tbs_response_data) single_response = tbs_response_data['responses'][0] cert_status = single_response['cert_status'].name if cert_status == 'good': self._process_good_status(single_response, cert_id, ocsp_response) SnowflakeOCSP.OCSP_CACHE.update_cache(self, cert_id, ocsp_response) elif cert_status == 'revoked': self._process_revoked_status(single_response, cert_id) elif cert_status == 'unknown': self._process_unknown_status(cert_id) else: raise OperationalError( msg="Unknown revocation status was returned. OCSP response " "may be malformed: {0}".format(cert_status), errno=ER_INVALID_OCSP_RESPONSE_CODE)
def is_valid_time(self, cert_id, ocsp_response): res = OCSPResponse.load(ocsp_response) if res['response_status'].native != 'successful': raise RevocationCheckError(msg="Invalid Status: {0}".format( res['response_status'].native), errno=ER_INVALID_OCSP_RESPONSE) basic_ocsp_response = res.basic_ocsp_response tbs_response_data = basic_ocsp_response['tbs_response_data'] single_response = tbs_response_data['responses'][0] cert_status = single_response['cert_status'].name try: if cert_status == 'good': self._process_good_status(single_response, cert_id, ocsp_response) except Exception as ex: logger.debug("Failed to validate ocsp response %s", ex) return False return True
def process_ocsp_response(self, issuer, cert_id, ocsp_response): try: res = OCSPResponse.load(ocsp_response) if self.test_mode is not None: ocsp_load_failure = getenv("SF_TEST_OCSP_FORCE_BAD_OCSP_RESPONSE") if ocsp_load_failure is not None: raise RevocationCheckError("Force fail") except Exception: raise RevocationCheckError( msg='Invalid OCSP Response', errno=ER_INVALID_OCSP_RESPONSE ) if res['response_status'].native != 'successful': raise RevocationCheckError( msg="Invalid Status: {}".format(res['response_status'].native), errno=ER_INVALID_OCSP_RESPONSE) basic_ocsp_response = res.basic_ocsp_response if basic_ocsp_response['certs'].native: logger.debug("Certificate is attached in Basic OCSP Response") ocsp_cert = basic_ocsp_response['certs'][0] logger.debug("Verifying the attached certificate is signed by " "the issuer") logger.debug( "Valid Not After: %s", ocsp_cert['tbs_certificate']['validity']['not_after'].native) cur_time = datetime.now(timezone.utc) """ Signature verification should happen before any kind of validation """ self.verify_signature( ocsp_cert.hash_algo, ocsp_cert.signature, issuer, ocsp_cert['tbs_certificate']) cert_valid, debug_msg = self.check_cert_time_validity(cur_time, ocsp_cert) if not cert_valid: raise RevocationCheckError( msg=debug_msg, errno=ER_INVALID_OCSP_RESPONSE_CODE) else: logger.debug("Certificate is NOT attached in Basic OCSP Response. " "Using issuer's certificate") ocsp_cert = issuer tbs_response_data = basic_ocsp_response['tbs_response_data'] logger.debug("Verifying the OCSP response is signed by the issuer.") self.verify_signature( basic_ocsp_response['signature_algorithm'].hash_algo, basic_ocsp_response['signature'].native, ocsp_cert, tbs_response_data) single_response = tbs_response_data['responses'][0] cert_status = single_response['cert_status'].name if self.test_mode is not None: test_cert_status = getenv("SF_TEST_OCSP_CERT_STATUS") if test_cert_status == 'revoked': cert_status = 'revoked' elif test_cert_status == 'unknown': cert_status = 'unknown' elif test_cert_status == 'good': cert_status = 'good' try: if cert_status == 'good': self._process_good_status(single_response, cert_id, ocsp_response) SnowflakeOCSP.OCSP_CACHE.update_cache(self, cert_id, ocsp_response) elif cert_status == 'revoked': self._process_revoked_status(single_response, cert_id) elif cert_status == 'unknown': self._process_unknown_status(cert_id) else: debug_msg = "Unknown revocation status was returned." \ "OCSP response may be malformed: {}.".\ format(cert_status) raise RevocationCheckError( msg=debug_msg, errno=ER_INVALID_OCSP_RESPONSE_CODE ) except RevocationCheckError as op_er: debug_msg = "{} Consider running curl -o ocsp.der {}".\ format(op_er.msg, self.debug_ocsp_failure_url) raise RevocationCheckError(msg=debug_msg, errno=op_er.errno)
def process_ocsp_response(self, issuer, cert_id, ocsp_response): try: res = OCSPResponse.load(ocsp_response) except Exception: raise RevocationCheckError(msg='Invalid OCSP Response', errno=ER_INVALID_OCSP_RESPONSE) if res['response_status'].native != 'successful': raise RevocationCheckError(msg="Invalid Status: {0}".format( res['response_status'].native), errno=ER_INVALID_OCSP_RESPONSE) basic_ocsp_response = res.basic_ocsp_response if basic_ocsp_response['certs'].native: logger.debug("Certificate is attached in Basic OCSP Response") ocsp_cert = basic_ocsp_response['certs'][0] logger.debug("Verifying the attached certificate is signed by " "the issuer") logger.debug( "Valid Not After: %s", ocsp_cert['tbs_certificate']['validity']['not_after'].native) cur_time = datetime.now(timezone.utc) if cur_time > ocsp_cert['tbs_certificate']['validity']['not_after'].native or \ cur_time < ocsp_cert['tbs_certificate']['validity']['not_before'].native: debug_msg = "Certificate attached to OCSP response is invalid. OCSP response "\ "current time - {0} certificate not before time - {1} certificate "\ "not after time - {2}. Consider running curl -o ocsp.der {3}".\ format(cur_time, ocsp_cert['tbs_certificate']['validity']['not_before'].native, ocsp_cert['tbs_certificate']['validity']['not_after'].native, super(SnowflakeOCSPAsn1Crypto, self).debug_ocsp_failure_url) raise RevocationCheckError(msg=debug_msg, errno=ER_INVALID_OCSP_RESPONSE_CODE) self.verify_signature(ocsp_cert.hash_algo, ocsp_cert.signature, issuer, ocsp_cert['tbs_certificate']) else: logger.debug("Certificate is NOT attached in Basic OCSP Response. " "Using issuer's certificate") ocsp_cert = issuer tbs_response_data = basic_ocsp_response['tbs_response_data'] logger.debug("Verifying the OCSP response is signed by the issuer.") self.verify_signature( basic_ocsp_response['signature_algorithm'].hash_algo, basic_ocsp_response['signature'].native, ocsp_cert, tbs_response_data) single_response = tbs_response_data['responses'][0] cert_status = single_response['cert_status'].name try: if cert_status == 'good': self._process_good_status(single_response, cert_id, ocsp_response) SnowflakeOCSP.OCSP_CACHE.update_cache(self, cert_id, ocsp_response) elif cert_status == 'revoked': self._process_revoked_status(single_response, cert_id) elif cert_status == 'unknown': self._process_unknown_status(cert_id) else: debug_msg = "Unknown revocation status was returned." \ "OCSP response may be malformed: {0}.".\ format(cert_status) raise RevocationCheckError(msg=debug_msg, errno=ER_INVALID_OCSP_RESPONSE_CODE) except RevocationCheckError as op_er: debug_msg = "{0} Consider running curl -o ocsp.der {1}".\ format(op_er.msg, self.debug_ocsp_failure_url) raise RevocationCheckError(msg=debug_msg, errno=op_er.errno)
def process_ocsp_response(self, issuer, cert_id, ocsp_response): try: res = OCSPResponse.load(ocsp_response) if self.test_mode is not None: ocsp_load_failure = getenv( "SF_TEST_OCSP_FORCE_BAD_OCSP_RESPONSE") if ocsp_load_failure is not None: raise RevocationCheckError( "Force fail", errno=ER_OCSP_RESPONSE_LOAD_FAILURE) except Exception: raise RevocationCheckError(msg="Invalid OCSP Response", errno=ER_OCSP_RESPONSE_LOAD_FAILURE) if res["response_status"].native != "successful": raise RevocationCheckError( msg="Invalid Status: {}".format(res["response_status"].native), errno=ER_OCSP_RESPONSE_STATUS_UNSUCCESSFUL, ) basic_ocsp_response = res.basic_ocsp_response if basic_ocsp_response["certs"].native: logger.debug("Certificate is attached in Basic OCSP Response") ocsp_cert = basic_ocsp_response["certs"][0] logger.debug("Verifying the attached certificate is signed by " "the issuer") logger.debug( "Valid Not After: %s", ocsp_cert["tbs_certificate"]["validity"]["not_after"].native, ) cur_time = datetime.now(timezone.utc) try: """ Signature verification should happen before any kind of validation """ self.verify_signature( ocsp_cert.hash_algo, ocsp_cert.signature, issuer, ocsp_cert["tbs_certificate"], ) except RevocationCheckError as rce: raise RevocationCheckError( msg=rce.msg, errno=ER_OCSP_RESPONSE_ATTACHED_CERT_INVALID) cert_valid, debug_msg = self.check_cert_time_validity( cur_time, ocsp_cert) if not cert_valid: raise RevocationCheckError( msg=debug_msg, errno=ER_OCSP_RESPONSE_ATTACHED_CERT_EXPIRED) else: logger.debug("Certificate is NOT attached in Basic OCSP Response. " "Using issuer's certificate") ocsp_cert = issuer tbs_response_data = basic_ocsp_response["tbs_response_data"] logger.debug("Verifying the OCSP response is signed by the issuer.") try: self.verify_signature( basic_ocsp_response["signature_algorithm"].hash_algo, basic_ocsp_response["signature"].native, ocsp_cert, tbs_response_data, ) except RevocationCheckError as rce: raise RevocationCheckError( msg=rce.msg, errno=ER_OCSP_RESPONSE_INVALID_SIGNATURE) single_response = tbs_response_data["responses"][0] cert_status = single_response["cert_status"].name if self.test_mode is not None: test_cert_status = getenv("SF_TEST_OCSP_CERT_STATUS") if test_cert_status == "revoked": cert_status = "revoked" elif test_cert_status == "unknown": cert_status = "unknown" elif test_cert_status == "good": cert_status = "good" try: if cert_status == "good": self._process_good_status(single_response, cert_id, ocsp_response) SnowflakeOCSP.OCSP_CACHE.update_cache(self, cert_id, ocsp_response) elif cert_status == "revoked": self._process_revoked_status(single_response, cert_id) elif cert_status == "unknown": self._process_unknown_status(cert_id) else: debug_msg = ( "Unknown revocation status was returned." "OCSP response may be malformed: {}.".format(cert_status)) raise RevocationCheckError( msg=debug_msg, errno=ER_OCSP_RESPONSE_CERT_STATUS_INVALID) except RevocationCheckError as op_er: debug_msg = "{} Consider running curl -o ocsp.der {}".format( op_er.msg, self.debug_ocsp_failure_url) raise RevocationCheckError(msg=debug_msg, errno=op_er.errno)