Confluence and Crowd - TLS accepts expired certificate in Java
Platform Notice: Data Center Only - This article only applies to Atlassian products on the Data Center platform.
Note that this KB was created for the Data Center version of the product. Data Center KBs for non-Data-Center-specific features may also work for Server versions of the product, however they have not been tested. Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.
*Except Fisheye and Crucible
Summary
When connecting Confluence and Crowd using TLS (HTTPS), it is essential to import the application's SSL certificate to prevent connection failures (PKIX errors).
In certain scenarios, if you are using a server certificate (rather than a CA certificate), Confluence and Crowd may continue to operate with expired TLS certificates. This is considered not optimal.
Diagnosis
There are several ways to check your certificate.
You can verify the certificate validity date by using the web browser or by using the following OpenSSL command.
openssl s_client -showcerts -servername <Server CN or FQDN> -connect <Server CN or FQDN>:443 | openssl x509 -noout -dates
Please change <Server CN or FQDN> to match your server address like atlassian.net
With org.apache.http debug logs enabled, we don't see it verifying the certificate expiry date.
2024-09-09 13:10:02,229 DEBUG [http-nio-8090-exec-8 url: /confluence/rest/applinks/3.0/status/7422c381-13db-386b-a0d9-438bcea07c12; user: admin] [http.conn.ssl.SSLConnectionSocketFactory] createLayeredSocket Starting handshake
2024-09-09 13:10:02,230 DEBUG [AppLinks ConcurrentExecutor:thread-2] [http.conn.ssl.SSLConnectionSocketFactory] createLayeredSocket Enabled protocols: [TLSv1.3, TLSv1.2]
...
2024-09-09 13:10:02,231 DEBUG [AppLinks ConcurrentExecutor:thread-2] [http.conn.ssl.SSLConnectionSocketFactory] createLayeredSocket Starting handshake
2024-09-09 13:10:02,272 DEBUG [AppLinks ConcurrentExecutor:thread-2] [http.conn.ssl.SSLConnectionSocketFactory] verifyHostname Secure session established
2024-09-09 13:10:02,272 DEBUG [AppLinks ConcurrentExecutor:thread-2] [http.conn.ssl.SSLConnectionSocketFactory] verifyHostname negotiated protocol: TLSv1.3
2024-09-09 13:10:02,272 DEBUG [AppLinks ConcurrentExecutor:thread-2] [http.conn.ssl.SSLConnectionSocketFactory] verifyHostname negotiated cipher suite: TLS_AES_128_GCM_SHA256
2024-09-09 13:10:02,272 DEBUG [AppLinks ConcurrentExecutor:thread-2] [http.conn.ssl.SSLConnectionSocketFactory] verifyHostname peer principal: CN=test.com, O=Internet Widgits Pty Ltd, ST=Some-State, C=AU
2024-09-09 13:10:02,272 DEBUG [AppLinks ConcurrentExecutor:thread-2] [http.conn.ssl.SSLConnectionSocketFactory] verifyHostname issuer principal: CN=test.com, O=Internet Widgits Pty Ltd, ST=Some-State, C=AU
...
2024-09-09 13:10:02,273 DEBUG [AppLinks ConcurrentExecutor:thread-2] [http.impl.conn.DefaultHttpClientConnectionOperator] connect Connection established 172.50.0.4:34142<->172.50.0.5:443
...
2024-09-09 13:10:02,280 DEBUG [http-nio-8090-exec-8 url: /confluence/rest/applinks/3.0/status/7422c381-13db-386b-a0d9-438bcea07c12; user: admin] [http.conn.ssl.SSLConnectionSocketFactory] verifyHostname Secure session established
2024-09-09 13:10:02,280 DEBUG [http-nio-8090-exec-8 url: /confluence/rest/applinks/3.0/status/7422c381-13db-386b-a0d9-438bcea07c12; user: admin] [http.conn.ssl.SSLConnectionSocketFactory] verifyHostname negotiated protocol: TLSv1.3
2024-09-09 13:10:02,280 DEBUG [http-nio-8090-exec-8 url: /confluence/rest/applinks/3.0/status/7422c381-13db-386b-a0d9-438bcea07c12; user: admin] [http.conn.ssl.SSLConnectionSocketFactory] verifyHostname negotiated cipher suite: TLS_AES_128_GCM_SHA256
Cause
Such behavior is correct ("as designed") if the certificate itself is listed in the truststore of the verifying party.
When the checked certificate is directly listed in the truststore, the certpath validation is skipped in Java:
It doesn't contradict the Section 6 in RFC 5280
As a result, not-yet-valid and expired certificates are accepted (considered valid) when listed directly in the Java truststore.
Solution
If you want to have the certificate validity checked during the TLS handshake, then we need to remove the server certificate and add the issuing CA's certificate into the truststore. Don't place there the server certificate itself.
We can use the java keytool to remove the server certificate. The following command to list all imported certificates and their expiration date:
keytool -list -v -keystore <path to your cacerts> |grep -E '^Alias name:|^Valid
Then remove the old server certificate by using:
keytool -delete -noprompt -alias confluence -keystore <path to your cacerts>
Lastly, we can import the CA certificate by using:
keytool -importcert -alias my-ca -keystore <path to your cacerts> -file <your CA certificate file>
Remember to change <path to your cacerts>, <your CA certificate file> to match yours.
In the import command we are using my-ca as an alias, you can change it as needed.
Now if the certificate expire, the connection will fail with the PKIX error. Like this:
Security logs:
2024-09-09 14:56:11,985 ERROR [Caesium-1-2] [atlassian.crowd.directory.DbCachingDirectoryPoller] pollChanges Error occurred while refreshing the cache for directory [ 393218 ].
com.atlassian.crowd.exception.OperationFailedException: javax.net.ssl.SSLHandshakeException: PKIX path validation failed: java.security.cert.CertPathValidatorException: validity check failed
...
Caused by: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: validity check failed
...
Caused by: java.security.cert.CertificateExpiredException: NotAfter: Sat Sep 07 13:00:00 UTC 2024
Confluence debug logs:
2024-09-09 14:56:11,809 DEBUG [Caesium-1-2] [http.conn.ssl.SSLConnectionSocketFactory] createLayeredSocket Starting handshake
2024-09-09 14:56:11,851 DEBUG [Caesium-1-2] [http.impl.conn.DefaultManagedHttpClientConnection] shutdown http-outgoing-54: Shutdown connection
2024-09-09 14:56:11,851 DEBUG [Caesium-1-2] [http.impl.execchain.MainClientExec] abortConnection Connection discarded
Notes
https://confluence.atlassian.com/doc/running-confluence-over-ssl-or-https-161203.html
How to import a public SSL certificate into a JVM
How to import an existing SSL certificate for use in Tomcat