How to add a certificate chain to a JKS
Asked Answered
A

2

5

I have a certificate chain called: cert.cer with the content of:

subject= ... OU=MyCA
issuer= ... OU=MyCA
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

subject= ... OU=Client
issuer= .. OU=MyCA
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

I tried to add this chain to JKS by calling:

keytool -import -trustcacerts -file cert.cer -keystore sample.keystore -storepass 123456 -alias chain

, which only adds the top level certificate of OU=MyCA.

How do I add this chain correctly to the JavaKeyStore (JKS)?

Archiplasm answered 4/8, 2015 at 21:57 Comment(7)
Get rid of the first two lines, every time they occur.Czarevitch
@EJP You mean I should delete the first two lines? I will give it try in a few hours. THX!Archiplasm
@EJP I deleted the first tow lines, but still the same result. Any other ideas?Archiplasm
The certificate chain will contain series of certificates. Each certificate contains Base64 format data with header/footer. Here header is 'BEGIN CERTIFICATE' and footer is 'END CERTIFICATE'. In between header and footer, the raw certificate data exist. So, there should not be any subject value or issue value or any other line outside of header and footer in the file. So, please try again excluding those lines.Demonetize
@SaqibRezwan Thx for your reply! I Is there a command to create such a chain? First, I followed the description in: https://langui.sh/2009/03/20/creating-a-pkcs7-p7b-using-openssl/ and issued the command: openssl crl2pkcs7 -nocrl -certfile cacert.pem -certfile clientcert.pem -out cert.p7b Second, I followed the instructions from: http://stackoverflow.com/a/22028156/1817029 and issued the cmd: openssl pkcs7 -print_certs -in cert.p7b -out chain.cer which should give me a valid certificate chain. Can you pls provide instruction to create that chain.Archiplasm
I had some experiments and long description so wrote them in answer.Demonetize
@Archiplasm I not only meant it, I said it. I don't know why you're even asking.Czarevitch
D
16

Ok, I ran your command to combine certificate in PKCS7 format:

openssl > crl2pkcs7 -nocrl -certfile a.crt -certfile b.crt -out outfile.p7b

It Worked.
Then I tried to import the PKCS#7 file to JKS file using following command as you said:

keytool -import -trustcacerts -file outfile.p7b -keystore keystore1.jks -storepass 123456 -alias chain

It did not work.
Then I researched a little and found that, I need to the certificate chain in a file either in Base64 format or in Der format. I had Base64 format file. So, I tried to concat the file using following windows command:

copy /b a.crt+b.crt c.crt

The linux command would be:

cat a.crt b.crt > c.crt

So the output file looked like this:

-----BEGIN CERTIFICATE-----
..............................
..............................
-----END CERTIFICATE----------BEGIN CERTIFICATE-----
...............................
...............................
-----END CERTIFICATE-----

Then, tried to import the certificate chain in JKS using the above command. It worked. Then, I try to see the the certificate list from the keystore. For that I ran following command:

keytool -list -v -keystore keystore1.jks

But it said, Only "1 entry is found" and one certificate was shown. As the keystore was not load with full certificate chain the experiment failed.
So, I tried to convert the PKCS#7 file in certificate chain by using following openssl command:

pkcs7 -print_certs -in outfile.p7b -out certificates.cer

The output file looks exactly like yours, started with subject dn and issuer dn and then header and footer. Then I tried to store the certificates from the 'certificates.cer' to a jks file 'keystore1.jks'. But, Again, after import, it is showing that, the keystore has only one certificate. So, the issuer dn and subject dn were not a problem.
Then I tried to convert the Base64 file to Der file and then tried to concat the data:

openssl x509 -in a.crt -outform DER -out aa.crt
openssl x509 -in b.crt -outform DER -out bb.crt
copy /b aa.crt+bb.crt cc.crt

Then, I tried to import the der concated file to JKS. But again only one certificate was imported.

I really thought about what could really wrong I am doing. So, I looked for the source code of KeyTool and found the method where the certificate or certificate chain was being imported.

Imports a JDK 1.1-style identity database. We can only store one certificate per identity, because we use the identity's name as the alias (which references a keystore entry), and aliases must be unique.

And I am surprised that, their code convert the inputstream to List of certificate but they work with only one certificate of the certificate (first one).

