Error Medic

How to Check OpenVPN Certificate Expiration: Fix 'VERIFY ERROR: certificate has expired'

Fix OpenVPN connection failures caused by expired certificates. Learn how to check client, server, and CA certificate expiration dates using OpenSSL.

Last updated:
Last verified:
1,465 words
Key Takeaways
  • Expired certificates trigger 'VERIFY ERROR: depth=0, error=certificate has expired' and TLS handshake failures.
  • Client, server, and Certificate Authority (CA) certificates all have distinct expiration dates that must be monitored.
  • Use the 'openssl x509' command-line tool to quickly inspect the 'notAfter' date of any OpenVPN .crt or .pem file.
  • Implement proactive monitoring via cron or Nagios/Zabbix to catch expiring certificates before they cause VPN downtime.
Diagnostic Approaches Compared
MethodWhen to UseTime requiredRisk / Complexity
OpenSSL CLI (`openssl x509`)Directly inspecting known certificate files on the server or client.1 minuteLow
OpenVPN Log InspectionWhen clients report sudden connection drops and you need to confirm the root cause.5 minutesLow
Automated Monitoring ScriptProactively alerting the team 30-60 days before a certificate expires.1-2 hoursMedium
Easy-RSA CheckManaging certificates via an existing Easy-RSA PKI infrastructure.2 minutesLow

Understanding OpenVPN Certificate Expiration

OpenVPN relies heavily on a Public Key Infrastructure (PKI) using TLS/SSL to authenticate connections and encrypt data. In this architecture, you typically have three types of certificates:

  1. The Certificate Authority (CA) Certificate: The root certificate that signs all other certificates. If this expires, the entire VPN infrastructure fails.
  2. The Server Certificate: Presented by the OpenVPN server to clients to prove its identity.
  3. The Client Certificates: Presented by connecting clients to the server for authentication.

By default, tools like easy-rsa generate client and server certificates valid for 10 years (3650 days), but many organizations reduce this to 1 or 2 years for security compliance. When a certificate passes its notAfter date, it becomes invalid.

Symptoms and Error Messages

When a certificate expires, users will typically experience sudden connection failures. The OpenVPN client GUI will stay stuck on "Connecting..." or "Waiting for server..." before eventually timing out.

If you inspect the OpenVPN client or server logs (usually located at /var/log/openvpn/openvpn.log or /var/log/syslog on Linux, or in the OpenVPN Connect GUI), you will see one of the following exact error messages:

Client-side log when the server certificate has expired:

VERIFY ERROR: depth=0, error=certificate has expired: C=US, ST=CA, L=SanFrancisco, O=MyCompany, OU=IT, CN=server
OpenSSL: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed
TLS_ERROR: BIO read tls_read_plaintext error
TLS Error: TLS object -> incoming plaintext read error
TLS Error: TLS handshake failed

Server-side log when a client certificate has expired:

192.168.1.100:54321 VERIFY ERROR: depth=0, error=certificate has expired: C=US, ST=CA, L=SanFrancisco, O=MyCompany, OU=IT, CN=client1
192.168.1.100:54321 OpenSSL: error:1417C086:SSL routines:tls_process_client_certificate:certificate verify failed
192.168.1.100:54321 TLS_ERROR: BIO read tls_read_plaintext error
192.168.1.100:54321 TLS Error: TLS object -> incoming plaintext read error
192.168.1.100:54321 TLS Error: TLS handshake failed

Another common symptom is the generic TLS timeout error if the connection simply drops the packet due to a failed verification: TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity)

Step 1: Locate Your Certificates

Before you can check the expiration dates, you need to find the .crt (or .pem) files.

On a standard Linux OpenVPN server, these are usually defined in your server.conf file (e.g., /etc/openvpn/server.conf). Look for these lines:

ca /etc/openvpn/ca.crt
cert /etc/openvpn/server.crt
key /etc/openvpn/server.key

For clients, the certificates are often embedded directly inside an .ovpn profile under <ca> and <cert> tags, or stored alongside it.

Step 2: Check Expiration Dates with OpenSSL

The most reliable way to check certificate expiration is using the OpenSSL command-line tool. OpenSSL can parse x509 certificates and print human-readable dates.

Run the following command against your server certificate:

openssl x509 -enddate -noout -in /etc/openvpn/server.crt

Output: notAfter=Oct 25 14:32:00 2026 GMT

