Improper Check for Certificate Revocation

Description

Improper Check for Certificate Revocation is a vulnerability that occurs when a product does not check or incorrectly checks the revocation status of a certificate, which may cause it to use a certificate that has been compromised. Certificate revocation is a critical security mechanism that allows certificate authorities to invalidate certificates before their natural expiration when the certificate's private key has been compromised, the certificate was issued incorrectly, or the certificate subject is no longer trusted. Using a revoked certificate almost certainly indicates malicious activity, as legitimate servers should never present revoked certificates unless severely compromised or outdated.

Risk

Failing to check certificate revocation represents a particularly severe vulnerability because revoked certificates are typically associated with confirmed security incidents. When a certificate is revoked, it usually means the private key has been compromised - possibly through data breach, server compromise, or other security incident. Legitimate servers should never use revoked certificates, so encountering one strongly indicates either a misconfigured legitimate server or an active attack. The risk is amplified by the fact that certificate revocation lists (CRLs) and Online Certificate Status Protocol (OCSP) responses exist specifically to protect against compromised certificates, making their bypass highly dangerous. Router and device firmware that caches keys without checking later revocation allows attackers to continue using compromised certificates long after revocation.

Solution

Ensure all certificates undergo revocation status validation before being trusted. Implement Certificate Revocation List (CRL) checking to download and verify against the CA's list of revoked certificates. Alternatively or additionally, implement OCSP (Online Certificate Status Protocol) for real-time revocation checking. Consider OCSP stapling where the server provides a signed, time-stamped OCSP response with the certificate, reducing latency and privacy concerns. When implementing certificate pinning, fully validate all certificate properties including revocation status before pinning occurs. Handle cases where revocation information is unavailable - consider this a failure depending on security requirements. Cache revocation status appropriately while respecting freshness requirements.

Common Consequences

ImpactDetails
Access ControlScope: Access Control

Untrusted entities may receive trust designation when their certificates should have been rejected due to revocation. This enables impersonation using compromised certificates.
Integrity, ConfidentialityScope: Integrity, Confidentiality

Data from malicious sources using revoked certificates may be integrated into trusted systems. Attackers impersonating trusted entities using revoked certificates can access sensitive data.

Example Code

Vulnerable Code (C/OpenSSL)

The following examples demonstrate improper revocation checking:

// Vulnerable: No revocation checking
#include <openssl/ssl.h>
#include <openssl/x509.h>

int vulnerable_verify_cert(SSL *ssl) {
    X509 *cert = SSL_get_peer_certificate(ssl);

    if (cert) {
        // Vulnerable: Only checks if certificate exists, no verification
        // No call to SSL_get_verify_result()
        // No CRL or OCSP checking
        return 1;  // "Trusted" - but may be revoked!
    }

    return 0;
}

SSL_CTX* vulnerable_create_context() {
    SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());

    // Basic verification enabled
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
    SSL_CTX_set_default_verify_paths(ctx);

    // Vulnerable: No CRL checking configured
    // No OCSP checking configured

    return ctx;
}
# Vulnerable: Python without revocation checking
import ssl
import socket

def vulnerable_connect(hostname, port):
    # Python's default SSL context does not check revocation
    context = ssl.create_default_context()

    # No CRL or OCSP checking
    # ssl module has limited built-in revocation support

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    ssl_sock = context.wrap_socket(sock, server_hostname=hostname)
    ssl_sock.connect((hostname, port))

    # Certificate chain validated, but revocation NOT checked!
    return ssl_sock
// Vulnerable: Java without revocation checking
import javax.net.ssl.*;
import java.security.*;

public class VulnerableRevocationCheck {

    public static SSLContext createVulnerableContext() throws Exception {
        SSLContext ctx = SSLContext.getInstance("TLS");

        // Default TrustManager - no revocation checking enabled
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
        tmf.init((KeyStore) null);

        ctx.init(null, tmf.getTrustManagers(), null);

        // Vulnerable: Revocation checking not enabled
        // PKIXParameters.setRevocationEnabled(false) is default behavior
        // for many configurations

        return ctx;
    }
}

Fixed Code (C/OpenSSL)

// Fixed: Proper revocation checking with CRL
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>

SSL_CTX* secure_create_context_with_crl() {
    SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());

    // Enable verification
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
    SSL_CTX_set_default_verify_paths(ctx);

    // Fixed: Enable CRL checking
    X509_STORE *store = SSL_CTX_get_cert_store(ctx);

    // Enable CRL checking for all certificates in chain
    X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
                                X509_V_FLAG_CRL_CHECK_ALL);

    // Load CRL file (should be periodically updated)
    X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
    if (lookup) {
        X509_LOOKUP_load_file(lookup, "/etc/ssl/crl/ca-crl.pem", X509_FILETYPE_PEM);
    }

    return ctx;
}

// Fixed: OCSP checking callback
int ocsp_verify_callback(SSL *ssl, void *arg) {
    // Get OCSP response from server (stapled)
    const unsigned char *resp_der;
    long resp_len = SSL_get_tlsext_status_ocsp_resp(ssl, &resp_der);

    if (resp_len <= 0) {
        // No OCSP response provided - decide based on policy
        // For strict security, reject
        fprintf(stderr, "No OCSP response received\n");
        return 0;  // Reject if OCSP required
    }

    // Parse and verify OCSP response
    OCSP_RESPONSE *resp = d2i_OCSP_RESPONSE(NULL, &resp_der, resp_len);
    if (resp == NULL) {
        fprintf(stderr, "Failed to parse OCSP response\n");
        return 0;
    }

    int status = OCSP_response_status(resp);
    if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
        fprintf(stderr, "OCSP response status: %d\n", status);
        OCSP_RESPONSE_free(resp);
        return 0;
    }

    // Additional verification of OCSP response...
    // Check signature, check certificate status, etc.

    OCSP_RESPONSE_free(resp);
    return 1;
}

