Spring Application raises bad_certificate error when connecting to remote endpoint over mutual TLS
search cancel

Spring Application raises bad_certificate error when connecting to remote endpoint over mutual TLS

book

Article ID: 294516

calendar_today

Updated On:

Products

VMware Spring Runtime

Issue/Introduction

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]
...

Environment


Cause

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.

Resolution

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.