Apologies for yet another "unable to find certificate" question.
I'm developing on a Windows 7 machine. I am using multiple Java versions and because of that am explicit about paths to the used java version (here Java6). I achieve this by the following two lines:
set path=c:\Program Files\Java\jdk1.6.0_45\bin;%path%
set java_home=c:\Program Files\Java\jdk1.6.0_45
I need to use a 3rd party web service https://service.gov/Service.svc?wsdl that provides a certificate.PFX certificate (both service URI and certificate file are renamed as a way to protect the 3rd party's interests). I have made sure that after importing the certificate file in Windows I can open the WSDL file in my browser.
I first import the certificate in my keystore (using Administrator Command Prompt to get access to write in the system folder):
keytool -importkeystore -srckeystore certificate.pfx -srcstoretype pkcs12 -keystore "c:\Program Files\Java\jdk1.6.0_45\jre\lib\security\cacerts"
I get a success notification. Still, I make sure that the new certificate is present in the output of:
keytool -list -keystore "c:\Program Files\Java\jdk1.6.0_45\jre\lib\security\cacerts"
Then I create a new folder containing blank subfolders called src and classes. Once this is done, I run wsimport from that new folder (using Java class instead of binary to make sure I am explicit about the truststore being used):
java -classpath "c:\Program Files\Java\jdk1.6.0_45\lib\tools.jar" -Djavax.net.ssl.trustStore="c:\Program Files\Java\jdk1.6.0_45\jre\lib\security\cacerts" -Djavax.net.ssl.trustStorePassword=changeit com.sun.tools.internal.ws.WsImport https://service.gov/Service.svc?wsdl -s src -d classes
The output is the following:
parsing WSDL...
[ERROR] sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Failed to read the WSDL document: https://service.gov/Service.svc?wsdl, because 1) could not find the document; /2) the document could not be read; 3) the root element of the document is not <wsdl:definitions>.
[ERROR] failed.noservice=Could not find wsdl:service in the provided WSDL(s):
At least one WSDL with at least one service definition needs to be provided.
Failed to parse the WSDL.
The WSDL file contains and is used by other organisations, so the problem is pretty certainly not on the 3rd party's side.
Am I missing something? To me it all seems obvious by now, but it still doesn't work. I have also tried this with Java8, and the result is pretty much the same. The only difference is that in Java8, the WsImport class no longer exists, so I am using the wsimport.exe binary.
Thanks in advance for any ideas or hints.
The pfx file (which contains a certificate and also a private key) is for client authentication, while a truststore is for validating the server certificate. It is important to understand the difference between a keystore and a truststore.
You have imported the client certificate (and key) into the default truststore (cacerts). What you should have done instead is:
Import the issuer (CA) of the SSL certificate of the server into cacerts. You can skip this step if the CA certificate is already in cacerts, which is probably the case here.
Use the pfx file as your keystore for client authentication. The easiest way is to convert it to jks: https://stackoverflow.com/a/3054034/2672392 The properties to pass to wsimport are "javax.net.ssl.keyStore" and "javax.net.ssl.keyStorePassword".
See this answer for a list of important SSL properties: https://stackoverflow.com/a/5871352/2672392
Related
I was hoping someone could help me out. Some small details will be altered for anonymity.
Initial problem:*
When importing spring boot project into RAD I get this error:
Failure to transfer org.apache.maven:maven-archiver:pom:3.5.0 from https://nexusrm.<myCompany>.net:8443/repository/<myCompany>-maven/
was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced.
Original error: Could not transfer artifact org.apache.maven:maven-archiver:pom:3.5.0 from/to central
(https://nexusrm.<myCompany>.net:8443/repository/<myCompany>-maven/): PKIX path building failed:
com.ibm.security.cert.IBMCertPathBuilderException: unable to find valid certification path to requested target
Inferred Cause:
I think my IDE cannot go to my companies nexus repository to get the parent pom file because the repo site uses a self signed certificate (or some other certificate error).
Workaround:
After opening my IDE (RAD/eclipse but I also have IntelliJ with same issue). I open the command line (windows 10), navigate/cd to my project, and add set MAVEN_OPTS="-Dmaven.wagon.http.ssl.insecure=true". This allows the Spring Boot project to run, but I have all sorts of other issues that may or may not be related and would like a permanant solution to this to make sure this is not causing issues. (other issues like when I open RAD I get popups saying failure to transfer other things, some projects saying incorrect package declarations, webserver+LDAP authentication stuff, etc)
Proposed Solution:
I believe I need to add the public certificate of the Nexus server to the trust store of the Java running Maven which I learned from this link https://support.sonatype.com/hc/en-us/articles/213465088-Maven-is-unable-to-connect-to-Nexus-after-configuring-Nexus-to-use-SSL- which says to do this:
Get the certificate from the server into a PEM encoded file on your Java client host:
keytool -printcert -rfc -sslserver example.com > example.pem (Optional/Advised)`
Import the certificate into the default Java truststore location under a relevant alias, using the default truststore password:
keytool -importcert -file example.pem -alias example.com -storepass changeit -keystore $JAVA_HOME/lib/security/cacerts
Main Questions
I cannot figure out how to do this. I need to know:
How to get the certificate (any browser) and how to put it into a PEM encoded file. In regards to the command-
I am unsure of what example.com should be and what example.pem should be. I know they are my server and pem file, but
Is server just the link of the nexus repo ie https://nexusrm.<myCompany>.net:8443/repository/<myCompany>-maven/? And
how do I generate this pem file?
Do I get the certificate by going to my browser->view certificate->details->copy to file?
What do I save the file as?
Conclusion:
Thanks so much for taking the time to read, I hope you can tell by my questions that I am new to all of this. It is possible there is a better way to fix this problem, or that this is not the right way to go about it at all it could be a firewall, configuration, or permissions thing, so any advice will be appreciated, just please keep in mind my skill level. I am just setting up my environment for my first software developer job, and trying to learn web applications using spring/spring boot. Please ask if you need more info.
Additional Info:
Java version 1.8_0_311 (jdk 1.8_0_311, jre 1.8_0_311)
Apache Maven Version 3.8.3
Particular error on Spring 2.5.5 but similair error on 2.6.0
I am using a Cisco anyconnect vpn
I know this question appears no stackoverflow a lot, and the exception is to do with a missing truststore - but here is my issue:
Using Apache Tomcat v7.0.56 as server on Windows with Java 8.0.71
modified tomcat/conf/server.xml to include SSL Connector with truststoreType="PKCS12", truststoreFile="conf/regtomcat.truststore" truststorePass="password"
I launch tomcat and I know it is reading this truststore file correctly as I originally did not have the file in pkcs12 format and tomcat reported an error on startup. I also have tried breaking the file location just to see tomcat startup fail as it can not find the file. So tomcat launches okay - it is reading the truststore which must mean it exists and can be read.
I load a p12 file into my browser certificate, and go to my application URL. I then get the tomcat error:
handling exception: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException:
the trustAnchors parameter must be non-empty
Given that my trustore exists, and contains my certificate - what could the problem be?
I generated all certificates and truststores using keytool. The truststore was created using the command
keytool -importcert -alias regClient -storetype PKCS12 -keystore regtomcat.truststore -file regClient.cer
One probable reason might be that if we use same .jks file as a keystore and as a truststore, then the server start up is failing with following error : java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty.
Keystore is to store the ServerCerts and TrustStore is to store the CA certs. On adding at least one CA certificate in the .jks, above issue will be resolved.
Okay - the problem was the certificate was created using JDK 1.8 and the tomcat was running with JRE 1.7 - for whatever reason this caused an issue, so the fix was to use JRE 1.8 and now everything works okay.
Faced same issue. My keystore only had private key pair of the website. Imported the public certificates from the key pair all the way down to the root and it worked.
Faced same issue. The cause was far more basic: the .jks file must be readable for the account under which tomcat service runs. Though we have it as a systemctl service (hence started/stopped from root) the account was tomcat, so a simple chown tomcat:tomcat for the .jks store did the job!
For me the issue was I was passing null to the keyword as password wherein the password was changeit
ks.load(fis, "changeit".toCharArray());
I successfully installed a GoDaddy SSL certificate in Tomcat last year.
When the certificate expired, I renewed it. I did this without generating a new keystore or CSR. GoDaddy delivered three files to me, gd_bundle.crt, gd_intermediate.crt, and a third .crt file with a random number as the name.
I don't know what to do next. I assume I have to incorporate these files into my existing keystore. GoDaddy provides this help page:
http://support.godaddy.com/help/article/5355/ssl-certificate-renewal-tomcat-4-x5-x6-x
The page says I can do this one of two ways. I tried the first way and all I got was an error message saying "-inkey: no such file or directory". I tried the second way, but I do not have any file with the name it references, and also any attempt to import the new certs into the existing keystore results in an error "certificate not imported, alias already exists".
What is the correct way to update my keystore file with the new certificate?
Thanks.
You need to use the keytool to import the numbered file into the existing KeyStore, using the same alias you're already using, with the -importcert option.
I am totally new to web services. I am tying to connect through SSL connection. I followed this site: SSLHandshakeException: PKIX: unable to find valid certification path to requested target , this thread How to solve javax.net.ssl.SSLHandshakeException Error? and I did add the certificate to the keystore as follow:
keytool -importcert -alias <some name> -file <Certifacate path> -keystore "%JAVA_HOME%/jre/lib/security/cacerts" -storepass changeit
and I checked it is exists by using keytool -list command
The problem is that I got this error message when I trying to connect through SSL in the application:
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 also tried to add the trustStore location and password in the application as follow:
System.setProperty("javax.net.ssl.trustStore","C:\\Program Files (x86)\\Java\\jre7\\lib\\security\\cacerts");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
But still got the same error.
I am using Jdeveloper 11g R1 and JDK 7, if that's help.
Update:
After further reading some solutions said I need to make this path:
C:\Program Files\Java\jdk1.7.0_09\jre\lib\security\cacerts
As truststore
I replace the above java statement to be as follow:
System.setProperty("javax.net.ssl.trustStore","C:\\Program Files\\Java\\jdk1.7.0_09\\jre\\lib\\security\\cacerts");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
but still I am getting the same error !!
After I got the certificate form third party I did the following:
Adding the certificate to the trusted root certificate in the browser with server Authentication check form the advance option.
Adding the certificate to the trust certificate using keytool options in the command prompt refer to this link: Resolving javax.net.ssl.SSLHandshakeException for mor information.
After long search I found that the cause of the problem unable to find valid certification path to requested target as follow: (Note: that's what I found out there may be more)
a. There is a missing intermediate certificates that is not added.
to solve this issue you need to add the root certificate and all the other will be added by default. To find out the certificate used by your third party refer to the following links. Basically, the proposed solution will provide you with a java class called (InsertCert.java) that will provide you with the certificates used by the server. what do you need is to pass the host name as a parameters. Find the details in the following links:
No more 'unable to find valid certification path to requested target'
Step by step video to solve the issue using information from the provisos link
b .You are adding the certificate in the wrong cacerts file.
To solve this issue refer to the same java class mentioned earlier (InsertCert.java) and it will provide with the correct cacerts path in my case I am using Jdeveloper 11.1.1.7 and the path is:
C:\Oracle\Middleware\JDeveloper\JDeveloper11117\jdk160_24\jre\lib\security\cacerts
I have a valid keystore on my local development machine, which contains a certificate for accessing a webservice via HTTPS.
I access this keystore in my project via:
System.setProperty("javax.net.ssl.truststore", "C:\\<workspaceprojectPath>\\SIPkeystore\\truststore.jks"); // sollte wohl auch ohne Keystore klappen
System.setProperty("javax.net.ssl.keyStore", "C:\\<workspaceprojectPath>\\SIPkeystore\\SIPkeystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "SECRET");
Now I want to access that certificate from another project. There I provide the same (full) path to the keystore in the other (local) project directory.
Apparently the path is still found by the jvm and the property is being set, but on accessing the web service I get the same error message as if I hadn't added the keystore at all.
When trying run the application I get a
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid
certification path to requested target
Is there a possibility to copy an existing keystore? This will be important also, when we deploy the application to our server. The application will run as stand-alone jar. (no web server)
EDIT:
Ok, copying the keystore does not seem to be the problem, as I am able to run the original application while using a local copy of the original keystore files. It seems like it is a configuration issue.
Is there a possibility to copy an existing keystore?
Yes. From the file system perspective it is just a file.
I imagine that the problem is one of the following:
The relevant properties are not correctly set in the other project.
The other JVM cannot find the keystore file (e.g. because of chrooting or some such)
The other JVM doesn't have the required permissions to access/read the keystore file.
The read access is being blocked by (for instance) SELinux.
First of all, if Web service doesn't require client certificate (i.e. that you introduce yourself) there's no need for keystore - you only need truststore.
It could be that other project cannot access truststore, so just for exercise, try to open C:\<workspaceprojectPath>\SIPkeystore\truststore.jks there and read first few bytes. If you succeed, it means that the other project has some other truststore set as default, so in that case try:
System.out.println(System.getProperty("javax.net.ssl.trustStore"));
Also, bear in mind that Java is case-sensitive, and you specified javax.net.ssl.truststore property instead of javax.net.ssl.trustStore. Try fixing this also.
The valicert class 3 CA certificate is not in your default truststore (which is probably the cacerts file in your JRE lib/security directory, but see the JSSE documentation for the full story).
I think you should create your own truststore file (which can be a copy of the cacerts file) and add the valicert root ca to this. Then point to this file with the javax.net.ssl.trustStore system property.