SSL_CTX* secure_create_context_with_ocsp() {
    SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());

    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
    SSL_CTX_set_default_verify_paths(ctx);

    // Fixed: Enable OCSP stapling verification
    SSL_CTX_set_tlsext_status_type(ctx, TLSEXT_STATUSTYPE_ocsp);
    SSL_CTX_set_tlsext_status_cb(ctx, ocsp_verify_callback);

    return ctx;
}

int secure_verify_cert(SSL *ssl, const char *hostname) {
    X509 *cert = SSL_get_peer_certificate(ssl);

    if (cert == NULL) {
        return 0;
    }

    // Check basic verification
    long result = SSL_get_verify_result(ssl);
    if (result != X509_V_OK) {
        // This includes X509_V_ERR_CERT_REVOKED if CRL checking enabled
        if (result == X509_V_ERR_CERT_REVOKED) {
            fprintf(stderr, "SECURITY: Certificate has been REVOKED\n");
        }
        fprintf(stderr, "Certificate verification failed: %s\n",
                X509_verify_cert_error_string(result));
        X509_free(cert);
        return 0;
    }

    // Hostname verification
    if (X509_check_host(cert, hostname, strlen(hostname), 0, NULL) != 1) {
        X509_free(cert);
        return 0;
    }

    X509_free(cert);
    return 1;
}
// Fixed: Java with revocation checking enabled
import javax.net.ssl.*;
import java.security.*;
import java.security.cert.*;

public class SecureRevocationCheck {

    public static SSLContext createSecureContext() throws Exception {
        // Create PKIXParameters with revocation checking
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");

        // Get system trust store
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null, null);  // Initialize empty, will use system certs

        // Configure PKIX parameters with revocation
        PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(
            trustStore, new X509CertSelector());

        // Fixed: Enable revocation checking
        pkixParams.setRevocationEnabled(true);

        // Configure CRL or OCSP
        // Option 1: Enable OCSP
        Security.setProperty("ocsp.enable", "true");

        // Option 2: Configure CRL
        System.setProperty("com.sun.security.enableCRLDP", "true");

        // Create manager factory parameters
        ManagerFactoryParameters mfp = new CertPathTrustManagerParameters(pkixParams);

        tmf.init(mfp);

        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(null, tmf.getTrustManagers(), null);

        return ctx;
    }

    public static void secureConnect(String hostname, int port) throws Exception {
        SSLContext ctx = createSecureContext();
        SSLSocketFactory factory = ctx.getSocketFactory();

        try (SSLSocket socket = (SSLSocket) factory.createSocket(hostname, port)) {
            SSLParameters params = socket.getSSLParameters();
            params.setEndpointIdentificationAlgorithm("HTTPS");
            socket.setSSLParameters(params);

            socket.startHandshake();

            // If we get here, certificate is valid AND not revoked
            // (CertPathValidatorException thrown if revoked)
        } catch (SSLHandshakeException e) {
            if (e.getCause() instanceof CertPathValidatorException) {
                CertPathValidatorException cpve = (CertPathValidatorException) e.getCause();
                if (cpve.getReason() == CertPathValidatorException.BasicReason.REVOKED) {
                    System.err.println("SECURITY: Certificate has been REVOKED");
                }
            }
            throw e;
        }
    }
}

The fix enables CRL and/or OCSP checking to verify certificate revocation status before trusting certificates.


Exploited in the Wild

LDAP-over-SSL Revocation Bypass (Enterprise Systems, 2011)

CVE-2011-2014 documented LDAP-over-SSL implementations that failed to check Certificate Revocation Lists, allowing continued use of revoked certificates for authentication.

Browser Intermediate Certificate Revocation (Web Browsers, 2009)

CVE-2009-3046 documented web browsers that didn't check revocation for intermediate certificates, only end-entity certificates, allowing attacks using revoked CA certificates.

Router Key Caching (Network Equipment, 2011)

CVE-2011-0935 documented routers that cached certificate keys without checking for later revocation, allowing continued use of revoked certificates.


Tools to Test/Exploit

  • testssl.sh — Command line tool for testing SSL/TLS including OCSP and CRL checking.

  • openssl ocsp — Tool for testing OCSP responses.

  • revoked.badssl.com — Test site with revoked certificate for testing.


CVE Examples

  • CVE-2011-2014 — LDAP-over-SSL failed to check Certificate Revocation Lists.

  • CVE-2009-3046 — Web browser didn't check intermediate certificate revocation.

  • CVE-2011-0935 — Router cached keys, bypassing later revocation checks.

  • CVE-2006-4409 — Revocation list inaccessible through HTTP proxies.


References

  1. MITRE Corporation. "CWE-299: Improper Check for Certificate Revocation." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/299.html

  2. RFC 5280. "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile." https://tools.ietf.org/html/rfc5280

  3. RFC 6960. "X.509 Internet Public Key Infrastructure Online Certificate Status Protocol - OCSP." https://tools.ietf.org/html/rfc6960