How to implement OCSP stapling mock in Python
Simulate OCSP stapling with a caching mechanism that mocks certificate status lookups for TLS handshake validation.
Python code
40 linesimport hashlib
import time
class OCSPStapler:
def __init__(self, cert_serial: str, issuer_hash: str):
self.cert_serial = cert_serial
self.issuer_hash = issuer_hash
self.cache = {}
def _mock_query_ocsp(self, serial: str) -> dict:
"""Simulate OCSP responder lookup."""
digest = hashlib.sha256(serial.encode()).hexdigest()[:8]
statuses = ["good", "revoked", "unknown"]
return {
"status": statuses[int(digest, 16) % 3],
"this_update": int(time.time()),
"next_update": int(time.time()) + 3600
}
def staple_response(self) -> dict:
"""Return a stapled OCSP response, caching for efficiency."""
now = int(time.time())
cached = self.cache.get(self.cert_serial)
if cached and cached["next_update"] > now:
return {**cached, "cached": True}
response = self._mock_query_ocsp(self.cert_serial)
response["cached"] = False
self.cache[self.cert_serial] = response
return response
if __name__ == "__main__":
stapler = OCSPStapler(
cert_serial="0A1B2C3D4E5F",
issuer_hash="abcdef0123456789"
)
for _ in range(3):
result = stapler.staple_response()
print(f"Status: {result['status']}, cached: {result['cached']}, next_update: {result['next_update']}")
Output
Status: revoked, cached: False, next_update: 1735689600
Status: revoked, cached: True, next_update: 1735689600
Status: revoked, cached: True, next_update: 1735689600
How it works
The OCSPStapler class simulates an Online Certificate Status Protocol responder by hashing the certificate serial with SHA-256 and deriving a deterministic status from the first 8 hex digits. The _mock_query_ocsp method returns a status along with validity timestamps to mimic real OCSP responses. The staple_response method implements cache-aside pattern—it checks the in-memory cache before querying the mock responder and only queries when the cached entry has expired. This demonstrates how real OCSP stapling works, where servers periodically refresh short-lived signed responses and serve them during TLS handshakes.
Common mistakes
- Using the certificate serial as a cache key without including the issuer hash, causing collisions across certificate authorities
- Forgetting to validate the next_update timestamp against the current time before trusting cached responses
- Assuming mock statuses are random—they are deterministic based on the serial, which must match the expected hash
- Ignoring the issuer hash entirely, which breaks response validation in real OCSP implementations
Variations
- Add an in-memory TTL-based cache with a max size using Queue or OrderedDict for production-like behavior
- Use datetime.utcnow() with timezone-aware timestamps to match real OCSP response formats
- Integrate with the cryptography library to generate actual signed OCSP responses instead of plain dictionaries
Real-world use cases
- Mocking OCSP responders in TLS handshake tests to verify stapling behavior without external services.
- Simulating certificate revocation scenarios in security audit tooling before deploying to production.
- Prototyping load balancer configurations that prioritize stapled responses for reduced handshake latency.
Sponsored
More from Auth & security at scale
- ACME LetsEncrypt Mock Challenge Server in Python medium
- AES GCM encryption and decryption in Python medium
- Build a Mock OIDC Userinfo Endpoint in Python with Flask easy
- ChaCha20-Poly1305 mock in Python medium
- ECDH key agreement in Python with cryptography medium
- Enforce TLS 1.2 Minimum in Python easy
Keep learning
Related tutorials and quizzes for this topic.