sun.security.validator.ValidatorException: PKIX path building failed - java

I have Created CSR request using this command :
openssl req -out certificatecsr.csr -new -newkey rsa:2048 -keyout certificatekey.key
After that CA has shared certificate(.cer) file with me.
Now after that i have converted .cer file to .p12 using key.
Creating a .p12 certificate using cer sent by CA and private key
C:\Java\jdk1.6.0_38\jre\bin>openssl pkcs12 -export -in C:\Users\asharma1\cert.cer -inkey certificatekey.key -out
certi.p12
Creating JKS keystore :
keytool -genkey -alias quid -keystore quid.jks
importing .p12 certificate into jks keystore
C:\Java\jdk1.6.0_38\jre\bin>keytool -v -importkeystore -srckeystore C:\OpenSSL-Win64\bin\certi.p12 -srcstoretype PKCS12
-destkeystore quid.jks -deststoretype JKS
but when i am referring this JKS from my java code i am getting this error :
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I have also added cer file to cacerts.but still getting the same error.
As far as JAVA code is concerned i am refering this link to refer my own created keystore :
http://jcalcote.wordpress.com/2010/06/22/managing-a-dynamic-java-trust-store/
public SSLContext getSSLContext(String tspath)
throws Exception {
TrustManager[] trustManagers = new TrustManager[] {
new ReloadableX509TrustManager(tspath)
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, null);
return sslContext;
}
SSLContext sslContext=getSSLContext("C:\\Java\\jdk1.6.0_38\\jre\\bin\\quid.jks");
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
URL pickUrl = new URL(pickupLocation);
URLConnection urlConn = pickUrl.openConnection();
HttpsURLConnection httpsURLConn = (HttpsURLConnection)urlConn;
httpsURLConn.setSSLSocketFactory(socketFactory);
String encoding = urlConn.getContentEncoding();
InputStream is = urlConn.getInputStream();
InputStreamReader streamReader = new InputStreamReader(is, encoding != null
? encoding : "UTF-8");
Please note i am not using any server. I am trying ti run above written code thorugh main method only.
Please let me know what need to be done.
Why do i need to convert my .cer file to .p12 file ?

I would suggest you import CA certificate (or whole chain of CA and intermediate CAs) to keystore.
I think that p12 was imported fine. What I am suggesting is import of the chain to keystore. At least that is what the error message is saying.
I presume that:
the root CA in the chain is not trusted so chain building fails or
there is no AIA section in certificates in the chain so no certificates up to trusted root CA can be fetched so chain building fails or
the certificates are not being fetched based on AIA because it is not implemented in java (I am not a java programmer) so chain building fails
You could use portecle to import missing trusted CA certificates (not end entity cartificate that you have in .p12 or in separate .cer file that you received from issuing CA). It is more user friendly than keytool. Just follow this guide.

I would suggest you use the *.der format instead of the .p12 format.
Here's an overall summary of how to import certificates to fix the following error:
Error while trying to execute request.
javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target
How to import certificates
Go to URL in your browser, click on HTTPS certificate chain (little lock symbol next to URL address) to export the certificate
Click "more info" > "security" > "show certificate" > "details" > "export..".
Save as .der
Repeat for any certificates you need to import
Locate $JAVA_HOME/jre/lib/security/cacerts
Import all *.der files into the cacerts file using the following:
sudo keytool -import -alias mysitestaging -keystore $JAVA_HOME/jre/lib/security/cacerts -file staging.der
sudo keytool -import -alias mysiteprod -keystore $JAVA_HOME/jre/lib/security/cacerts -file prod.der
sudo keytool -import -alias mysitedev -keystore $JAVA_HOME/jre/lib/security/cacerts -file dev.der
The default keystore password is 'changeit'
You can view the change that you made with this command that shows the Certificate fingerprint.
keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts
If this doesn't solve the problem, try adding these java options as arguments:
-Djavax.net.ssl.trustStore="$JAVA_HOME/jre/lib/security/cacerts"
-Djavax.net.ssl.trustStorePassword="changeit"

