• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Liutauras Vilda
  • Jeanne Boyarsky
  • paul wheaton
Sheriffs:
  • Ron McLeod
  • Devaka Cooray
  • Henry Wong
Saloon Keepers:
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
  • Tim Moores
  • Mikalai Zaikin
Bartenders:
  • Frits Walraven

SSL Exception

 
Ranch Hand
Posts: 218
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello. If you have a minute, I've been messing around with REST and trying to grab a JWT from an HTTPS endpoint. The cert chain at the endpoint is...

server cert (acme004.acme.com) --> Acme Subordinate CA --> Acme Root CA

I administer the endpoint server (acme004.acme.com) and TLS is working for browser requests so from the TLS keystore on the server (pfx), I extracted the public certs for Acme Subordinate CA and Acme Root CA and saved them to their own crt files...




Then I imported each CRT to cacerts in the JVM....



But I keep getting...

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've tried several things but keep getting same exception. Is there something up with the order I uploaded (ROOT then SUBORDINATE)? I originally thought I needed to add only the ROOT crt but that was the same exception. Aksi, both the SUBORDINATE and ROOT are in Trusted Publishers (Windows). Thank you very much for reading.




 
Sheriff
Posts: 4641
582
VSCode Eclipse IDE TypeScript Redhat MicroProfile Quarkus Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I might be able to help, but it is not clear (to me) what you are doing and what you are trying to achieve.

This is what I understand:
  - You want to get a JWT from a (web) server.
  - The server has a certificate for hostname acme004.acme.com, which has been signed by Acme Subordinate C.
  - The certificate for Acme Subordinate C has been signed by Acme Root CA, which is presumably a trusted CA.
  - You are able to connect to the server using a browser, presumably without needing to install any certificates in the browser or the platform where the browser is running.
  - You extracted all the certificates in the certificate chain from the server.
  - You are using these certificates with a Java (client?) application (not sure why), and are seeing a SSLHandshakeException.

Is this correct?  Any more information that you can share?
 
Thomas Griffith
Ranch Hand
Posts: 218
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hey.thanks so much for reading and replying.  Yeah, I think you nailed it. Ultimately I am trying to hit a REST endpoint on that server to get a JSON data respnse. The server is HCL Domino and there is a url on that server to acquire a JWT first. But right now I'm trying all this with a standalone jave executable so trying to get the jvm to trust the cert chain.
 
Ron McLeod
Sheriff
Posts: 4641
582
VSCode Eclipse IDE TypeScript Redhat MicroProfile Quarkus Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Normally, there should not be any need to have the server certificates packaged with the client.  During the TLS negotiation, the server should send its host certificate along with any intermediate certificates to the client side, and the certificate for the (trusted) top-level CA should already be installed on the client platform.

Is there something special in this case?  Is Acme Root CA a non-public internal enterprise CA?

Can you post a simplified version of your application to demonstrate what you are doing (leave out anything which might be confidential)?
 
Thomas Griffith
Ranch Hand
Posts: 218
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi. Yeah, it's enterprise only intermediate and root certs which are uploaded. presumably by policy, to the windows trust stores. That's what I can't figure out. I see them in Trusted Publishers via cert mgr on my Windows.

Before I tried to upload the intermediate and root certs to jvm cacerts, I had a different SSL exception. I will restore the original cacerts and post that exception. I can't remember what it was, but something telling me it couldn't find a cert. I'll post my code and the original error when I get back. Thanks so much again.
 
Thomas Griffith
Ranch Hand
Posts: 218
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, I restored the original cacerts in the jvm. Just the default cacerts, none of my additions...this is the 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

and this is the code...




 
Ron McLeod
Sheriff
Posts: 4641
582
VSCode Eclipse IDE TypeScript Redhat MicroProfile Quarkus Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Maybe try making a TLS connection to httpbin.org/anything test endpoint with debug logging enable to get a reference of what a successful connection looks like, and then substitute your URL and see how it differs.

