I know what a certificate chain is. In java when working with KeyStore objects we can add certificates and private keys to a keystore object.
for that we do:
KeyStore sourceKeystore = KeyStore.getInstance("jks");
try (InputStream stream = new BufferedInputStream(Files.newInputStream(sourceKeystorePath))) {
sourceKeystore.load(stream, sourceKeystorePassword);
}
KeyStore destKeystore = KeyStore.getInstance("jks");
destKeystore.load(null, destKeystorePassword);
Enumeration<String> aliasList = sourceKeystore.aliases();
while (aliasList.hasMoreElements()) {
String alias = aliasList.nextElement();
destKeystore.setCertificateEntry(alias, sourceKeystore.getCertificate(alias));
if(sourceKeystore.isKeyEntry(alias)) {
System.out.println(alias + " : is private key");
Key key = sourceKeystore.getKey(alias, "secret".toCharArray());
Certificate[] chain = new Certificate[1];
chain[0] = sourceKeystore.getCertificate(alias);
destKeystore.setKeyEntry(alias, key, "secret".toCharArray(), chain);
}
}
try (OutputStream stream = new BufferedOutputStream(Files.newOutputStream(destKeystorePath))) {
destKeystore.store(stream, destKeystorePassword);
}
What I want to undertstand is destKeystore.setKeyEntry()
. When I give a cert chain as a parameter in this can I give an array of certs like this?
First Question: what does these various ways of setting the chain mean?
Second question: Also if I have a JKS file. How do I find this exact value of certificate chain and in which order the certificate chain was set for a private key in this KeyStore? basically what I mean is I want to find out what was the Certificate[] parameter passed to KeyStore.setKeyEntry() in that JKS file
First, the basics of how the certificate chain is formed.
When you initially create a key pair
by any means (keytool, openssl, etc,.), it basically consists of a private key
associated with its self-signed certificate
, where the self-signed certificate contains the public key
. And then a PKCS#10
(certificate signing request) is created out of the key-pair, which is basically some identity information about the owner of the private key + public key, put together and signed by the private key. This CSR will be sent to a Certificate Authority
to get signed certificate back. The CA signs it and responds with a certificate chain. This received certificate chain is then updated to the initially created private key, replacing the old self-signed certificate. Now, we call this key pair a signed key pair, it is not self-signed any more.
Now understanding what the CA sent. Basically a certificate chain sent by the CA looks like this:
CA Certificate (self-signed)
|
|__ 2. Sub CA Certificate (signed by the above CA)
|
|__ 1. Sub-sub CA Certificate (if any) (signed by the above Sub CA)
|
|__ 0. End Entity Certificate (your certificate, signed by the above cert)
If you look at the indexes of the certificates, they tell the following:
In coding terminology, the first (zeroth) element of the certificate array is the user certificate, and the last element of the certificate array is the CA certificate. Which means, the matching public key that belongs to your private key can be found in the first certificate.
99% of the time you don't have to deal with the order of the certificate chain yourself. When the CA responds with a certificate chain, it is usually in the correct order. All you have to do, is to update the certificate chain to your private key.
Now the answers to your questions:
Certificate[] chain = new Certificate[1]; chain[0] = sourceKeystore.getCertificate(alias); destKeystore.setKeyEntry(alias, key, "secret".toCharArray(), chain);
there is also a method available to return you the entire certificate chain that is associated with the private key getCertificateChain(). Where you can simple do:
Certificate[] chain = sourceKeystore.getCertificateChain(alias); destKeystore.setKeyEntry(alias, key, "secret".toCharArray(), chain);
The order in which the getCertificateChain()
returns the array is the way it was set in the first place.