The TLS handshake is failing because the client doesn’t trust the server’s certificate. This usually means the certificate isn’t signed by a Certificate Authority (CA) that the client recognizes, or the certificate itself is malformed or expired.

Here are the common culprits and how to fix them:

1. Self-Signed Certificates

Diagnosis: Check the certificate details on the client. If it shows "Issuer: CN=your.server.name" (or similar, where the issuer is the same as the subject), it’s self-signed. You can also run:

openssl s_client -connect your.server.name:443 -showcerts < /dev/null 2>/dev/null | openssl x509 -noout -issuer -subject

Look for the issuer= and subject= lines to be identical.

Fix: The correct fix is to obtain a certificate signed by a trusted CA. For development or internal use, you can create your own CA and sign the server certificate with it. Then, import the new CA’s certificate into the client’s trust store.

Why it works: Clients have a pre-installed list of trusted root CAs. When a certificate is signed by one of these trusted CAs (or a CA whose own certificate is signed by a trusted CA), the client automatically trusts it. A self-signed certificate is its own root CA, which no client trusts by default.

2. Expired Certificates

Diagnosis: Examine the certificate’s "Not Before" and "Not After" dates. If the current date is outside this range, the certificate has expired or is not yet valid.

openssl s_client -connect your.server.name:443 < /dev/null 2>/dev/null | openssl x509 -noout -dates

Look for notBefore= and notAfter= lines.

Fix: Renew the certificate with your CA. If you are using a service like Let’s Encrypt, ensure your automated renewal process is working. For example, if using Certbot, check its logs (/var/log/letsencrypt/letsencrypt.log) for errors and rerun the renewal command:

sudo certbot renew

After renewal, you’ll likely need to reload your web server’s configuration (e.g., sudo systemctl reload nginx or sudo systemctl reload apache2).

Why it works: Certificates have a limited lifespan for security reasons. An expired certificate is no longer considered valid by browsers and clients because its cryptographic guarantees may have weakened or its associated keys may have been compromised.

3. Incorrectly Configured Intermediate Certificates

Diagnosis: The server might be sending its end-entity certificate but is missing the necessary intermediate CA certificate(s) in the chain. This is often visible in browser developer tools (Security tab) or by using openssl s_client:

openssl s_client -connect your.server.name:443 < /dev/null 2>/dev/null | openssl x509 -noout -text | grep -A 1 "Issuer:"

Compare the issuer of the server certificate with the issuer of the next certificate in the chain (if any are presented).

Fix: Ensure your web server (e.g., Nginx, Apache) is configured to serve the full certificate chain. For Nginx, this typically means concatenating the server certificate and intermediate certificates into a single file specified by the ssl_certificate directive. For example, ssl_certificate /etc/letsencrypt/live/your.server.name/fullchain.pem;.

Why it works: The client needs to be able to trace the server’s certificate back to a root CA it trusts. If an intermediate certificate is missing, the chain of trust is broken, and the client cannot verify the server’s identity.

4. Certificate Name Mismatch (Common Name or Subject Alternative Name)

Diagnosis: The hostname the client is trying to connect to (e.g., app.example.com) does not match any of the names listed in the certificate’s Common Name (CN) or Subject Alternative Name (SAN) fields.

openssl s_client -connect your.server.name:443 < /dev/null 2>/dev/null | openssl x509 -noout -text | grep -A 1 "Subject Alternative Name:"

Also check the CN:

openssl s_client -connect your.server.name:443 < /dev/null 2>/dev/null | openssl x509 -noout -subject

Compare these names against your.server.name.

Fix: Obtain a new certificate that includes all hostnames and IP addresses clients will use to access the server in the SAN field. For example, if clients access via www.example.com and app.example.com, both must be present. If using Let’s Encrypt with Certbot, ensure you specify all domains:

sudo certbot certonly --webroot -w /var/www/html -d your.server.name -d www.your.server.name

Then reload your web server.

Why it works: This is a fundamental security check. The certificate guarantees the identity of the server for the specific names listed within it. A mismatch means the client has no cryptographic assurance that it’s talking to the intended server.

5. Client Trust Store Issues

Diagnosis: The client might be missing the root CA certificate that signed the server’s certificate, even if the server’s certificate is correctly issued by a trusted CA. This is common in enterprise environments with custom CAs or on systems with minimal default trust stores.

Fix: Import the root CA certificate (and any intermediate CA certificates if not already present on the server) into the client’s operating system or application’s trust store. For example, on Debian/Ubuntu:

sudo cp your_ca.crt /usr/local/share/ca-certificates/your_ca.crt
sudo update-ca-certificates

Why it works: Explicitly adding the CA to the client’s trust store tells the client to trust certificates signed by that CA.

6. Certificate Revocation List (CRL) or Online Certificate Status Protocol (OCSP) Issues

Diagnosis: The server’s certificate might have been revoked by the issuing CA, but the client is unable to check this status. This can manifest as a CERTIFICATE_UNKNOWN error if the CRL/OCSP check fails or if the CA is unreachable.

Fix: If the certificate was revoked, you must obtain a new one. If the CA’s CRL distribution points or OCSP responders are unreachable from the client, you may need to configure proxy settings or firewall rules to allow access. In some cases, you might be able to disable CRL/OCSP checking on the client (though this reduces security).

Why it works: Revocation is a mechanism for invalidating a certificate before its expiry date, typically due to key compromise. If the client cannot verify that the certificate hasn’t been revoked, it cannot trust it.

The next error you’ll likely encounter if all certificate issues are resolved is a SSL_ERROR_SYSCALL if there’s a network connectivity problem or a HTTP 502 Bad Gateway if the upstream application is misconfigured.

Want structured learning?

Take the full Tls-ssl course →