The ran the code below using this command line: java -Djavax.net.debug=ssl,handshake jm7.java
and was able to see a trust chain of:
I verified that the CA OU=Starfield Class 2 Certification Authority, O="Starfield Technologies, Inc.", C=US was in the platform's Java truststore:
 
Ron McLeod
Sheriff
Posts: 4641
582
VSCode Eclipse IDE TypeScript Redhat MicroProfile Quarkus Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Since it sounds like you are using an enterprise CA which may not be included in the platform's trust store, what you were attempting before to have a custom truststore containing the CA is probably the right move.

I tried the same creating a custom truststore containing the Starfield-G2 CA certificate and then used that truststore rather than the platform's Java truststore, and it did work.

I grabbed the CA cert from here: https://ssl-tools.net/subjects/8bc19e845b981d61cf5469211a68b8e311336d90 and saved the PEM version to the file system.  It looked like this:
Examining it with openssl, it looked correct (Subject Key Identifier and Authority Key Identifier match, CA: TRUE):
Then I imported the CA certificate into a new truststore:
Finally, I ran the app with the custom truststore:
 
Ron McLeod
Sheriff
Posts: 4641
582
VSCode Eclipse IDE TypeScript Redhat MicroProfile Quarkus Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Here's a quick example of how to use the custom truststore programmatically.  I don't have an easy way to test it, so it may need a bit of tweeking:
 
Saloon Keeper
Posts: 28319
210
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
As a general rule, I don't recommend setting up JEE servers to handle SSL themselves. First and foremost because the default SSL port is a "magic" port ID, and Java apps (including JEE servers) cannot listen to that port -- or port 80 -- unless they are running insecurely (as root).

Secondly because obtaining certs and installing them in a Java keystore is a royal pain. The formats required are not the same as you normally get from cert providers for common webservers such as Apache, Nginx and IIs, so you may have to convert them. Then you have to install BOTH the cert and private keys for your cert AND you usually have to install one or more higher-level certs to validate the link to the internal keystore of the server's JVM.

You referenced the "acme" server. If that's  a reference to LetsEncrypt, you'd get a lot better support if you ran Domino through a reverse proxy like Apache or Nginx, and that's especially important since certbot certs require renewal at frequent intervals, so you really don't want to slog through that process manually every few months. And you wouldn't have to run Domino as root.
 
Thomas Griffith
Ranch Hand
Posts: 218
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello, Ron,

1. the endpoint, httpbin.org/anything, seems to go through, no exceptions, and with no adding trusted public certs.

2. I downloaded the cer file for acme004.acme.com directly from the Edge browser, where it successfully completes TLS handshakes for browser sessions...saved as a cer file, then added that to cacerts. Still throws the same exception for the java program.

3. ran the command line: java -Djavax.net.debug=ssl,handshake jm6 for both endpoints. Both "good" and "bad" endpoint returns their complete chains, as you described, with issuer and subject.

A. The "good" prints out this line...

