SSL error for external API calls with the tomcat server - java

Something was changed in network configuration at my company to remediate log4j vulnerability but now my API calls are failing saying: SSL certificate chain is invalid .
I have tried setting cacert in jvm with the certificate from chrome but it does not work. Any suggestion on where to get the correct certificate from? and jvm cacert is the right place to update it?

Updating the cacert in JVM with proper certificate, will resolve the ssl certificate issue. But make sure you use correct certificate to complete certificate chain.
Reference document - https://www.grim.se/guide/jre-cert

Related

sun.security.validator.ValidatorException: SunCertPathBuilderException -while importing certificate

I am getting below Exception
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I have set the SSL certificate in the location
C:\Program Files\AdoptOpenJDK\jdk-11.0.9.11-hotspot\lib\security
keytool -import -keystore cacerts -file C:\Users\test\Desktop\Certificate\oCertificate.cer
But i am getting the above exception while i am hitting the server.
Results i saw
I have added the certificate to the Jdk cacerts file but then it worked for two days than again i was getting the same error. I am unable to get it was working i am able to succesfully ping the server than again it is showing the exception.
Is the problem you describe that running keytool to import the certificat gives you this error? Please provide the option -trustcacerts and see the documentation about this:
Import a New Trusted Certificate
Before you add the certificate to the keystore, the keytool command
verifies it by attempting to construct a chain of trust from that
certificate to a self-signed certificate (belonging to a root CA),
using trusted certificates that are already available in the keystore.
If the -trustcacerts option was specified, then additional
certificates are considered for the chain of trust, namely the
certificates in a file named cacerts.
If the keytool command fails to establish a trust path from the
certificate to be imported up to a self-signed certificate (either
from the keystore or the cacerts file), then the certificate
information is printed, and the user is prompted to verify it by
comparing the displayed certificate fingerprints with the fingerprints
obtained from some other (trusted) source of information, which might
be the certificate owner. Be very careful to ensure the certificate is
valid before importing it as a trusted certificate. The user then has
the option of stopping the import operation. If the -noprompt option
is specified, then there is no interaction with the user.
Source: https://docs.oracle.com/en/java/javase/11/tools/keytool.html
Alternatively you may find that keytool is not very user-friendly and you may enjoy other software like: https://keystore-explorer.org/downloads.html more.
Or if the problem is that your (TLS-client, or even TLS-server) software has some certificate issue it might be as jccampanero already suggested that the server might have switched to a different certificate, or for all I know the server may actually be several different servers behind a load-balancer which may not all have the same certificates. (Or maybe you installed some Java update that replaced the default cacerts file?)
In case of problems I highly recommend reading the JSSE-documentation and enabling debug logging with java option -Djavax.net.debug=all or maybe a little less than all like handshake see the Java 11 docs at:
https://docs.oracle.com/en/java/javase/11/security/java-secure-socket-extension-jsse-reference-guide.html#GUID-31B7E142-B874-46E9-8DD0-4E18EC0EB2CF
This shows the exact TrustStore your application uses, the certificate(s) that the server offers during the handshake and a lot of other negotiation stuff that is part of the TLS handshake.
If you prefer full control of who you trust to issue certificates you can configure your own truststore instead of the default that can live outside your Java installation with options like:
java -Djavax.net.ssl.trustStore=samplecacerts \
-Djavax.net.ssl.trustStorePassword=changeit \
Application
I trust that studying this debug logging should make it straightforward to resolve the issue, if it doesn't please provide us with some of the relevant logging.
The error you reported indicates that your application is unable to establish a trusted SSL connection with the remote peer, because it is unable to find a valid certification path.
Which seems very strange to me is why it worked a few days ago and now it is not: perhaps the server changes the certificate, or maybe your setup change in some way.
The SSL configuration will be highly dependent on the software you are using to connect with the remote server: it can be different if you are using standard Java classes like URLConnection or HttpURLConnection, or libraries like Apache HttpClient or OkHttp, among others. The difference mainly has to do with if that piece of software uses or not Java Secure Socket Extension (JSSE) under the hood.
Assuming that you are using JSSE, in order to successfully configure your trust relationship, you need to properly configure a TrustManager, and more specifically, an X509TrustManager. From the docs:
The primary responsibility of the TrustManager is to determine whether the presented authentication credentials should be trusted.
Basically you can configure this X509TrustManager in two ways.
On on hand, you can create your own implementation. For example:
// This KeyStore contains the different certificates for your server
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(
new FileInputStream("/path/to/serverpublic.keystore"),
"yourserverpublickeystorepassword".toCharArray()
);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); // SunX509
tmf.init(keyStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
// You can configure your client for mutual authentication
// and/or provide a SecureRandom also if you wish
sslContext.init(null, trustManagers, null);
Please, consider read this SO question for a complete example.
Or, on the other hand, as you are doing, you can configure the standard TrustManagerFactory properly.
As indicated in the above-mentioned documentation, the standard TrustManagerFactory uses the following process to try to find trust material, in the specified order:
First, you can use the javax.net.ssl.trustStore system property to point to the keystone that contains your trusted server certificates when running the application. If the javax.net.ssl.trustStorePassword system property is also defined, then its value is used to check the integrity of the data in the truststore before opening it.
If the javax.net.ssl.trustStore system property was not specified, then:
if the file java-home/lib/security/jssecacerts exists, that file is used;
if the file java-home/lib/security/cacerts exists, that file is used;
if neither of these files exists, then the SSL cipher suite is anonymous, does not perform any authentication, and thus does not need a truststore.
No matter the chosen mechanism used, you must be sure that the keystore contains all the necessary certificates to trust the remote server, not only the SSL certificate, but all the certificates in the certificate chain.
openssl provides an useful command that allows you to obtain all the certificates used in the SSL connection:
openssl s_client -showcerts -connect google.com:443
Of course, modify the domain as appropriate.
It will output different certificates; be sure to save each of them, including —–BEGIN CERTIFICATE—– and —–END CERTIFICATE—–, and include them in your keystore.
This handy utility can probably be of help for this purpose as well: as indicated in the project README, it basically will try to connect to the remote peer and save the necessary certificate information. This related article provides more information about the tool.
As other answers have pointed out the list of things that need to be setup correctly is long and varied depending on which HTTP client you are using, but assuming you have followed the information provided in the other answers, here's what I would check:
Make sure the cert was imported correctly into the cacerts file. This can get get overwritten by software updates, Group Policy (if you are on a windows domain), you accidentally changed JVMs, and so on. Double check the path to the JVM that is in use
Importing a certificate isn't always enough to ensure the trust is correctly setup. The hostname used to access the service must match the imported certificate either by the Common Name (CN), or a Subject Alternate Name (SAN DNS) entry. This first image shows the Common Name from the current google cert.
, the second image shows the SANs:
The upshot of this is that whatever hostname you are using to access the service (eg test.amazingapp.com) must match either the CN or one of the entries in the SAN field. If you are accessing the service via an IP address, then the IP needs to be in either of these fields.
Finally, ensure the certificate is not expired.
If you've checked all these and it still isn't working, then you will likely need to turn on SSL logging with the system property javax.net.debug as described here on the Oracle JSSE Site, using $ java -Djavax.net.debug=all will give all the information that exists about the handshake. It will take some time to work through but the answer will be there.

com.ibm.jsse2.util no trusted certificate found

I created a java agent that needs to connect to an API internaly. The protocol used is HTTPS. When the agent tries to connect to the API it throws the following error:
com.ibm.jsse2.util: no trusted certificate found. This all is running on a Domino 9.0.1fp3 server. The SSL certificate is a self signed certificate with a custom certificate authority.
I tried the following solution http://www-01.ibm.com/support/docview.wss?uid=swg21588966 but to no success. Even when we restarted the server it does not correctly pick up the certificate chain. As a last resort we created a little java class that ignores SSL certificates that are self signed. But ofcourse this is not a great solution.
I was wondering if someone also encountered this issue and knows how to solve it.
Apparently IBM forgot to mention that you actually need to restart the whole server for this to work....

ssl certificate error: unable to get local issuer certificate

This website, https://dcs1.noaa.gov, recently updated their SSL certification. Since that change I cannot grab a file from there that I need. I get the following error:
--08:37:12-- https://dcs1.noaa.gov/pdts_compressed.txt
=> `pdts_compressed.txt'
Resolving dcs1.noaa.gov... 205.156.2.181
Connecting to dcs1.noaa.gov|205.156.2.181|:443... connected.
ERROR: Certificate verification error for dcs1.noaa.gov: unable to get local issuer certificate
To connect to dcs1.noaa.gov insecurely, use `--no-check-certificate'.
Unable to establish SSL connection.
I am running Red Hat Linux 4.x and updated all the openssl packages. The usual process I use to access this file is running in Java and uses URL.openStream() to read the file. The command wget also does not work so I am assuming that it is an SSL problem and not a java problem.
the cert is issued by Verisign, probably their root cert is in your servers root cert store. Open the webpage from your machine from a browser and you will see the cert is valid. You can also try to wget from another machine and it will work too.
Probably, the new server certificate is issued by an issuing authority that is not trusted by you. You need to import the issuing authority's certificate in your truststore.
You could try testing the SSL connection with openssl's s_client. I recently had a similar problem and had it resolved. Here's a link to that solution. It also includes information on how to use the s_client to test an SSL connection.
SSL Error: unable to get local issuer certificate

HttpClient+SSL from Glassfish

I'm trying to download a simple page from an SSL secured webpage. I'm using HtmlUnit for that task (which wraps around HttpClient).
The webpage I'm trying to download has a proper certificate signed by Verisign and Verisign certificate is present in cacerts file (it was there in first place but I even reimported whole certiciate chain there).
My application runs perfectly as stand-alone application using the same JVM that is used by Glassfish. However if I deploy it to glassfish I'm getting a classic certificate problem exception:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated,
com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:352)
org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:339)
org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:123)
org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:147)
org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:108)
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:597)
com.gargoylesoftware.htmlunit.HttpWebConnection.getResponse(HttpWebConnection.java:133)
com.gargoylesoftware.htmlunit.WebClient.loadWebResponseFromWebConnection(WebClient.java:1405)
com.gargoylesoftware.htmlunit.WebClient.loadWebResponse(WebClient.java:1324)
com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:303)
com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:385)
I've already tried disabling security manager in glassfish and that did not help.
What can be the cause of this weird behavior?
Thanks in advance.
I thought GlassFish used it's own magical keystore:
http://metro.java.net/guide/Configuring_Keystores_and_Truststores.html
Good luck!
If this is test or temporary code and you don't care to validate the certificate, try accepting all certs and host names. Using that SSLUtilities class:
SSLUtilities.trustAllHostnames();
SSLUtilities.trustAllHttpsCertificates();
You can import certificate chain into a truststore and set the following VM arguments:
-Djavax.net.ssl.trustStore="<path to truststore file>"
-Djavax.net.ssl.trustStorePassword="<passphrase for truststore>"
or override the truststore at runtime like:
System.setproperty("javax.net.ssl.trustStore","<path to truststore file>")
System.setproperty("javax.net.ssl.trustStorePassword","<passphrase for truststore>")
Keep in mind that both options will override default JVM truststore. So if you are hitting different sites with different certs, you may want to import all of them into one truststore.

Will client JVM for a web service(https) throw an SSL Exception when the server is having a valid certificate from a CA?

I have a web service deployed on tomcat hosted on a remote server.
I have set it up such that it can be accessed only via HTTPS.
For this, I generated a Certificate Signing Request (CSR) and used it to get a temporary certificate from VeriSign.
My web service client is on my local machine. If I try to access the service it will throw a javax.net.ssl.SSLHandshakeException:unable to find valid certification path to requested target
If I install the certificate in to local Java's keystore, the issue will be resolved.
My question is if I install a valid SSL certificate from a CA in to my tomcat server,
will I get this client-side error even if I do not import the certificate to local key store?
No, you won't. JVM ships with root ca's by default. The older JVMs (1.5.xx version) don't have all root CA's, but if you have a certificate from Verisign it shouldn't be a problem.
Java has many root CA certificates already installed. As long as you use one of those popular CAs to get your certificate, the client will not receive an error.
While you should be fine, its a good idea to include not only the actual certificate for your site, but also the entire chain leading up to the root certificate. (Sometimes you'll bump into clients which are missing some intermediate certificates and this can cause annoying debugging problems.)

Categories

Resources