OpenSSL default handling of expired client certificates during mutual TLS
0 reputation · 20 Jun 2022, 04:33 UTC
0 reputation · 20 Jun 2022, 04:33 UTC
The goal is to enforce least‑privilege authentication by ensuring that a TLS server rejects connections when the client presents an expired certificate, even when SSL_VERIFY_PEER is set.
OpenSSL completes the handshake and stores the error X509_V_ERR_CERT_HAS_EXPIRED in the verification result, but it does not automatically abort the connection. The application must examine SSL_get_verify_result() (or provide a custom verify_callback) to decide whether to continue. This leaves an unresolved policy decision about whether the library should treat expiration as a fatal alert by default or rely solely on application‑level checks.
What verification flag or callback configuration would cause OpenSSL to treat an expired client certificate as a fatal error without requiring explicit application logic? Should developers enable additional verify modes, or is the current approach of checking SSL_get_verify_result() the recommended practice for least‑privilege enforcement?
There is no single OpenSSL verification flag that automatically treats an expired client certificate as a fatal handshake error. The library records X509_V_ERR_CERT_HAS_EXPIRED in the verification result but completes the handshake unless a custom verify_callback returns 0 for that error.
OpenSSL's design separates policy from mechanism. SSL_VERIFY_PEER enables validation, and SSL_VERIFY_FAIL_IF_NO_PEER_CERT ensures a certificate is presented, but neither converts expiration into a fatal alert. The application must decide whether to abort.
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);verify_callback to return 0 when X509_V_ERR_CERT_HAS_EXPIRED is seen:int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
int err = X509_STORE_CTX_get_error(ctx);
if (err == X509_V_ERR_CERT_HAS_EXPIRED) {
return 0; // abort handshake
}
return preverify_ok;
}
openssl req -new -x509 -days -1 -keyout expired.key -out expired.crtopenssl s_server -verify_return_error -CAfile ca.crt -cert server.crt -key server.key and connect using the expired certificate.Behavior of error stacking differs slightly between OpenSSL 1.1.1 and 3.x. If you are targeting a specific version, confirm the callback receives the expected error code.
Which OpenSSL version (1.1.1, 3.0, 3.1, 3.2) is your deployment target? The callback logic is the same, but internal error handling may affect edge cases.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 20 Jun 2022, 10:40 UTC
When OpenSSL encounters X509_V_ERR_CERT_HAS_EXPIRED it does not automatically send a fatal TLS alert. Instead, it records the error, sends a warning‑level alert (alert level warning), and allows the handshake to finish. Application data can therefore be exchanged before the server checks SSL_get_verify_result() or acts on a verify_callback. To prevent any data from being sent, the callback must return 0 for that error, which upgrades the alert to fatal and aborts the handshake before the encrypted application payload is processed.