Skip to main content
โšก Calmops

OCSP Protocol: Complete Certificate Status Checking Guide for 2026

Introduction

Certificate revocation is a critical component of PKI security. When a certificate’s private key is compromised or when an employee leaves, certificates must be invalidated immediately. The Online Certificate Status Protocol (OCSP) provides a real-time mechanism for checking certificate validity without the overhead of downloading entire Certificate Revocation Lists (CRLs).

This comprehensive guide covers everything from OCSP protocol mechanics to production implementations. You’ll learn how OCSP compares to CRLs, how to implement OCSP stapling for performance, and best practices for building reliable certificate validation systems.

Modern web applications require robust certificate validation. With TLS now mandatory for most web traffic, understanding OCSP is essential for security engineers, DevOps professionals, and anyone responsible for PKI infrastructure.

Understanding Certificate Revocation

The Revocation Problem

When a certificate needs to be invalidated, the CA must make this information available to verifying parties. Two primary mechanisms exist:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                   Certificate Revocation Methods                       โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                       โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”            โ”‚
โ”‚   โ”‚     CRL (Certificate                                         โ”‚
โ”‚   โ”‚     Revocation List) โ”‚         โ”‚        OCSP        โ”‚            โ”‚
โ”‚   โ”‚                     โ”‚         โ”‚  (Online Certificateโ”‚            โ”‚
โ”‚   โ”‚  โ€ข Download entire  โ”‚         โ”‚    Status Protocol)โ”‚            โ”‚
โ”‚   โ”‚    list of revoked โ”‚         โ”‚                     โ”‚            โ”‚
โ”‚   โ”‚    certificates    โ”‚         โ”‚  โ€ข Query individual โ”‚            โ”‚
โ”‚   โ”‚                     โ”‚         โ”‚    certificate      โ”‚            โ”‚
โ”‚   โ”‚  โ€ข Can be large    โ”‚         โ”‚    status           โ”‚            โ”‚
โ”‚   โ”‚    (hundreds of MB)โ”‚         โ”‚                     โ”‚            โ”‚
โ”‚   โ”‚                     โ”‚         โ”‚  โ€ข Small response  โ”‚            โ”‚
โ”‚   โ”‚  โ€ข Updated periodicโ”‚         โ”‚  โ€ข Real-time        โ”‚            โ”‚
โ”‚   โ”‚    (hours/days)   โ”‚         โ”‚    status           โ”‚            โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜            โ”‚
โ”‚                                                                       โ”‚
โ”‚   Combined approach often used: OCSP as primary, CRL as fallback     โ”‚
โ”‚                                                                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Why OCSP Matters

Aspect CRL OCSP
Response size Large (MB) Small (KB)
Real-time No (periodic) Yes (immediate)
Bandwidth High Low
Privacy Poor Better
Client load High Lower

OCSP Protocol Deep Dive

Protocol Overview

OCSP follows a simple request-response model:

  1. Client builds OCSP request containing certificate serial number
  2. Request is sent to OCSP responder
  3. Responder queries CA’s revocation database
  4. Response is signed and returned
  5. Client validates response signature

Request Format

from dataclasses import dataclass
import hashlib


@dataclass
class OCSPRequest:
    """OCSP request structure."""
    issuer_name_hash: bytes
    issuer_key_hash: bytes
    serial_number: bytes
    nonce: bytes = None


def build_ocsp_request(cert, issuer_cert) -> OCSPRequest:
    """Build OCSP request for a certificate."""
    import hashlib
    
    # Hash of issuer's subject name
    issuer_name_hash = hashlib.sha1(
        issuer_cert.subject.public_bytes()
    ).digest()
    
    # Hash of issuer's public key
    issuer_key_hash = hashlib.sha1(
        issuer_cert.public_key().public_bytes(
            encoding=serialization.Encoding.DER,
            format=serialization.PublicFormat.SubjectPublicKeyInfo
        )
    ).digest()
    
    # Generate nonce
    import os
    nonce = os.urandom(16)
    
    return OCSPRequest(
        issuer_name_hash=issuer_name_hash,
        issuer_key_hash=issuer_key_hash,
        serial_number=cert.serial_number,
        nonce=nonce
    )


