GET from Glassfish with specifying .pem file - java

I am able to access the URL I want through a curl command from my Glassfish machine by specifying a cert.pem file.
In my Java application however, I tried using a jks file that holds the exact same information I get an exception.
I am doing this in Java:
System.setProperty("javax.net.ssl.keyStore", keystore_path);
System.setProperty("javax.net.ssl.keyStorePassword", "pass123");
Keystore path is retrieved by
getClass().getClassLoader().getResource("/keystore.jks").getPath()
While I can look inside the jks file just fine with the keytool utility, I am getting the following stacktrace from Glassfish:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java: 141) at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java: 126) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java: 280) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java: 382) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java: 292) at sun.security.validator.Validator.validate(Validator.java: 260) at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java: 324) at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java: 229) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java: 124) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java: 1491) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java: 216) at sun.security.ssl.Handshaker.processLoop(Handshaker.java: 979) at sun.security.ssl.Handshaker.process_record(Handshaker.java: 914) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java: 1062) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java: 1375) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java: 1403) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java: 1387) at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java: 543) at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java: 409) at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java: 177)
One of the suggestions is to specify to do a one-way handshake, but I'm not sure how to specify that.
Also, can I specify the .pem file as I do in the case of the working curl command and would that have any gain?

You need to set the trustStore variable, not the keyStore
System.setProperty("javax.net.ssl.trustStore", keystore_path);
System.setProperty("javax.net.ssl.trustStorePassword", "pass123");
Ensure also that keystore_path points to an absolute location. It can not load files from classpath

Related

Why is liferay loading my JKS file inconsistently?

I have some java code in Liferay 6.2 ee sp14 that needs to load a keystore JKS file in order to access some web services (using third-party libraries). If I attempt to call the code (and therefore load the JKS file) as soon as the server has loaded after a restart, it sometimes works. But sometimes it won't work, throwing an error message that suggests the JKS file wasn't actually loaded properly. And it is almost guaranteed to fail if I don't try to access the web services as soon as the server is running.
If it works the first time then it will continue to work until the server is restarted. If it doesn't work the first time then it will never work, and the only chance of getting it to work is to restart the server and try to run the code as soon as the server has loaded.
This is the error message that I see:
com.sun.xml.internal.ws.client.ClientTransportException: HTTP transport error: 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
I get the same error message if I don't try to load a keystore file, or I deliberately load the wrong keystore file first, which is why I think the issue is with the keystore file not being loaded. I'm sure it's FINDING my file because I can always read it and display the contents. My theory is that some other module (probably an outdated one) is loading a different keystore file, and the system simply won't load a second file.
Is there any way to figure out what could be interfering with my keystore file being loaded, or to force it to load even if another keystore file has already been loaded?
The specific code I'm using to load the jks file:
System.setProperty("javax.net.ssl.keyStore", jksPath);
System.setProperty("javax.net.ssl.keyStorePassword", jksPass);
System.setProperty("javax.net.ssl.keyStoreType", "JKS");
System.setProperty("javax.net.ssl.trustStore", jksPath);
System.setProperty("javax.net.ssl.trustStorePassword", jksPass);
System.setProperty("javax.net.ssl.trustStoreType", "JKS");
I have tried clearing the properties first, but it makes no difference:
System.clearProperty("javax.net.ssl.keyStore");
System.clearProperty("javax.net.ssl.keyStorePassword");
System.clearProperty("javax.net.ssl.keyStoreType");
System.clearProperty("javax.net.ssl.trustStore");
System.clearProperty("javax.net.ssl.trustStorePassword");
System.clearProperty("javax.net.ssl.trustStoreType");
Does anyone have any suggestions? I'm really desperate here.

Added certificate to cacerts still "unable to find valid certification path to requested target"

This may look like a duplicate but it is not.
I added the certificate from the ssl endpoint to my cacerts file. I verified its added. I restarted the jvm and my computer, but I still get unable to find valid certification path to requested target exception.
In addition to adding the certificate from the ssl endpoint the following helped me fix the issue. I added this system property in my code and it helped me navigate to the required secured endpoint.
System.setProperty("javax.net.ssl.trustStore", "path/to/cacerts");
However the above one works for local, while doing it for prod deployment I moved the cacerts to my project and change the path to cacerts to the one in my project. This way it worked for both remote and local end points.

javax.mail.MessagingException: Can't send command to SMTP host;

