Quantcast
Channel: Active questions tagged https - Stack Overflow
Viewing all articles
Browse latest Browse all 1506

Mutual Authentication via certificate exchange failing in Java: SSLHandshakeException: Remote host terminated the handshake

$
0
0

I've built a Java client to a HTTP server protected with mutual authentication. This is not the first time I do this, but this is the first time I had this problem.The application is a Spring Boot with OpenFeign, but I've reduced this problem to a simple pure Java HttpClient.


Edit:It appears that the problem is not a mismatch of signature algorithms as stated below. The problem is that the client certificate is not being sent for some unknown reason...

Additionally to the methods described bellow, I also tried to load the certificate and key through their DER files... with the same error...

JDK11 HttpClient mutual tls


It appears that the problem is a mismatch of signature algorithms. Here's a piece of log (-Djavax.net.debug=ssl:handshake):

javax.net.ssl|DEBUG|51|HttpClient-1-Worker-0|2024-05-03 14:33:06.372 BRT|CertificateRequest.java:690|Consuming CertificateRequest handshake message ("CertificateRequest": {"certificate types": [rsa_sign, dss_sign, ecdsa_sign]"supported signature algorithms": [ecdsa_secp521r1_sha512, rsa_pkcs1_sha512, ecdsa_secp384r1_sha384, rsa_pkcs1_sha384, ecdsa_secp256r1_sha256, rsa_pkcs1_sha256, dsa_sha256, ecdsa_sha224, rsa_sha224, dsa_sha224, ecdsa_sha1, rsa_pkcs1_sha1, dsa_sha1]"certificate authorities": [...]})javax.net.ssl|ALL|51|HttpClient-1-Worker-0|2024-05-03 14:33:06.376 BRT|X509Authentication.java:221|No X.509 cert selected for [EC, RSA, DSA]javax.net.ssl|WARNING|51|HttpClient-1-Worker-0|2024-05-03 14:33:06.376 BRT|CertificateRequest.java:781|No available authentication schemejavax.net.ssl|DEBUG|51|HttpClient-1-Worker-0|2024-05-03 14:33:06.377 BRT|ServerHelloDone.java:151|Consuming ServerHelloDone handshake message (<empty>)javax.net.ssl|DEBUG|51|HttpClient-1-Worker-0|2024-05-03 14:33:06.377 BRT|CertificateMessage.java:293|No X.509 certificate for client authentication, use empty Certificate message insteadjavax.net.ssl|DEBUG|51|HttpClient-1-Worker-0|2024-05-03 14:33:06.377 BRT|CertificateMessage.java:324|Produced client Certificate handshake message ("Certificates": <empty list>)

When verifying the certificate information, the signing algorithm is "SHA256withRSA" which is not present in the list above.

But, (and here comes the odd part) some other tests I do work.

  • Curl informing the certificate and key works
  • Insomnia Rest with certificate and key works
  • Postman with .p12 (PKCS12 / PFX) (the same configured in Java) works

And printing the server's SSL info with OpenSSL, the signature algorithms is different from the list I got with Java.

openssl s_client -connect xxxxx.com:443...Acceptable client certificate CA names...Client Certificate Types: RSA sign, DSA sign, ECDSA signRequested Signature Algorithms: ECDSA+SHA512:RSA+SHA512:ECDSA+SHA384:RSA+SHA384:ECDSA+SHA256:RSA+SHA256:DSA+SHA256:ECDSA+SHA224:RSA+SHA224:DSA+SHA224:ECDSA+SHA1:RSA+SHA1:DSA+SHA1Shared Requested Signature Algorithms: ECDSA+SHA512:RSA+SHA512:ECDSA+SHA384:RSA+SHA384:ECDSA+SHA256:RSA+SHA256:DSA+SHA256:ECDSA+SHA224:RSA+SHA224:DSA+SHA224Peer signing digest: SHA256Peer signature type: RSAServer Temp Key: ECDH, prime256v1, 256 bits...

Shouldn't these "signature algorithms" be the same? What am I missing here?

I tried to configure my certificate using Java Properties

      System.setProperty("javax.net.ssl.trustStore", "trust.p12");      System.setProperty("javax.net.ssl.trustStorePassword", "password");      System.setProperty("javax.net.ssl.trustStoreType", "PKCS12");      System.setProperty("javax.net.ssl.keyStore", "keys.p12");      System.setProperty("javax.net.ssl.keyStorePassword", "password");      System.setProperty("javax.net.ssl.keyStoreType", "PKCS12");

And programmatically

        KeyStore keyStore = KeyStore.getInstance("PKCS12");        keyStore.load(new FileInputStream("keys.p12"), "password".toCharArray());        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");        kmf.init(keyStore, "password".toCharArray());        KeyStore truststore = KeyStore.getInstance("PKCS12");        truststore.load(new FileInputStream("trust.p12"), "password".toCharArray());        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");        tmf.init(truststore);        SSLContext sslContext = SSLContext.getInstance("SSL");        sslContext.init(kmf.getKeyManagers(), trustAllCerts, new SecureRandom());        HttpClient httpClient = HttpClient.newBuilder().sslContext(sslContext).build();        String endpoint = "https://xxxxx.com/v1/list";        String json = "{\"test\": \"test\"}";        HttpRequest.BodyPublisher requestBody = HttpRequest.BodyPublishers.ofString(json, StandardCharsets.UTF_8);        HttpRequest httpRequest = HttpRequest.newBuilder()                .uri(URI.create(endpoint))                .POST(requestBody)                .setHeader("Content-Type", "application/json")                .build();        HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());

Both tries (java 17 and 21) resulted in

Exception in thread "main" javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake    at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:956)    at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:133)    at org.example.SslTest2.main(SslTest2.java:65)Caused by: javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake    at java.net.http/jdk.internal.net.http.common.SSLTube.checkForHandshake(SSLTube.java:595)    at java.net.http/jdk.internal.net.http.common.SSLTube$SSLTubeFlowDelegate.checkForHandshake(SSLTube.java:156)    at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate$Reader.errorCommon(SSLFlowDelegate.java:369)    at java.net.http/jdk.internal.net.http.common.SubscriberWrapper.onError(SubscriberWrapper.java:412)    at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$ReadSubscription.signalCompletion(SocketTube.java:645)    at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$InternalReadSubscription.read(SocketTube.java:829)    at java.net.http/jdk.internal.net.http.SocketTube$SocketFlowTask.run(SocketTube.java:181)    at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:207)    at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:280)    at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:233)    at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$InternalReadSubscription.signalReadable(SocketTube.java:782)    at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$ReadEvent.signalEvent(SocketTube.java:965)    at java.net.http/jdk.internal.net.http.SocketTube$SocketFlowEvent.handle(SocketTube.java:253)    at java.net.http/jdk.internal.net.http.HttpClientImpl$SelectorManager.handleEvent(HttpClientImpl.java:1467)    at java.net.http/jdk.internal.net.http.HttpClientImpl$SelectorManager.lambda$run$3(HttpClientImpl.java:1412)    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)    at java.net.http/jdk.internal.net.http.HttpClientImpl$SelectorManager.run(HttpClientImpl.java:1412)Caused by: java.net.SocketException: Connection reset    at java.base/sun.nio.ch.SocketChannelImpl.throwConnectionReset(SocketChannelImpl.java:401)    at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:434)    at java.net.http/jdk.internal.net.http.SocketTube.readAvailable(SocketTube.java:1178)    at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$InternalReadSubscription.read(SocketTube.java:841)    ... 11 more

Viewing all articles
Browse latest Browse all 1506

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>