Related

sun.security.validator.ValidatorException:PKIX path building failed

I am trying to reach an external API through a secured connection. The connection usually requires a client certificate issued by the company. The certificate has been whitelisted and I also checked with Postman by importing the certificate and it worked fine. I am getting sun.security.validator.ValidatorException when I try to reach the API.
I generated these files using the .crt file:
trustStore.jks-
"C:\Program Files\Java\jdk1.8.0_341\bin\keytool" -import -file "C:/Users/user/certs/example.crt" -alias exampleCA -keystore "C:/Users/user/certs/truststore.jks"
2.keyStore.p12-
openssl pkcs12 -export -in "C:/Users/user/certs/example.crt" -inkey "C:/Users/user/certs/example.key" -certfile "C:/Users/user/certs/example.crt" -name "examplecert" -out "C:/Users/user/certs/keystore.p12"
3.keystore.jks-
"C:\Program Files\Java\jdk1.8.0_341\bin\keytool" -importkeystore -srckeystore "C:/Users/user/certs/keystore.p12" -srcstoretype pkcs12 -destkeystore "C:/Users/user/certs/keystore.jks" -deststoretype JKS
I have the keyStore setup in properties:
server.port=443
server.use-forwarded-headers=true
security.require-ssl=true
server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password= password
server.ssl.key-alias=examplecert
When I hit the url, I can see the same cert being used with httpsnot-secure error
However, when I click in the background 'thisisunsafe' as mentioned here stackoverflow-answer, I get the error:
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target] with root cause
Can someone help me in this? I am completely new to SpringBoot.

Import Certificate to Keystore

I have generated the keystore using this command :
keytool -genkeypair -alias test -keyalg RSA -keystore keystore.jks
Under this section i have provided the following response:
What is your first and last name?
[Unknown]: myservice.example.com
Now i have generated the certificate with Common Name:myservice.example.com,
How should i import this certificate to my keystore so my client can connect to my service to a specific port and browser shouldn't display the invalid certificate error ?

How do I use client certificates in a client java application?

