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)?

My-Name-Is
  • 4,814
  • 10
  • 44
  • 84
  • Get rid of the first two lines, every time they occur. – user207421 Aug 05 '15 at 01:00
  • @EJP You mean I should delete the first two lines? I will give it try in a few hours. THX! – My-Name-Is Aug 05 '15 at 08:04
  • @EJP I deleted the first tow lines, but still the same result. Any other ideas? – My-Name-Is Aug 05 '15 at 20:08
  • 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. – Saqib Rezwan Aug 05 '15 at 20:56
  • @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. – My-Name-Is Aug 05 '15 at 21:12
  • I had some experiments and long description so wrote them in answer. – Saqib Rezwan Aug 06 '15 at 05:28
  • @My-Name-Is I not only meant it, I said it. I don't know why you're even asking. – user207421 Aug 06 '15 at 06:09

2 Answers2

15

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.

Saqib Rezwan
  • 1,382
  • 14
  • 20
  • 1
    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. – user207421 Aug 06 '15 at 06:08
  • 1
    Yes, I agree, Sorry for that. I just described all the process if that help someone else for any other matter. – Saqib Rezwan Aug 06 '15 at 06:42
  • 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----- – srinivas Mar 09 '21 at 07:59
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.

Community
  • 1
  • 1
dave_thompson_085
  • 34,712
  • 6
  • 50
  • 70
  • Does that mean that it should be possible to import a certificate chain into a `JCEKS` key store? – My-Name-Is Aug 06 '15 at 09:54
  • 1
    @My-Name-Is 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 JCEKS – dave_thompson_085 Aug 07 '15 at 05:06
  • 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. – Ville Nov 01 '17 at 21:32
  • @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 cmd} /^-----END/{close(cmd);cmd=""}'` – dave_thompson_085 Nov 02 '17 at 22:20
  • @dave_thompson_085 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. – Ville Nov 03 '17 at 05:35
  • [Link to the AWS documentation](https://docs.aws.amazon.com/redshift/latest/mgmt/connecting-transitioning-to-acm-certs.html#importing-the-acm-bundle-to-truststore) regarding the above (`redshift-keytool.jar`). – Ville Nov 03 '17 at 05:38
  • 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. – charlie_pl Aug 13 '18 at 08:09
  • @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). – dave_thompson_085 Aug 15 '18 at 02:08