I have imported the certificate to cacerts (to where the JAVA_HOME is pointing) but still getting this error. Not able to figure out the issue. There is no firewall issue from client's mail server which is a Microsoft ESMTP server. I am able to telnet this from my server. Tried SSLpoke but it's getting timed out. Tried tcpdump of port 25, can see the communication back and forth. Basically trying to a trigger an outbound email from the mail server.
The detailed error log is:
Caused by: javax.mail.MessagingException: Can't send command to SMTP
host; 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
at com.sun.mail.smtp.SMTPTransport.sendCommand(SMTPTransport.java:1420)
at com.sun.mail.smtp.SMTPTransport.sendCommand(SMTPTransport.java:1408)
at com.sun.mail.smtp.SMTPTransport.ehlo(SMTPTransport.java:847)
at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:384)
at javax.mail.Service.connect(Service.java:297)
at javax.mail.Service.connect(Service.java:156)
at javax.mail.Service.connect(Service.java:105)
at javax.mail.Transport.send0(Transport.java:168)
at javax.mail.Transport.send(Transport.java:98)
at com.issuetracker.esb.mail.GmailImpl.transportMessage(GmailImpl.java:94)
at com.issuetracker.esb.mail.Mail.sendSRMail(Mail.java:188)
Did you use the -trustcacerts parameter when importing the cert with keytool?
Edit: My conversation on this topic has covered specific reasons for the error to occur but did not have the appearance of an 'answer', so here's a rewrite.
PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target
This error indicates that a valid certificate chain for the purposes of trusting an incoming certificate could not be obtained from the resident keystore file being used by the running JRE (by default, in the JRE's jre/lib/security/cacerts file).
Typical causes of this include:
Neglecting to include the parameter -trustcacerts when importing the certificate with the keytool command.
When the JRE is looking for certificates it knows about to match the incoming one, it will only consider the certificates that have been marked as trusted in this way.
The certificate has been signed by a root CA for whom the JRE does not already have the root certificate installed for.
Typically this is caused by having the certificate signed by an unknown root certificate authority (CA), such as a company's own internal CA that the JRE knows nothing about (yet), or even by some third party root CAs that aren't as popular as some other big-name vendors, and so whilst a browser or OS may have a root certificate already, Java may not have shipped with it.
To rectify this, you will also need to obtain and install the root CA certificate and mark it trusted too.
There are also companies that provide certificate signing that are acting as intermediaries, meaning that they don't have their own root CA themselves, but have been given a certificate by a trusted root CA to allow them to further sign certificate signing requests (CSRs).
In these cases, whilst you may have your own certificate and the underlying root CA already installed and trusted, unless you also obtain and install the intermediate certificate, then the 'certificate chain' is broken and a valid certificate path cannot be made.
So possible solutions in summary include:
Perform all certificate installations for other sites with the -trustcacerts parameter.
Check that the root CA certificate exists in the keystore file also, if not, obtain and install it using keytool -importcert -trustcacerts as well.
Check if there is also an intermediate certificate to complete the full chain, and if so, obtain and install that using keytool -importcert -trustcacerts into the keystore file also.
Note: Examining the .crt file in Windows by double-clicking the file can give you an opportunity to examine the certificate path and see if and which root and intermediary CAs were involved to help show what you will need.
Once a complete and valid certificate chain has been installed and trusted into the keystore file, the error should pass.

SocketException Default SSL context is null while connecting to remote server

I am facing the following SSL connection exception when trying to connect to remote server:
java.net.SocketException: Default SSL context init failed: null
Most of the thread suggest that there is some problem with the keystore location that contains the certificate file.
Others like this post: Default SSL context init failed: null suggests is to create the SSL Context by yourself. But, again the issue is not resolved yet.
And here is what I did so far:
I tried to add certificate to the following file locations and all of them gave me the same error mentioned earlier:
• Cacerts file in Java Home.
• Default cacerts location for the IDE I am using (JDveloper 10.1.3.2) which is in my case : C:\JDeveloper\WorkSpace_10g\jdevstudio10132\jdk\jre\lib\security\cacerts
• New keystore that only contains this certificate.
The certificated is added using Portecle applet( I also tried keytool options from Command prompts)
I am also referring to the trustStore and keyStore in the code as follow:
System.setProperty("javax.net.ssl.trustStore", trustStore file path goes here);
System.setProperty("javax.net.ssl.trustStorePassword", password goes here);
System.setProperty("javax.net.ssl.keyStore", keyStore file path goes here);
System.setProperty("javax.net.ssl.keyStorePassword", password goes here);
In the above code the file path refer for the cacerts files mentioned earlier (Java home, default JDeveloper cacerts and newly created keystore) of course I tried each one separately.
The keystore isn't found. Check that you can open that file from within the same piece of code by the same name you're using in javax.net.ssl.keyStore.
If you're using the default cacerts you don't need to set javax.net.ssl.trustStore/trustStorePassword at all.

SSL Self-signed Expired Certificate in Java

Hi I am accessing a developmental API that only has a self signed, expired certificate through Java, and unexpectedly I am getting the error about unable to find valid certification path to requested target. so I went to the url with firefox and exported the certificate to add to my keystore, using keytool -importcert -alias mycert -file mycert.cert -keystore cacert, thinking that it should work now. But upon making the call, I am still getting the same error.
Am I missing some step to link up the cert to java?
the error is
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318)
... 22 more
UPDATE: problem solved. location of keystore was wrong.
should be {location of java home}/lib/security/cacerts
exported the certificate to add to my keystore
No you didn't, you added it to your truststore. You shouldn't modify the one in the JRE, for the reason GregS gave, you should create your own and tell the server to use it.

Categories

Resources