Can't load a JKS keystore containing - java

I'm trying to load a JKS keystore containing an intermediate CA certificate acquired from an existing web server.
The Verisign certificate is shown below.
-----BEGIN CERTIFICATE-----
MIIF5DCCBMygAwIBAgIQW3dZxheE4V7HJ8AylSkoazANBgkqhkiG9w0BAQUFADCB
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMTYxMTA3MjM1OTU5WjCBujEL
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQg
aHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYSAoYykwNjE0MDIGA1UEAxMrVmVy
aVNpZ24gQ2xhc3MgMyBFeHRlbmRlZCBWYWxpZGF0aW9uIFNTTCBDQTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAJjboFXrnP0XeeOabhQdsVuYI4cWbod2
nLU4O7WgerQHYwkZ5iqISKnnnbYwWgiXDOyq5BZpcmIjmvt6VCiYxQwtt9citsj5
OBfH3doxRpqUFI6e7nigtyLUSVSXTeV0W5K87Gws3+fBthsaVWtmCAN/Ra+aM/EQ
wGyZSpIkMQht3QI+YXZ4eLbtfjeubPOJ4bfh3BXMt1afgKCxBX9ONxX/ty8ejwY4
P1C3aSijtWZfNhpSSENmUt+ikk/TGGC+4+peGXEFv54cbGhyJW+ze3PJbb0S/5tB
Ml706H7FC6NMZNFOvCYIZfsZl1h44TO/7Wg+sSdFb8Di7Jdp91zT91ECAwEAAaOC
AdIwggHOMB0GA1UdDgQWBBT8ilC6nrklWntVhU+VAGOP6VhrQzASBgNVHRMBAf8E
CDAGAQH/AgEAMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRw
czovL3d3dy52ZXJpc2lnbi5jb20vY3BzMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6
Ly9FVlNlY3VyZS1jcmwudmVyaXNpZ24uY29tL3BjYTMtZzUuY3JsMA4GA1UdDwEB
/wQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZ
MFcwVRYJaW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7
GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwKQYDVR0R
BCIwIKQeMBwxGjAYBgNVBAMTEUNsYXNzM0NBMjA0OC0xLTQ3MD0GCCsGAQUFBwEB
BDEwLzAtBggrBgEFBQcwAYYhaHR0cDovL0VWU2VjdXJlLW9jc3AudmVyaXNpZ24u
Y29tMB8GA1UdIwQYMBaAFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqGSIb3DQEB
BQUAA4IBAQCWovp/5j3t1CvOtxU/wHIDX4u6FpAl98KD2Md1NGNoElMMU4l7yVYJ
p8M2RE4O0GJis4b66KGbNGeNUyIXPv2s7mcuQ+JdfzOE8qJwwG6Cl8A0/SXGI3/t
5rDFV0OEst4t8dD2SB8UcVeyrDHhlyQjyRNddOVG7wl8nuGZMQoIeRuPcZ8XZsg4
z+6Ml7YGuXNG5NOUweVgtSV1LdlpMezNlsOjdv3odESsErlNv1HoudRETifLriDR
fip8tmNHnna6l9AW5wtsbfdDbzMLKTB3+p359U64drPNGLT5IO892+bKrZvQTtKH
qQ2mRHNQ3XBb7a1+Srwi1agm5MKFIA3Z
-----END CERTIFICATE-----
I have imported the certificate into a JKS keystore using the following command:
keytool -importcert -trustcacerts -alias vs -file vs.cer -keystore vs.jks -storepass changeit -storetype JKS
I have verified that keytool can read the certificate details back from the newly created keystore.
Finally, I am using the following Java code to load the keystore:
final KeyStore trustStore = KeyStore.getInstance("JKS");
trustStream = getClass().getClassLoader().getResourceAsStream("vs.jks");
trustStore.load(trustStream, "changeit".toCharArray());
Currently using JDK 1.7.0_51.
Unfortunately, an exception is thrown while in the load() method.
java.security.cert.CertificateParsingException: java.io.IOException: X500 RDN
at sun.security.x509.X509CertInfo.<init>(X509CertInfo.java:171)
at sun.security.x509.X509CertImpl.parse(X509CertImpl.java:1788)
at sun.security.x509.X509CertImpl.<init>(X509CertImpl.java:202)
at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:97)
at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:747)
at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:55)
at java.security.KeyStore.load(KeyStore.java:1214)
...
Caused by: java.io.IOException: X500 RDN
at sun.security.x509.RDN.<init>(RDN.java:242)
at sun.security.x509.X500Name.parseDER(X500Name.java:804)
at sun.security.x509.X500Name.<init>(X500Name.java:307)
at sun.security.x509.CertificateIssuerName.<init>(CertificateIssuerName.java:82)
at sun.security.x509.X509CertInfo.parse(X509CertInfo.java:685)
at sun.security.x509.X509CertInfo.<init>(X509CertInfo.java:169)
... 37 more
Am I doing anything wrong?
I have the feeling that there is something unexpected in the certificate which is confusing the parser. The stack trace suggests that there may be a problem parsing the issuer name.
Is there anything I can do to work around this?