The notAfter date is the exact moment the certificate expires. You should also check the notBefore date to ensure the certificate is currently valid (e.g., if there's a clock skew issue).

openssl x509 -dates -noout -in /etc/openvpn/server.crt

Output:

notBefore=Oct 26 14:32:00 2023 GMT
notAfter=Oct 25 14:32:00 2026 GMT

Step 3: Extracting and Checking Embedded .ovpn Certificates

If you only have an .ovpn file with embedded certificates, you cannot pass the whole file directly to openssl x509 because it contains extra configuration text. You must extract the certificate block first.

You can do this manually by copying the text between <cert> and </cert> into a new file named client.crt, or use sed to pipe it directly into OpenSSL:

sed -n '/<cert>/,/<\/cert>/p' client.ovpn | sed '1d;$d' | openssl x509 -enddate -noout

Step 4: Using Easy-RSA to Check Status

If you manage your certificates using the easy-rsa utility, you can check the status of all issued certificates using the index.txt file located in your Easy-RSA pki directory.

Cat the index file:

cat /etc/openvpn/easy-rsa/pki/index.txt

The lines in index.txt look like this: V 261025143200Z 01 unknown /CN=server

The fields are:

  1. Status: V (Valid), R (Revoked), E (Expired)
  2. Expiration Date: YYMMDDHHMMSSZ (e.g., 261025143200Z is Oct 25, 2026)
  3. Revocation Date (if applicable)
  4. Serial Number
  5. Unknown
  6. Distinguished Name (e.g., /CN=server)

Step 5: Fixing Expired Certificates

If a certificate has expired, it cannot be extended or renewed in place. You must generate a new certificate and distribute it.

For a Client Certificate:

  1. Revoke the old certificate (optional but recommended for cleanliness): ./easyrsa revoke client1
  2. Generate a new certificate: ./easyrsa build-client-full client1 nopass
  3. Package the new .crt (and new .key) into a fresh .ovpn file.
  4. Distribute the new profile to the user.

For a Server Certificate:

  1. Generate a new server certificate: ./easyrsa build-server-full server nopass
  2. Copy the new server.crt and server.key to your OpenVPN directory (e.g., /etc/openvpn/).
  3. Restart the OpenVPN service: systemctl restart openvpn@server

For a CA Certificate: If your CA expires, you must rebuild your entire PKI. This involves generating a new CA, generating new server certificates, generating new client certificates for every user, and distributing new .ovpn files to everyone. This is highly disruptive, which is why CA certificates are typically issued with 10 to 20-year lifespans.

Frequently Asked Questions

bash
# --- Diagnostics: Check Expiration Dates ---

# 1. Check the expiration date of the OpenVPN server certificate
openssl x509 -enddate -noout -in /etc/openvpn/server.crt

# 2. Check the expiration date of the Certificate Authority (CA)
openssl x509 -enddate -noout -in /etc/openvpn/ca.crt

# 3. Check both the start and end dates
openssl x509 -dates -noout -in /etc/openvpn/server.crt

# 4. Check an inline certificate embedded within an .ovpn profile
sed -n '/<cert>/,/<\/cert>/p' myprofile.ovpn | sed '1d;$d' | openssl x509 -enddate -noout


# --- Proactive Monitoring Script ---
# Save as /usr/local/bin/check_openvpn_certs.sh and run via cron
# Warns if any .crt file in the directory expires in less than 30 days (2592000 seconds)

#!/bin/bash
CERT_DIR="/etc/openvpn"
WARN_DAYS=30
WARN_SECONDS=$((WARN_DAYS * 86400))

for cert in "$CERT_DIR"/*.crt; do
    if [ -f "$cert" ]; then
        # Get expiration date in seconds since epoch
        EXP_DATE=$(openssl x509 -enddate -noout -in "$cert" | cut -d= -f2)
        EXP_SECS=$(date -d "$EXP_DATE" +%s)
        NOW_SECS=$(date +%s)
        DIFF_SECS=$((EXP_SECS - NOW_SECS))

        if [ $DIFF_SECS -lt 0 ]; then
            echo "CRITICAL: Certificate $cert has EXPIRED!"
        elif [ $DIFF_SECS -lt $WARN_SECONDS ]; then
            DAYS_LEFT=$((DIFF_SECS / 86400))
            echo "WARNING: Certificate $cert expires in $DAYS_LEFT days."
        else
            echo "OK: $cert is valid."
        fi
    fi
done
E

Error Medic Editorial

A dedicated team of senior DevOps and Site Reliability Engineers specializing in infrastructure troubleshooting, secure networking, and highly available Linux deployments.

Sources

Related Guides