def encode_ocsp_request(request: OCSPRequest) -> bytes:
    """Encode OCSP request in DER format."""
    from pyasn1.codec.der import encoder
    from pyasn1Modules import rfc6960
    
    # Build OCSPRequest structure
    req = rfc6960.OCSPRequest()
    
    # Add request list
    req['requestList'] = []
    
    # This is simplified - real implementation needs full ASN.1 encoding
    return encoder.encode(req)

Response Format

from enum import Enum
from datetime import datetime


class OCSPResponseStatus(Enum):
    """OCSP response status codes."""
    SUCCESSFUL = 0
    MALFORMED_REQUEST = 1
    INTERNAL_ERROR = 2
    TRY_LATER = 3
    SIG_REQUIRED = 4
    UNAUTHORIZED = 6


class OCSPCertStatus(Enum):
    """Certificate status values."""
    GOOD = 0
    REVOKED = 1
    UNKNOWN = 2


@dataclass
class OCSPResponse:
    """OCSP response structure."""
    response_status: OCSPResponseStatus
    produced_at: datetime
    this_update: datetime
    next_update: datetime = None
    cert_status: OCSPCertStatus = None
    revocation_time: datetime = None
    revocation_reason: int = None
    signature: bytes = None


def parse_ocsp_response(response_data: bytes) -> OCSPResponse:
    """Parse OCSP response."""
    from pyasn1.codec.der import decoder
    
    # Decode response
    response, _ = decoder.decode(response_data, asn1Spec=rfc6960.OCSPResponse())
    
    # Extract fields
    return OCSPResponse(
        response_status=OCSPResponseStatus(int(response['responseStatus'])),
        produced_at=datetime.fromtimestamp(
            int(response['responseBytes']['basicOCSPResponse']['producedAt'])
        ),
        this_update=datetime.fromtimestamp(
            int(response['responseBytes']['basicOCSPResponse']['responses'][0]['thisUpdate'])
        ),
        cert_status=OCSPCertStatus(
            int(response['responseBytes']['basicOCSPResponse']['responses'][0]['certStatus']['good'])
        )
    )

OCSP Request/Response Example

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                        OCSP Request                                    โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                       โ”‚
โ”‚  POST /ocsp/status HTTP/1.1                                          โ”‚
โ”‚  Host: ocsp.digicert.com                                             โ”‚
โ”‚  Content-Type: application/ocsp-request                              โ”‚
โ”‚  Accept: application/ocsp-response                                  โ”‚
โ”‚                                                                       โ”‚
โ”‚  [DER-encoded OCSP request - typically 100-200 bytes]               โ”‚
โ”‚                                                                       โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                        OCSP Response                                  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                       โ”‚
โ”‚  HTTP/1.1 200 OK                                                     โ”‚
โ”‚  Content-Type: application/ocsp-response                            โ”‚
โ”‚  Last-Modified: Wed, 13 Mar 2026 10:00:00 GMT                       โ”‚
โ”‚  Expires: Wed, 13 Mar 2026 11:00:00 GMT                            โ”‚
โ”‚  Cache-Control: max-age=3600                                         โ”‚
โ”‚                                                                       โ”‚
โ”‚  [DER-encoded OCSP response - signed, includes:                     โ”‚
โ”‚    - Response status                                                 โ”‚
โ”‚    - Certificate status (good/revoked/unknown)                      โ”‚
โ”‚    - This update / Next update timestamps                            โ”‚
โ”‚    - Signature from OCSP responder]                                 โ”‚
โ”‚                                                                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

OCSP Implementation

