JKS is Java Keystore, a proprietary keystore type designed for Java. It can be used to store private keys and certificates used for SSL communication, it cannot store secret keys however. The keytool shipped with JDKs cannot extract private keys stored on JKS. This type of keystore usually has an extension of jks.
Next we will show how to operate the JKS keystore with pure Java code.
Create JKS keystore
The simplest method to create a JKS keystore to create an empty keystore. We can first get an instance of KeyStore and then load a null keystore. After loading the null keystore, we just need to call KeyStore.store() with the keystore name and password of the keystore.
Below is a simple demo:
1
2
3
4
5
6
7
8
|
try
{
KeyStore keyStore = KeyStore.getInstance(
"JKS"
);
keyStore.load(
null
,
null
);
keyStore.store(
new
FileOutputStream(
"mytestkey.jks"
),
"password"
.toCharArray());
}
catch
(Exception ex){
ex.printStackTrace();
}
|
Post execution of above call, you will see a keystore named mytestkey.jks in current working directory. Now the keystore is empty without any entries.
Store private key
Now let's store one private key and its associated certificate chain into the keystore. Note we can not store a private key without an associated certificate chain into a keystore using JDK. With some other library or native libraries, you may be able to store a private key without associated certificate chain.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
try
{
KeyStore keyStore = KeyStore.getInstance(
"JKS"
);
keyStore.load(
new
FileInputStream(
"mytestkey.jks"
),
"password"
.toCharArray());
CertAndKeyGen gen =
new
CertAndKeyGen(
"RSA"
,
"SHA1WithRSA"
);
gen.generate(
1024
);
Key key=gen.getPrivateKey();
X509Certificate cert=gen.getSelfCertificate(
new
X500Name(
"CN=ROOT"
), (
long
)
365
*
24
*
3600
);
X509Certificate[] chain =
new
X509Certificate[
1
];
chain[
0
]=cert;
keyStore.setKeyEntry(
"mykey"
, key,
"password"
.toCharArray(), chain);
keyStore.store(
new
FileOutputStream(
"mytestkey.jks"
),
"password"
.toCharArray());
}
catch
(Exception ex){
ex.printStackTrace();
}
|
First, we will create a private key and a self signed certificate and then call KeyStore.setKeyEntry() with the specified alias, key, the password for the key and its associated certificate chain. Remember we need to call KeyStore.store() to store the key into the keystore.
The alias is the label of the entry so that it can be found easily later.
Store certificate
We can store certificate on JKS keystore. The certificate to be store should be a X509Certificate. It can be stored on the keystore without associated private key. This process is similar to storing private key.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
try
{
KeyStore keyStore = KeyStore.getInstance(
"JKS"
);
keyStore.load(
new
FileInputStream(
"mytestkey.jks"
),
"password"
.toCharArray());
CertAndKeyGen gen =
new
CertAndKeyGen(
"RSA"
,
"SHA1WithRSA"
);
gen.generate(
1024
);
X509Certificate cert=gen.getSelfCertificate(
new
X500Name(
"CN=SINGLE_CERTIFICATE"
), (
long
)
365
*
24
*
3600
);
keyStore.setCertificateEntry(
"single_cert"
, cert);
keyStore.store(
new
FileOutputStream(
"mytestkey.jks"
),
"password"
.toCharArray());
}
catch
(Exception ex){
ex.printStackTrace();
}
|
Loading private key
After storing the keys, we can also load the entries inside the keystore. Here we are saying to load private key, actually it's not the case here, as we described earlier, the private key cannot be extracted from JKS using Java. Here we actually extract the certificate chain of the private key.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
try
{
KeyStore keyStore = KeyStore.getInstance(
"JKS"
);
keyStore.load(
new
FileInputStream(
"mytestkey.jks"
),
"password"
.toCharArray());
Key key = keyStore.getKey(
"alias"
,
"password"
.toCharArray());
// System.out.println("Private key : "+key.toString()); //You will get a NullPointerException if you uncomment this line
java.security.cert.Certificate[] chain = keyStore.getCertificateChain(
"mykey"
);
for
(java.security.cert.Certificate cert:chain){
System.out.println(cert.toString());
}
}
catch
(Exception ex){
ex.printStackTrace();
}
|
Note the commented line, the key will be null as expected. We can get the certificate chain as normal though.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
[
[
Version: V3
Subject: CN=ROOT
Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5
Key: Sun RSA public key, 1024 bits
modulus: 90980299845597512779139009881469177009407272139633139241921529845092210461181243924599150259446249079941561941533303439718936138867375776965995893255358889228584415558006141961051402385279285497775776996780406808976543439543789816486513982581378223575354716191394304768315366544413052547926792470794374067383
public exponent: 65537
Validity: [From: Sat Sep 06 09:57:28 CST 2014,
To: Sun Sep 06 09:57:28 CST 2015]
Issuer: CN=ROOT
SerialNumber: [ 206b697b]
]
Algorithm: [SHA1withRSA]
Signature:
0000: 53 6A FD FE E6 3A 5E 6E A6 43 C4 F4 D1 56 D4 08 Sj...:^n.C...V..
0010: 7E 3B 8B 73 68 71 56 AB 96 FE 24 E7 2D DC 04 BB .;.shqV...$.-...
0020: 14 B0 C6 71 8D F0 3E EC FE D8 5B BB 8C 0F 55 63 ...q..>...[...Uc
0030: 2B 38 8E 45 F1 2D F0 BB 8C 6D 13 A8 11 37 E1 FA +8.E.-...m...7..
0040: 77 AF C7 73 72 2B 40 4F 74 32 F6 3C 24 E6 AB ED w..sr+@Ot2.<$...
0050: 2C 6F 19 2E DC 58 5F CB 75 62 40 2F 3E BE 59 99 ,o...X_.ub@/>.Y.
0060: C0 1F 7A 70 15 AF C3 66 B3 4F C9 11 C3 45 59 EF ..zp...f.O...EY.
0070: 36 F4 1C C9 9B FA 5E 43 A0 28 DB 07 0D F2 53 6E 6.....^C.(....Sn
]
|
Loading certificate
This is similar to loading private key, we need to pass the alias of the certificate we want to extract.
1
2
3
4
5
6
7
8
9
10
|
try
{
KeyStore keyStore = KeyStore.getInstance(
"JKS"
);
keyStore.load(
new
FileInputStream(
"mytestkey.jks"
),
"password"
.toCharArray());
java.security.cert.Certificate cert = keyStore.getCertificate(
"single_cert"
);
System.out.println(cert.toString());
}
catch
(Exception ex){
ex.printStackTrace();
}
|
The output will be:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
[
[
Version: V3
Subject: CN=SINGLE_CERTIFICATE
Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5
Key: Sun RSA public key, 1024 bits
modulus: 99756834215197288877309915243024788596281418171661241282881476656110879586349799740269767889529808199104172091786860877280382867461569439907754755558759387462421169749111354565793974372777424046360810758009149155148290676527032833774084635148674232352006810533640038723102562578516643345287042787777951043863
public exponent: 65537
Validity: [From: Sat Sep 06 10:14:33 CST 2014,
To: Sun Sep 06 10:14:33 CST 2015]
Issuer: CN=SINGLE_CERTIFICATE
SerialNumber: [ 6943e549]
]
Algorithm: [SHA1withRSA]
Signature:
0000: 35 58 70 96 F4 35 82 2A 95 9F BB 31 02 6E 7C 29 5Xp..5.*...1.n.)
0010: 4A FE AF EB 2D B5 3A A7 C7 9D 4C 9A 34 2C 5C 46 J...-.:...L.4,\F
0020: C2 82 A8 AC 1A C0 98 A5 67 21 74 7B 1E E2 E5 AC ........g!t.....
0030: DE B2 1D 87 BE 16 45 9B D0 2A D3 2B F6 E1 4B 35 ......E..*.+..K5
0040: 27 8B A7 0A EF F2 07 41 90 A6 69 07 BE 87 C5 B1 '......A..i.....
0050: 54 DE DB A2 5A 41 47 3B 3F A7 74 6F 5C C8 8D B4 T...ZAG;?.to\...
0060: C8 65 2B 0F 8E 94 A8 80 C7 8B B5 78 FA C2 9C ED .e+........x....
0070: 8E EC 28 E4 8E 62 A1 59 6A BC 37 7B 0D FC C7 AF ..(..b.Yj.7.....
]
|
Import keys and certificates
This process is actually very simple, we first need to load the keystore where the certificate to be imported. Then we also need to load another keystore where we need to import certificate to. Next, we need to get the certificate from source keystore and put it into the destination keystore.
Since we cannot extract private key from JKS, so we can only import certificate to JKS. However, we can extract private keys from other types of keystore(PKCS12) and then store them in JKS keystore.
We will cover other type of keystore in future posts.