This is a topic that has taken me quite some time to figure out. There are bits and pieces of information scattered and one has to put everything together. I was hoping that with this post I could help others quickly assemble a working solution.
I have a client-cert.pem, client-key.pem and a root.pem files and I need to used them in my Java client to access a remote REST API.
How do I package them into a truststore and use them to make API calls?
In order to load your certificates into your application your will need to package them into a truststore.
Creating a truststore
given the 3 files:
client-cert.pem
client-key.pem
root.pem
Run the following commands in your terminal. Replace PASSWORD with your desired password.
Package your client key and certificate into a keystore. This will create a PKCS12 keystore file.
openssl pkcs12 -export \
-inkey client-key.pem -in client-cert.pem \
-out client.pfx -passout pass:PASSWORD \
-name qlikClient
Add the keystore to your truststore. It will create a truststore if the destination doesn't exit. This will create a PKCS12 truststore file. By default it creates a JKS file which is a proprietary format. By specifying -deststoretype PKCS12 you will create a file which is in an industry standard format.
keytool -importkeystore \
-destkeystore truststore.pfx -deststoretype PKCS12 -deststorepass PASSWORD \
-srckeystore client.pfx -srcstorepass PASSWORD -srcstoretype PKCS12 \
-alias qlikClient
Add your root CA to the truststore
keytool -importcert \
-keystore truststore.pfx -storepass PASSWORD \
-file root.pem -noprompt \
-alias qlikServerCACert
Note that in the above commands we use the same PASSWORD for both the keystore and the truststore. You could alternatively use different passwords. Also note that you have to specify an alias for each item you add to the truststore.
If you want your truststore to trust all cacerts available in your system add -trustcacerts option to step 2 or 3.
You can use the following command to list the contents of your truststore
keytool -list -keystore truststore.pfx -storepass PASSWORD
Using the truststore in you application
Once you have your truststore you need to load it into your application. Assuming you have a constant KEYSTORE_PATH holding the path to your truststore and keyStorePass holding the password, read the truststore file into a KeyStore
private KeyStore readStore() {
try (InputStream keyStoreStream = new FileInputStream(KEYSTORE_PATH)) {
KeyStore keyStore = KeyStore.getInstance("PKCS12"); // or "JKS"
keyStore.load(keyStoreStream, keyStorePass.toCharArray());
return keyStore;
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
Create a custom SSLContext and a custom HttpClient,
final KeyStore truststore = readStore();
final SSLContext sslContext;
try {
sslContext = SSLContexts.custom()
.loadTrustMaterial(truststore, new TrustAllStrategy())
.loadKeyMaterial(truststore, keyStorePass.toCharArray(), (aliases, socket) -> "qlikClient")
.build();
} catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException | UnrecoverableKeyException e) {
throw new RuntimeException("Failed to read keystore", e);
}
final CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
You can now use this HttpClient to make requests to your API.
HttpResponse response = httpClient.execute(new HttpGet("https://sense-gcp-central1eu.net:4242/qrs/app/full"));
Or, if you are using the OpenUnirest/unirest-java library, you can configure Unirest to use your custom HttpClient
Unirest.config().httpClient(httpClient);
HttpResponse<JsonNode> response = Unirest.get("https://sense-gcp-central1eu.net:4242/qrs/app/full").asJson();
References
https://alvinalexander.com/java/java-keytool-keystore-certificate-tutorials
How do I use an SSL client certificate with Apache HttpClient?
I know it is an old question, but I figured out something wrong in your question.
The truststore is used by your client to list the remote server to which it can trust.
If the certificate/key you have and would like to use, is for your own java client, you should include them in your keystore, not truststore.
This is the store your client will use in case the remote server asks your client to authenticate itself.
On top of the already given answers, if you are using spring boot and resttemplate as http client implementation, you can use the keystore you created by doing so in your application properties:
server:
ssl:
enabled: true
key-alias: <<app-client-alias>>
key-store: <<path_to_your_keystore>>
key-store-password: <<PASSWORD>>

KeyStore and TrustStore mismatch

I have a customer who replaced the keystore and truststore of our product components. After replacement the components can't communicate with each other (2 way SSL).
On SSL logs I see:
http-nio-8100-exec-2, fatal error: 42: null cert chain
javax.net.ssl.SSLHandshakeException: null cert chain
%% Invalidated: [Session-6, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
http-nio-8100-exec-2, SEND TLSv1.2 ALERT: fatal, description = bad_certificate
http-nio-8100-exec-2, WRITE: TLSv1.2 Alert, length = 2
http-nio-8100-exec-2, fatal: engine already closed. Rethrowing javax.net.ssl.SSLHandshakeException: null cert chain
They have configured the same keystore and truststore files on both sides.
I've opened their keystore and truststore and this is how they are built:
keystore
entry1 - server
cert[1] MD5: X
cert[2] MD5: Y
cert[3] MD5: Z
truststore
entry1 - root
cert[1] MD5: Z
entry2 - intermediate
cert[1] MD5: Y
It seems to me that the fact that cert[1] in the keystore (with MD5 X) is missing from the truststore is problematic.
Am I right?
Can you see any other problem with the way their keystore and truststore was built?
It looks like your problem is related to some missing certificates either in your keystore and/or truststore.
Generally speaking, when the client sends a request to the server, the server presents its certificate chain which must include the server's certificate as the first entry followed by its issuer and other issuers. Each following certificate must directly certify the one preceding it unless it is present in the truststore on the client-side.
You need to check whether your cert[1] in keystore is a self-signed certificate. You can achieve this in the following way:
For .jks Java keystore type:
keytool -list -v -keystore [keystore-file-name].jks
-For #PKCS12 keystore type:
keytool -list -keystore [keystore-file-name].p12 -storetype PKCS12 -v
When the certificate is printed, check the 'Issuer' attribute.
If it matches the 'Owner' attribute, it means it's a self-signed certificate and you need to add the 'cert[1]' into the truststore.
If they don't match, try one of the following alternatives:
Generate a new 'cert[1]' signed by either 'Y' or
'Z' and add it into the keystore or replace the existing one. The decision whether to replace it or add depends how your code reads the certificate. A replacement might be a better option.
Add the current 'Issuer' of 'cert[1]' of the keystore into the
truststore.
If the certificate of the 'Issuer' of 'cert[1' in the keystore is already present in the truststore, I would've expected the SSL handshake to be successful.
Here is how you add an issuer to a truststore:
1) Get hold of the Public Certificate of the issuer, which is stored in .cer file. If the issuer is self-generated and you've got access to its keystore, the certificate an be exported from there using the following command:
keytool -export -keystore [issuer-keystore].jks -alias [alias]-file [output-file-name].cer
2) Import the .cer file into the truststore:
keytool -importcert -file [output-file-name].cer -keystore [truststore-file-name].jks -alias [alias]
Am I right?
No. As long as the truststore contains one of the certificates in the keystore's certificate chain, it should trust the certificate in the KeyStore.