Python Implementation

import requests
import base64
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.x509 import ocsp as x509_ocsp
from datetime import datetime, timedelta
from typing import Optional


class OCSPClient:
    """Client for checking certificate status via OCSP."""
    
    def __init__(self, timeout: int = 10):
        self.timeout = timeout
    
    def check_certificate(
        self,
        cert_path: str,
        issuer_path: str,
        ocsp_responder: str
    ) -> dict:
        """Check certificate status via OCSP."""
        
        # Load certificates
        with open(cert_path, 'rb') as f:
            cert = x509.load_pem_x509_certificate(f.read(), default_backend())
        
        with open(issuer_path, 'rb') as f:
            issuer = x509.load_pem_x509_certificate(f.read(), default_backend())
        
        # Build OCSP request
        builder = x509_ocsp.OCSPRequestBuilder()
        builder = builder.add_certificate(
            cert, issuer, hashes.SHA1()
        )
        ocsp_request = builder.build()
        
        # Encode request
        request_der = ocsp_request.public_bytes(serialization.Encoding.DER)
        request_b64 = base64.b64encode(request_der).decode('ascii')
        
        # Send request
        url = f"{ocsp_responder.rstrip('/')}/{cert.serial_number}"
        
        headers = {
            'Content-Type': 'application/ocsp-request',
            'Accept': 'application/ocsp-response'
        }
        
        response = requests.post(
            url,
            data=request_der,
            headers=headers,
            timeout=self.timeout
        )
        
        if response.status_code != 200:
            return {
                'status': 'error',
                'message': f"HTTP {response.status_code}"
            }
        
        # Parse response
        ocsp_response = x509.load_der_ocsp_response(response.content)
        
        # Extract status
        status = ocsp_response.response_status
        cert_status = ocsp_response.certificate_status
        
        result = {
            'status': 'success',
            'response_status': str(status.name),
            'produced_at': str(ocsp_response.produced_at),
            'this_update': str(ocsp_response.this_update),
            'next_update': str(ocsp_response.next_update) if ocsp_response.next_update else None
        }
        
        # Add certificate status
        if cert_status == x509_ocsp.OCSPCertStatus.GOOD:
            result['certificate_status'] = 'good'
        elif cert_status == x509_ocsp.OCSPCertStatus.REVOKED:
            result['certificate_status'] = 'revoked'
            result['revocation_time'] = str(ocsp_response.revocation_time)
            result['revocation_reason'] = str(ocsp_response.revocation_reason) if ocsp_response.revocation_reason else None
        else:
            result['certificate_status'] = 'unknown'
        
        return result


def check_certificate_status(
    cert_path: str,
    issuer_path: str,
    ocsp_responder: str
) -> bool:
    """
    Check if certificate is valid.
    
    Returns True if certificate is valid (not revoked).
    """
    client = OCSPClient()
    result = client.check_certificate(cert_path, issuer_path, ocsp_responder)
    
    if result['status'] != 'success':
        # On error, be conservative - treat as potentially revoked
        return False
    
    return result['certificate_status'] == 'good'

Building an OCSP Responder

from flask import Flask, request, Response
from datetime import datetime, timedelta
import hashlib


app = Flask(__name__)


# In-memory revocation database (use database in production)
revoked_certs = {
    1234567890: {
        'revoked_at': datetime(2026, 1, 15, 10, 0, 0),
        'reason': 1  # keyCompromise
    }
}


def build_ocsp_response(serial_number: int) -> bytes:
    """Build OCSP response for certificate."""
    
    now = datetime.utcnow()
    
    # Check if revoked
    if serial_number in revoked_certs:
        status = 'revoked'
        revocation_time = revoked_certs[serial_number]['revoked_at']
    else:
        status = 'good'
        revocation_time = None
    
    # Build response (simplified - real implementation needs proper ASN.1)
    response = {
        'responseStatus': 'successful',
        'thisUpdate': now,
        'nextUpdate': now + timedelta(hours=24),
        'certStatus': status,
        'revocationTime': revocation_time
    }
    
    return response


