When Spring app deployed with Java Buildpack fails to complete SSL handshake with remote endpoint outside TAS Platform, it raises error "Received fatal alert: bad_certificate" as below:
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) ~[na:1.8.0_152] at sun.security.ssl.Alerts.getSSLException(Alerts.java:154) ~[na:1.8.0_152] at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2033) ~[na:1.8.0_152] at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1135) ~[na:1.8.0_152] at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385) ~[na:1.8.0_152] at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413) ~[na:1.8.0_152] at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397) ~[na:1.8.0_152] at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559) ~[na:1.8.0_152] ...
After enabling SSL debug logging, the problem surfaces because the server has mutual TLS enabled and the application is using diego instance certificate by default.
In case of mutual TLS handshake, client(the Spring application in this scenario) not only verify remote certificate, but also sends client certificate for remote to verify. If the remove side can not verify the client certificate with its configured Certificate Authority, "bad_certificate" will be returned.
By default the java buildpack adds the required root ca certs and client certificate(diego instance certificate). The restTemplate will source these certs and use them as the default HTTP client.
Use a Custom HTTP Client
Using a custom HTTP client is an option that can be used to override default settings provided by the system. One way to do that is to build your own HTTP client and define the SSL context that suits your needs. Here is an example of that:
HttpClientBuilder httpClientBuilder = HttpClients.custom() .setSSLContext(SSLContext.getDefault()) .useSystemProperties(); restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClientBuilder.build())
Change the Default Client Certs
As per the java buildpack docs, users can override the cert location using environmental variables.