{"id":"612e6f63253b02cd","repo":"redis/redis-py","slug":"failed-to-fetch-ocsp-certificate","errorCode":null,"errorMessage":"failed to fetch ocsp certificate","messagePattern":"failed to fetch ocsp certificate","errorType":"exception","errorClass":"ConnectionError","httpStatus":null,"severity":"error","filePath":"redis/ocsp.py","lineNumber":287,"sourceCode":"    def check_certificate(self, server, cert, issuer_url):\n        \"\"\"Checks the validity of an ocsp server for an issuer\"\"\"\n\n        r = requests.get(issuer_url)\n        if not r.ok:\n            raise ConnectionError(\"failed to fetch issuer certificate\")\n        der = r.content\n        issuer_cert = self._bin2ascii(der)\n\n        ocsp_url = self.build_certificate_url(server, cert, issuer_cert)\n\n        # HTTP 1.1 mandates the addition of the Host header in ocsp responses\n        header = {\n            \"Host\": urlparse(ocsp_url).netloc,\n            \"Content-Type\": \"application/ocsp-request\",\n        }\n        r = requests.get(ocsp_url, headers=header)\n        if not r.ok:\n            raise ConnectionError(\"failed to fetch ocsp certificate\")\n        return _check_certificate(issuer_cert, r.content, True)\n\n    def is_valid(self):\n        \"\"\"Returns the validity of the certificate wrapping our socket.\n        This first retrieves for validate the certificate, issuer_url,\n        and ocsp_server for certificate validate. Then retrieves the\n        issuer certificate from the issuer_url, and finally checks\n        the validity of OCSP revocation status.\n        \"\"\"\n\n        # validate the certificate\n        try:\n            cert, issuer_url, ocsp_server = self.components_from_socket()\n            if issuer_url is None:\n                raise ConnectionError(\"no issuers found in certificate chain\")\n            return self.check_certificate(ocsp_server, cert, issuer_url)\n        except AuthorizationError:\n            cert, issuer_url, ocsp_server = self.components_from_direct_connection()","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/ocsp.py#L269-L305","documentation":"Raised by OCSPValidator.check_certificate (redis/ocsp.py:287) during TLS connection setup when OCSP revocation checking is enabled. After building the OCSP request URL from the server certificate's AIA extension, the library performs requests.get(ocsp_url); if the OCSP responder returns a non-2xx HTTP status (r.ok is False), it raises redis.exceptions.ConnectionError. The library performs this check to refuse TLS connections whose revocation status cannot be verified.","triggerScenarios":"Connecting with redis.Redis(..., ssl=True, ssl_ocsp_context=...) or RedisCluster with OCSP validation enabled, where the OCSP responder URL (extracted from the cert's Authority Information Access extension) returns an HTTP error (4xx/5xx), is unreachable, or is blocked. Specifically triggered when requests.get(ocsp_url, headers=header).ok evaluates False inside OCSPValidator.check_certificate.","commonSituations":"Corporate firewall / egress proxy blocking the OCSP responder host; OCSP responder temporarily down or misconfigured; self-signed or internal CA certs that point to a non-functional OCSP URL; air-gapped environments with no outbound HTTP; expired OCSP responder certificate causing TLS failure at the requests layer (which yields a non-ok response or exception).","solutions":["Disable OCSP validation if your deployment does not require it: drop the ssl_ocsp_context argument and connect with ssl=True only.","Verify network egress to the OCSP responder URL extracted from the cert (inspect the AIA extension) and allow it through firewall/proxy.","Configure an HTTPS_PROXY/HTTP_PROXY environment variable so 'requests' can reach the OCSP responder through your corporate proxy.","Use a server certificate whose AIA extension points to a healthy, reachable OCSP responder."],"exampleFix":"# before\nclient = redis.Redis(host='rediss.example.com', port=6379, ssl=True, ssl_ocsp_context=ocsp_ctx)\n# after (drop OCSP validation if not required)\nclient = redis.Redis(host='rediss.example.com', port=6379, ssl=True)","handlingStrategy":"try-catch","validationCode":"# Pre-flight: ensure the OCSP responder URL extracted from the cert is reachable\nimport requests\nfrom cryptography import x509\nfrom cryptography.hazmat.backends import default_backend\n\ndef ocsp_responder_reachable(cert_pem: bytes) -> bool:\n    cert = x509.load_pem_x509_certificate(cert_pem, default_backend())\n    try:\n        aia = cert.extensions.get_extension_for_oid(\n            x509.oid.ExtensionOID.AUTHORITY_INFORMATION_ACCESS\n        ).value\n    except x509.extensions.ExtensionNotFound:\n        return False\n    ocsp_urls = [d.access_location.value for d in aia\n                 if d.access_method == x509.oid.AuthorityInformationAccessOID.OCSP]\n    if not ocsp_urls:\n        return False\n    try:\n        return requests.get(ocsp_urls[0], timeout=5).ok\n    except Exception:\n        return False","typeGuard":null,"tryCatchPattern":"from redis.exceptions import ConnectionError as RedisConnectionError\n\ntry:\n    client = redis.Redis(host=HOST, port=PORT, ssl=True, ssl_ocsp_context=ctx)\n    client.ping()\nexcept RedisConnectionError as e:\n    if 'failed to fetch ocsp certificate' in str(e):\n        # OCSP responder unreachable: fall back to TLS without OCSP validation\n        client = redis.Redis(host=HOST, port=PORT, ssl=True)\n    else:\n        raise","preventionTips":["Only enable ssl_ocsp_context when your deployment mandates revocation checking and the responder is reachable.","Allowlist the OCSP responder host in your egress firewall/proxy.","Monitor OCSP responder uptime independently so you detect outages before clients fail.","Test the full TLS+OCSP path in staging with the production certificate."],"tags":["tls","ocsp","ssl","network","security","certificate"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}