'peer not authenticated' SSL certificate error usng DefaultHttpClient

I have an application jar from which I m calling an HTTPS url using DefaultHTTPClient class object but its giving peer not authenticate exception, so I want to sign jar using keystore.
I have .cer file which has public key and I can able to import into keystore but when I use jarsigner tool it says certificate chain not found.you must have private key and associate public key.
I have .pfx file also which is suppose to an private key but I don't know how to import it.can any one able to tell me the steps how to import .pfx file and use in jarsigner.
Correct me if I m wrong somewhere..
UPDATE
As per #Duncan I am able to import .cer file in JVM by referring This Link.. I used bellowed command to import .cer into cacerts
c:\Program Files\Java\jre7\bin>keytool -importcert -alias esbcert -file "e:\Desktop\esbcert\esb.cer" -keystore "c:\Program Files\Java\jre7\lib\security\cacerts"
-storepass changeit
After this I entered 'y' to trust the certificate
Trust this certificate? [no]: y
Certificate was added to keystore
After that I Run my application but it still gives me javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
Stack is as follows :
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at sun.security.ssl.SSLSessionImpl.getPeerCertificates(Unknown Source)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.jav
a:126)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFact
ory.java:572)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnect
ion(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedCli
entConnectionImpl.java:294)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(Default
RequestDirector.java:645)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultReq
uestDirector.java:480)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpCl
ient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpCl
ient.java:805)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpCl
ient.java:784)
at testhttps.TestHTTPS.testWithMKCLHTTPClient(TestHTTPS.java:95)
at testhttps.TestHTTPS.main(TestHTTPS.java:49)
My Code is :
String url = "https://domain.org/webapp/transformer/doTransformer/doReg";
try {
HttpPost postRequest = new HttpPost(url);
HttpResponse httpResponse = null;
DefaultHttpClient httpClient = new DefaultHttpClient();
httpResponse = httpClient.execute(postRequest);
} catch (Exception e) {
e.printStackTrace();
}
This exceptions tell that connection made to server URL is not from authenticated client. To resolve this issue we have to import server's public certificate in jre on which java application is runnering to import certificate follow these steps:
As per #Duncan (comment) I am able to import .cer file in JVM by referring This Link.. I used bellowed command to import .cer into cacerts
c:\Program Files\Java\jre7\bin>keytool -importcert -alias esbcert
-file "e:\Desktop\esbcert\esb.cer" -keystore "c:\Program Files\Java\jre7\lib\security\cacerts" -storepass changeit
After this I entered 'y' to trust the certificate
Trust this certificate? [no]: y
Certificate was added to keystore

Categories