@app.route('/ocsp/<int:serial_number>', methods=['POST', 'GET'])
def ocsp_check(serial_number):
    """OCSP endpoint for checking certificate status."""
    
    # In production, validate request and sign response
    response = build_ocsp_response(serial_number)
    
    return Response(
        str(response),
        mimetype='application/ocsp-response'
    )


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

OCSP Stapling

What is OCSP Stapling?

OCSP stapling allows the server to “staple” the OCSP response to the TLS handshake, eliminating the need for clients to make separate OCSP requests:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    OCSP Stapling Flow                                   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                       โ”‚
โ”‚   Without Stapling:                                                  โ”‚
โ”‚                                                                       โ”‚
โ”‚   Client                    Server                   OCSP Responder  โ”‚
โ”‚     |                         |                          |            โ”‚
โ”‚     |------TLS Handshake----->|                          |            โ”‚
โ”‚     |                         |                          |            โ”‚
โ”‚     |<----Certificate--------|                          |            โ”‚
โ”‚     |                         |                          |            โ”‚
โ”‚     |-----------------OCSP Request--------------------->|            โ”‚
โ”‚     |                         |                          |            โ”‚
โ”‚     |<----------------OCSP Response---------------------|            โ”‚
โ”‚     |                         |                          |            โ”‚
โ”‚                                                                       โ”‚
โ”‚   With Stapling:                                                     โ”‚
โ”‚                                                                       โ”‚
โ”‚   Client                    Server                   OCSP Responder  โ”‚
โ”‚     |                         |                          |            โ”‚
โ”‚     |                         |<---OCSP Response--------|            โ”‚
โ”‚     |                         |     (periodically)       |            โ”‚
โ”‚     |                         |                          |            โ”‚
โ”‚     |------TLS Handshake----->|                          |            โ”‚
โ”‚     |                         |                          |            โ”‚
โ”‚     |<----Certificate + OCSP Response (stapled)---------|            โ”‚
โ”‚     |                         |                          |            โ”‚
โ”‚                                                                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Server Configuration

Nginx:

server {
    listen 443 ssl http2;
    server_name example.com;
    
    ssl_certificate /etc/ssl/certs/example.com.crt;
    ssl_certificate_key /etc/ssl/private/example.com.key;
    
    # Enable OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    
    # Resolver for OCSP lookup
    ssl_stapling_resolver 8.8.8.8 8.8.4.4 valid=300s;
    ssl_stapling_resolver_timeout 5s;
    
    # Cache OCSP responses
    ssl_stapling_file /var/cache/nginx/ocsp.staple;
    
    # Include root CAs for verification
    ssl_trusted_certificate /etc/ssl/certs/ca-bundle.crt;
}

Apache:

<VirtualHost *:443>
    ServerName example.com
    
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/example.com.crt
    SSLCertificateKeyFile /etc/ssl/private/example.com.key
    SSLCertificateChainFile /etc/ssl/certs/ca-bundle.crt
    
    # Enable OCSP stapling
    SSLUseStapling on
    SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
    SSLStaplingStandardCacheTimeout 3600
    SSLStaplingErrorCacheTimeout 600
    SSLStaplingReturnResponderErrors Off
</VirtualHost>

HAProxy:

frontend https-in
    bind *:443 ssl crt /etc/ssl/certs/example.com.pem
    
    # Enable OCSP stapling
    ssl OCSP-response on
    
    default_backend web-servers

Verifying OCSP Stapling

# Check OCSP stapling with OpenSSL
openssl s_client -connect example.com:443 -status -servername example.com

# Look for "OCSP Response Status: successful"
# and "OCSP Response Data:"

# Check with testssl
testssl --standard --ocsp example.com

