2

I am trying to perform Mutual Authentication using java. I have tried with curl and it is working with the following commands:

curl --cert-type P12 --cert my-p12-file.p12:password https://server-url --header "Content-Type:application/json" --data '{"key":"value"}'

or

curl --cert client.crt --key my-key.pem --cacert RootCA.cer https://server-url --header "Content-Type:application/json" --data '{"key":"value"}'

Both commands are working fine and giving the proper output. I have tried the same functionality in Postman and it is working there as well. When I tried it programmatically it is working in nodejs but not in Java. I have followed many blogs/tutorials/SO answers but nothing has worked. Here is the Java code:

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLContext;
import java.io.File;
public class DemoSO {
 private static CloseableHttpClient httpClient;
 public static void main(String[] args) throws Exception {
 System.setProperty("javax.net.debug", "ssl");
 String trustStore = "root-certificate-truststore.jks";
 String keyStore = "keystore-v0.jks";
 String extraPwd = "password";
 SSLContext sslContext = SSLContexts.custom().
 loadKeyMaterial(new File(keyStore),extraPwd.toCharArray(),extraPwd.toCharArray())
 .loadTrustMaterial(new File(trustStore))
 .build();
 SSLConnectionSocketFactory sslConSocFactory = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
 httpClient = HttpClients.custom().setSSLSocketFactory(sslConSocFactory)
 .setSSLContext(sslContext)
 .build();
 HttpPost httpPost = new HttpPost("https://server-url");
 String requestBody = "{\"key\":\"value\"}";
 StringEntity entity = new StringEntity(requestBody);
 Header header = new BasicHeader("Content-Type", "application/json");
 entity.setContentType(header);
 httpPost.setHeader(header);
 httpPost.setEntity(entity);
 HttpResponse response = httpClient.execute(httpPost);
 for (Header allHeader : response.getAllHeaders()) {
 System.out.println(allHeader.toString());
 }
 System.out.println(response.getAllHeaders().toString());
 System.out.println(response.getStatusLine());
 System.out.println(EntityUtils.toString(response.getEntity()));
 }
}

The above code sends a POST request to https://server-url. The trustStore was generated from the Root certificate using the following commands:

openssl x509 -inform der -in RootCA.cer -outform pem -out root-certificate.pem (Converted the .cer to .pem)

keytool -import -file root-certificate.pem -alias root-certificate -keystore root-certificate-truststore.jks

The keyStore was generated using the .p12 file, which was working fine through openssl, postman and node program.

keytool -importkeystore -srckeystore my-p12-file.p12 -destkeystore keystore-v0.jks -srcstoretype PKCS12 -deststoretype jks -deststorepass password

Any help or suggestion to implement in java will be appreciated.

Thanks.

[Edit1]

Forgot to add the response. It is giving 401 Unauthorized. This is the same error it was giving previously in cURL and postman , but when I passed the .p12 file it started working properly and giving 200 in the response code.

<ErrorCode>401-Unauthorized</ErrorCode>
<ErrorMessageCode>3103</ErrorMessageCode>
<ErrorMessage>Not enough authentication factor, 1 is required!</ErrorMessage> 

Debug mode shows the following error:

upcoming handshake states: client finished[20]
upcoming handshake states: server change_cipher_spec[-1]
upcoming handshake states: server finished[20]
*** ServerHelloDone
[read] MD5 and SHA1 hashes: len = 4
0000: 0E 00 00 00 ....
Warning: no suitable certificate found - continuing without client authentication
*** Certificate chain
<Empty>
***
update handshake state: certificate[11]
upcoming handshake states: client_key_exc
asked Jun 3, 2020 at 20:31
5
  • This code does not send the .p12 file, and there is no reason why it should. Please clarify. Commented Jun 4, 2020 at 0:03
  • Oh, that is something I am don't understanding that what changes it requires. I am missing something. First time I am implementing MA. What I am assuming is the keystore was generated from .p12 file, so it will have the required information. Commented Jun 4, 2020 at 6:14
  • 1
    That code looks right to me and with trivial changes works for me. (1) What specifically doesn't work? (2) What output do you get from javax.net.debug? (In java 11 up use ssl,keymanager,handshake rather than just ssl) @user207421: the client-side keystore isn't sent but it is used for authentication, assuming the server requests it which the server here apaprently does Commented Jun 4, 2020 at 7:52
  • I have added the output, its giving 401 Unauthorized, previously I was getting the same error with cURL and postman as well, but when passed it the .p12 file the error went and it was giving 200 with proper json in the response. Commented Jun 4, 2020 at 9:27
  • when you said: "I passed the .p12 file it started working properly and giving 200 in the response code." ... It means that Did you fix your problem? Commented Jun 11, 2020 at 15:30

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.