if (certs!=null && certs.length>0) {
      // we can only store one user cert per identity.
      // convert old-style to new-style cert via the encoding
         DerOutputStream dos = new DerOutputStream()
         certs[0].encode(dos);
         .............................

So there is nothing we can do to add multiple certificate at once. There policy is one certificate for one entry. So, if you have multiple certificate to entry you have to make entry them individually. Or, write some java code to make our work easy (I always do this).
Sorry for making this so long. But hopefully this will clear most of your confusion.

Demonetize answered 6/8, 2015 at 5:27 Comment(3)
It didn't need to be that long. You could have cut the first three-quarters of this. The only relevant part is the quotation from the sorce code and what follows.Czarevitch
Yes, I agree, Sorry for that. I just described all the process if that help someone else for any other matter.Demonetize
Hi @SaqibRezwan, Or, write some java code to make our work easy (I always do this). >> What is the code written for performing certificate chain import using keytool ?. Can you please share the code snippet? I need to import the multiple certificates with the same alias using keytool. But it always importing only the first certificate. -----BEGIN CERTIFICATE----- ... (server certificate) -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- ... (CA certificate) -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- ... (root certificate for CA's issuer) -----END CERTIFICATE-----Interstice
B
10

There are two kinds of entries in a JKS-type KeyStore:

  • a PrivateKey entry contains a privatekey and the cert or chain of certs for that privatekey

  • a TrustedCert entry contains exactly one cert and no privatekey

The generic KeyStore interface allows a third kind of entry for a SecretKey but it is not supported by JKS, only the much-less-used JCEKS and I believe a BouncyCastle format.

I found your other question https://security.stackexchange.com/questions/95945/how-to-add-a-certificate-chain-to-a-jks which explains why you correctly don't want a privatekey entry. However, most of the instructions you'll find for keytool etc. are about attaching a chain (usually returned from a CA) to a privatekey, and gloss over the fact that you cannot store a chain of certs as one entry without a privatekey.

So yes you must enter each cert separately. However, that does not necessarily mean you must fetch each cert separately. CertPathBuilder exists precisely to extract from a truststore such as (but not only) a JKS all the certs forming a valid chain. Unfortunately the bells and whistles needed to make CertPathBuilder (and specifically "PKIX") work right for SSL/TLS make it rather clumsy to use for simpler applications, so you might prefer to just fetch the certs.

PS- concatenated PEM certs do work where a chain is allowed (only with a privatekey) but the example you show is not valid. The -----BEGIN and -----END lines are supposed to be separate lines, NOT run together like you have them.

Brescia answered 6/8, 2015 at 9:42 Comment(8)
Does that mean that it should be possible to import a certificate chain into a JCEKS key store?Archiplasm
@Archiplasm only in a privatekey entry along with a privatekey, which you correctly didn't want in JKS and for the same reasons don't want in JCEKSBrescia
What a pain! I ran into this issue after AWS converted Redshift to an ACM-based certificate. To connect to a Redshift cluster with a Java-based client, such as DbVisualizer using its Redshift JDBC driver, requires the ACM CA root cert in a JKS. But AWS provides the ACM CA root as a file with six concatenated PEM certificates. The only solution was to break them up into individual files, convert each to DER encoding, and then import each individually to the JKS that DbVisualizer could use.Tungstate
@Ville: you didn't need DER; keytool -importcert can read PEM or DER, but for trustedcert only one per file in either format. (Java7 up can even read PEM with extraneous 'comments', which many OpenSSL-produced PEM files have.) You could do awk <chain.pem '/^-----BEGIN/{cmd="keytool -importcert -keystore xyz.jks -storepass secret -alias cert"(++n);} cmd{print >cmd} /^-----END/{close(cmd);cmd=""}'Brescia
@Brescia Thanks for that info. It also turns out that AWS has released a keytool replacement, redshift-keytool.jar, specifically for importing the Redshift's CA root chain either into a custom JKL (the use case I had), or to the system keystore, like so: java -jar redshift-keytool.jar -c -k redshift-ca -p Sup3rS3cr3tPassw0rd (former), or sudo java -jar redshift-keytool.jar -s (latter). Even though it reads in the entire certificate chain in one go, it can't be used as a general keytool replacement since it automatically loads the specific, predefined certs from the AWS.Tungstate
Link to the AWS documentation regarding the above (redshift-keytool.jar).Tungstate
Maybe do you remember the reasons for not including privatekey entry? Question you linked to is down, that's why it's always better to leave at least an excerpt.Oler
@charlie_pl: my notes say this asker wanted to encrypt to someone else (who was the private key holder); my notes don't say why they wanted the chain instead of just the leaf, but a logical reason is to (re)validate the chain at the last moment before using the public key (avoiding ToCtToU risks).Brescia

© 2022 - 2024 — McMap. All rights reserved.