I have figured out the cause. Nothing wrong with the certificate file or the keystore!
I'm using Maven to compile my project, which is automatically copying the jks file to the target build directory.
It turned out that, during the copying process, Maven assumed the file was a text file, and "helpfully" converted any extended ASCII characters (>= 0x80) to '?' (0x3F)!
When analysing / listing the JKS file, I naturally only looked in my source directory and never thought to verify that the resource file be identical in content!
Confirms the golden rule, Never Trust Maven!
I solved this by adding the following to my pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>jks</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>

I recently had this same exception:
java.security.cert.CertificateParsingException: java.io.IOException: X500 RDN
I had a little look back in the history of our mercurial repo and it is pretty clear that a merge was done of various keystores when changes from a similar repo (different release) were pulled in. The outcome was that all of those keystores that were "merged" were in fact corrupted.
A manual copy of the affected files between the repos resolved the issue.

Related

Client Authentication Tomcat - trustAnchors parameter must be non-empty

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());

WsImport unable to find imported certificate

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

Install a renewed SSL certificate in Tomcat

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.

Self-signed applet doesn't get a full permission

I've googled lots of links like oracle and velocity review and stackoverlow too, but still no success.
The point is simple. Jar is signed using:
keytool -genkey -alias signFiles -keystore compstore -keypass bca321 -dname "cn=test" -storepass abc123
jarsigner -keystore compstore -storepass abc123 -keypass bca321 -signedjar SignedJar.jar UnsignedJar.jar signFiles
And it runs perfectly on local machine. But when SignedJar.jar is used like an applet via HTTP(S), even if user accepts certificate (IE or FF or Chrome - no difference), it stops working with:
java.security.AccessControlException: access denied (javax.smartcardio.CardPermission Broadcom Corp Contacted SmartCard 0 connect)
at java.security.AccessControlContext.checkPermission(Unknown Source)
at java.security.AccessController.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPermission(Unknown Source)
at sun.security.smartcardio.TerminalImpl.connect(Unknown Source)
Yes, it tries to read from smartcard inserted in terminal, and gets an exception on calling connect.
Yes, I've tried this approach too:
AccessController.doPrivileged(new PrivilegedAction() {
...
But with no luck. So where is the catch?
Thanks in advance,
Kirill
I ran into this problem today, java 1.7.0_11, applet jars signed with self-signed certificate added to the list of trusted certificates. It went away when I removed the section in my policy file that granted my applet's codebase all permissions.
After creating public/private keys, creating the associate certificate and signing which one of your applet jars with the certificate you should create a hash for each file in the JAR and sign them with the private key. These hashes, the public key, and the certificate must be added to the META-INF directory of the JAR file alongside the JAR’s manifest.
Here is the command line:
$ jar -tf SignedApplet.jar
See link

PKCS#12 : DerInputStream.getLength() exception

I generate a certificate using the keytool command:
keytool -genkeypair -alias myRSAKey -keyalg RSA -keysize 1024 -keystore test.p12 -storepass test -storetype pkcs12
Then if I try to load it using java security API, after getting the file as a byte[] :
KeyStore ks = KeyStore.getInstance("PKCS12");
try{
ks.load(new ByteArrayInputStream(data), "test".toCharArray())
} catch (Exception e){
...
}
I get a DerInputStream.getLength(): lengthTag=127, too big exception.
What is wrong?
I had this problem and I've searched the depths of google and still couldn't find the answer. After some days battling with a terrible quality legacy code, I found what was causing this error.
KeyStore.load(InputStream is, String pass);
this method takes an InputStream and if there's any problem with such InputStream, this exception is thrown, some problems that I've encountered:
The InputStream points to the wrong / blank / just created file
The InputStream is already open or something else is holding the resource
The InputStream was already used and read, thus the position of the next byte of InputStream is it's end
The last one was the responsible for my problem. The code was creating an InputStream from a certificate, and proceeding to use it in two KeyStore.load() calls, the first one was successful, the second one always got me this error.
For others with a similar problem:
"keystore load: DerInputStream.getLength(): lengthTag=109, too big."
For me solution was to remove the param: -storetype pkcs12
since the standard type is jks
Probably the certificate you create has an extra character at the end which is misinterpreted to be another certificate.
Use one or more blank lines at the end.
Refer: Java Certificate Parsing
My issue (lengthTag=109, too big) was the .p12 file actually is JKS format and not PKCS # 12 format. Someone renamed the file extension. By regenerating in proper PKCS format resolved the issue.
java.io.IOException: DerInputStream.getLength(): lengthTag=109, too big.
at sun.security.util.DerInputStream.getLength(DerInputStream.java:599)
at sun.security.util.DerValue.init(DerValue.java:365)
at sun.security.util.DerValue.<init>(DerValue.java:320)
at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1914)
at java.security.KeyStore.load(KeyStore.java:1445)
To check the format of a security file, may use KeyStore Explorer to open the file. The left bottom bar shows the actual format.
Specify the type of certificate in the code
for eg:
System.setProperty("javax.net.ssl.trustStoreType", "jks");
System.setProperty("javax.net.ssl.keyStoreType", "pkcs12");
This happened to me in Android Studio after AndroidX migration and using the new testing framework. Even deleting the existing ~/.android/debug.keystore was failing for me
The solution was regenerate it manually (accept all questions as empty and say yes at the last one)
$ keytool -genkey -v -keystore debug.keystore -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000
And copy it
$ rm ~/.android/debug.keystore
$ cp debug.keystore ~/.android/debug.keystore
This happened to me because I had copy and pasted the .p12 file locally on my windows 10 machine. No clue how/why this is a problem, but when I clone a project that has .p12 files and point my code to them, the files work. However, copy and pasting the files in windows file explorer to somewhere else on the harddrive causes this error!!!!
I had the same issue.
My solution is to replace PKCS12 with jceks in the line below because I was apparently using the wrong type.
KeyStore clientStore = KeyStore.getInstance("PKCS12");
You are doing something wrong.
I tried your command and then loaded the p12 just fine.
The following code works:
FileInputStream fin = new FileInputStream("..\\test.p12");
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(fin, "123456".toCharArray());
System.out.println(ks.getCertificate("myrsakey"));
I was wondering if you put the command as is you get an error from keytool that the password must be at least 6 characters.
You did not get that error? What version of java are you using?
Note:if you need to create certificates you can also look into this tool.
http://sourceforge.net/projects/certhelper/
Make sure the scope of the inputstream variable is only to the method where you’re declaring it but not as static/class variable.This way this exception can be avoided.
Reason : Inputstream is not getting closed after the first time of loading certificate or data in it while it is declared as class variable.so make it available only to method.
This happened to me because the following command:
openssl pkcs12 -export -in import.pem -inkey myhost.key.pem -name shared > server.p12 (from https://docs.oracle.com/en/database/other-databases/nosql-database/12.2.4.5/security/import-key-pair-java-keystore.html)
generated a wrongly formatted pkcs12 file. Using the following corrected the problem:
openssl pkcs12 -export -in import.pem -inkey myhost.key.pem -name shared -out server.p12
This error has multpile causes... The log can be realy confusing.
One main cause can be maven filtering.
According to maven official documentation
Warning: Do not filter files with binary content like images! This will most likely result in corrupt output.
Our .jks was corrupted by maven during packaging stage.
This thread helped me to figure it out.
We can exclude some directories or file extensions from filtering directly in concerned pom.xml :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>${maven-resources-plugin.version}</version>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>jks</nonFilteredFileExtension>
<nonFilteredFileExtension>p12</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>

Categories