# Verify certificate chain and OCSP
openssl verify -CAfile ca-bundle.crt -proxy_url http://proxy:8080 \
    -status_timeout 10 example.com.crt

Implementing OCSP Stapling in Code

import ssl
import socket
import OpenSSL
from datetime import datetime, timedelta


def fetch_ocsp_response(cert_path: str, issuer_path: str, ocsp_responder: str) -> bytes:
    """Fetch OCSP response from responder."""
    
    # Load certificates
    cert = OpenSSL.crypto.load_certificate(
        OpenSSL.crypto.FILETYPE_PEM,
        open(cert_path).read()
    )
    issuer = OpenSSL.crypto.load_certificate(
        OpenSSL.crypto.FILETYPE_PEM,
        open(issuer_path).read()
    )
    
    # Create OCSP request
    ocsp_req = OpenSSL.crypto.ocsp_create_request(cert, issuer)
    
    # Send request
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((ocsp_responder, 80))
    
    request = b'POST /ocsp HTTP/1.1\r\n'
    request += b'Host: {}\r\n'.format(ocsp_responder.encode())
    request += b'Content-Type: application/ocsp-request\r\n'
    request += b'Content-Length: {}\r\n\r\n'.format(len(ocsp_req)).encode()
    request += ocsp_req
    
    sock.sendall(request)
    response = sock.recv(4096)
    sock.close()
    
    # Extract OCSP response (simplified)
    return response


def staple_ocsp_response(cert_path: str, issuer_path: str) -> bytes:
    """Get OCSP response for stapling."""
    
    ocsp_responder = "ocsp.example.com"  # Configure your responder
    
    # Fetch fresh OCSP response
    return fetch_ocsp_response(cert_path, issuer_path, ocsp_responder)

Best Practices

Production Checklist

Practice Implementation
Enable OCSP stapling Reduce client-side load
Use reliable responders Monitor availability
Set appropriate cache times Balance freshness vs. performance
Implement fallback Use CRL when OCSP fails
Sign responses Prevent spoofing
Monitor responses Alert on revocation

Monitoring and Alerting

import schedule
import time


def monitor_ocsp_responders():
    """Monitor OCSP responder availability."""
    
    responders = [
        'http://ocsp.digicert.com',
        'http://ocsp.sectigo.com',
        'http://ocsp.pki.goog'
    ]
    
    import requests
    
    for responder in responders:
        try:
            start = time.time()
            response = requests.get(responder, timeout=5)
            elapsed = time.time() - start
            
            if response.status_code == 200:
                print(f"โœ“ {responder}: OK ({elapsed*1000:.0f}ms)")
            else:
                print(f"โœ— {responder}: HTTP {response.status_code}")
                
        except Exception as e:
            print(f"โœ— {responder}: {e}")


# Check every 5 minutes
schedule.every(5).minutes.do(monitor_ocsp_responders)

Troubleshooting Common Issues

Issue Solution
OCSP stapling not working Check nginx ssl_stapling_verify
Response too old Increase ssl_stapling_resolver valid time
Invalid signature Include CA bundle in ssl_trusted_certificate
Responder unreachable Configure fallback to CRL
Slow responses Use cache, enable stapling

Conclusion

OCSP is essential for modern certificate validation, providing real-time revocation checking that balances security with performance. By implementing OCSP stapling and proper monitoring, you ensure robust TLS certificate validation while minimizing the load on both clients and OCSP responders.

Key takeaways:

  1. OCSP is real-time: Provides current certificate status vs. CRL’s periodic updates
  2. Stapling is essential: Reduces latency and improves privacy
  3. Proper configuration matters: Ensure responders are reachable and responses are cached
  4. Monitor availability: OCSP responder downtime can break validation
  5. Have fallback: Use CRL when OCSP fails

By following the patterns and practices in this guide, you’ll build certificate validation systems that are secure, performant, and reliable.

Resources

Comments