javax.net.ssl|FINE|01|main|2024-09-30 09:56:01 EDT|null:-1|Consuming ECDH ServerKeyExchange handshake message {....

B. the "bad" throws the Exception...

javax.net.ssl|SEVERE|01|main|2024-09-30 09:56:01 EDT|null:-1|Fatal (CERTIFICATE_UNKNOWN):sun.security.validator.ValidatorException: PKIX path building failed....

so it's still at the same spot, I guess. It's weird because I downloaded the cert directly from the browser and still can't resolve the chain, and that command line java -Djavax does print the chain (subject, issuer)...


 
Thomas Griffith
Ranch Hand
Posts: 218
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello, Tim. Yeah, I was using the Domino server (intranet) as sort of a proof of concept for REST since it offers a built in JSON data stream (via URL) and trying to access via JWT. Domino also offers a URL to acquire the JWT, which is where I'm having trouble with the https.
 
Tim Holloway
Saloon Keeper
Posts: 28319
210
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I may have missed it, but just to confirm, JWT stands here for JSON Web Token, right?

For internal use, I'd normally recommend a non-SSL URL, but that's probably silly when obtaining a security token.

The Apache HTTPD and Nginx servers offer JWT support that might make them a better alternative than handling JWT straight from Domino, but I'd have to do something horrible like read the docs to see how that woud work.
 
Ron McLeod
Sheriff
Posts: 4641
582
VSCode Eclipse IDE TypeScript Redhat MicroProfile Quarkus Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Thomas Griffith wrote:2. I downloaded the cer file for acme004.acme.com directly from the Edge browser, where it successfully completes TLS handshakes for browser sessions...saved as a cer file, then added that to cacerts. Still throws the same exception for the java program.


I guess that indicates that the certificate for the enterprise CA is in the truststore used by the browser, but not in the truststore being used by the Java application.  The Java CA truststore is at: $JAVA_HOME/jre/lib/security/cacerts (on my Linux workstation, that is a link to /etc/pki/java/cacerts).

Thomas Griffith wrote:so it's still at the same spot, I guess. It's weird because I downloaded the cert directly from the browser and still can't resolve the chain, and that command line java -Djavax does print the chain (subject, issuer)...


Have you tried importing the CA certificate into a new truststore and then using that truststore with your Java app - either by specifying the system properties on the command line, or by loading and configuring inside your app?  I provided examples for both.
 
Thomas Griffith
Ranch Hand
Posts: 218
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hey, Ron. I discovered my javac/java command line was using a jvm installed as part of an enterprise Oracle installation, wasn't pointing to my jvm (where I was adding the certs to the cacerts). So I moved my standalone java program (java/class) directly into the bin of my jvm, then ran the following experiments...

1. Do nothing with cacerts

java jm6 - returned the above SSLException: unable to find certification path


2. Add Root CA cert to cacerts

streamed back the login screen html of the target Domino server


3. Restore original cacerts, add the acme004.acme.com cert downloaded from Edge to cacers

streamed back the login screen html of the target Domino server


So I think that explains the SSL issue, but despite sending login credentials, the HTTPURLConnection getting to the Domino JWT endpoint is now being stopped at the server Login screen.

PS Does setting JAVA_HOME to my own JVM override the order of PATH (where Oracle is listed before my JVM)? thank you.

 
Tim Holloway
Saloon Keeper
Posts: 28319
210
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
JAVA_HOME is not a formal or official part of Java. It's a convention used by some, but not all Java apps, and they only support it gets is for either the Java application code or its startup script (for something like TOMCAT) to resolve and use it.

Many complex systems do not use JAVA_HOME, in particular IDEs, which often locate their JVM from a config file.

You'd have to consult the documentation for your product to see where it gets its actual JVM root location. And in special cases, such as some Oracle products, it may well be hard-wired in to ensure that Oracle knows that you're using the JVM that's certified for the product.

That said, plunking in user-supplied certs into a JVM is ill-advised. More properly your keystore should contain the fully tree from user level up to, but not including, one of the universal certifiers supplied from the vendor for the JVM. Usually when you register for a cert, the certifier will include those intermediate certs along with the user cert and key.
 
Ron McLeod
Sheriff
Posts: 4641
582
VSCode Eclipse IDE TypeScript Redhat MicroProfile Quarkus Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Normally, you would set the JAVA_HOME environment variable to location of the JRE (for example: /usr/lib/jvm/jre-21-openjdk-21.0.2.0.13-1.0.1.el8.x86_64), and then you would add $JAVA_HOME/bin to the PATH (at the beginning in case there are other Java JRE already defined in the PATH).
 
If you were a tree, what sort of tree would you be? This tiny ad is a poop beast.
Gift giving made easy with the permaculture playing cards
https://coderanch.com/t/777758/Gift-giving-easy-permaculture-playing
reply
    Bookmark Topic Watch Topic
  • New Topic