Generate certificate in Java -- Store certificate in KeyStore

English 简体中文 繁体中文 ภาษาไทย Tiếng Việt
Summary

Storing a private key and its associated certificate chain in a Java KeyStore is crucial for secure SSL communication. The process involves initializing a KeyStore instance, typically JKS, loading it (either empty or existing), and then using setKeyEntry() with an alias, the private key, its password, and the certificate chain. After storing, the KeyStore is persisted to a file, and the chain can later be retrieved via getCertificateChain() using the entry's alias. A complete Java program demonstrates generating a root, intermediate, and leaf certificate chain, storing it, and then reloading and displaying its contents.

之前的文章中,我們已經解釋了如何在 Java 中建立憑證鏈。產生鏈之後,我們需要將其儲存在某處,以便稍後在進行實際的 SSL 通訊時可以使用它,無論是在金鑰儲存庫還是信任儲存庫中。這篇文章將向您展示如何將私鑰及其關聯的憑證鏈儲存在金鑰儲存庫檔案中。

在 Java 中有不同類型的金鑰儲存庫,在這篇文章中,我們將選擇 JKS 來演示如何儲存憑證鏈。當將私鑰條目儲存到金鑰儲存庫時,我們也需要儲存其關聯的憑證鏈。通常,我們需要給條目一個別名來識別該條目。以下是將條目儲存到金鑰儲存庫的程式碼片段:

KeyStore keyStore=KeyStore.getInstance("jks");
keyStore.load(null,null);

keyStore.setKeyEntry(alias, key, password, chain);
keyStore.store(new FileOutputStream(keystore),password);

首先,我們將載入一個空的 keystore,如果您已經有一個 keystore,可以替換:

keyStore.load(null,null);

keyStore.load(new FileInputStream(keystore),password);

載入金鑰儲存庫後,我們可以通過呼叫 setKeyEntry 並傳遞別名、私鑰、金鑰保護密碼和關聯的憑證鏈來設定條目。然後我們呼叫 keyStore.store() 來儲存條目。請注意,在某些硬體金鑰儲存庫中,我們不需要呼叫 keyStore.store() 方法來儲存金鑰儲存庫,setKeyEntry() 將自動將條目放入硬體中。

我們可以通過呼叫

keyStore.getCertificateChain() 方法並指定別名來從金鑰儲存庫中檢索憑證鏈。

Certificate[] certs=keyStore.getCertificateChain(alias);

以下是一個可行的程式,演示如何儲存和檢索憑證鏈。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;

//import javax.security.cert.Certificate;


import sun.security.x509.BasicConstraintsExtension;
import sun.security.x509.CertAndKeyGen;
import sun.security.x509.CertificateExtensions;
import sun.security.x509.CertificateIssuerName;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;

public class CertificateChainGeneration {
	public static void main(String[] args){
		try{
			//Generate ROOT certificate
			CertAndKeyGen keyGen=new CertAndKeyGen("RSA","SHA1WithRSA",null);
			keyGen.generate(1024);
			PrivateKey rootPrivateKey=keyGen.getPrivateKey();
			
			X509Certificate rootCertificate = keyGen.getSelfCertificate(new X500Name("CN=ROOT"), (long) 365 * 24 * 60 * 60);
	        
			//Generate intermediate certificate
			CertAndKeyGen keyGen1=new CertAndKeyGen("RSA","SHA1WithRSA",null);
			keyGen1.generate(1024);
			PrivateKey middlePrivateKey=keyGen1.getPrivateKey();
			
			X509Certificate middleCertificate = keyGen1.getSelfCertificate(new X500Name("CN=MIDDLE"), (long) 365 * 24 * 60 * 60);
	        
			//Generate leaf certificate
			CertAndKeyGen keyGen2=new CertAndKeyGen("RSA","SHA1WithRSA",null);
			keyGen2.generate(1024);
			PrivateKey topPrivateKey=keyGen2.getPrivateKey();
			
			X509Certificate topCertificate = keyGen2.getSelfCertificate(new X500Name("CN=TOP"), (long) 365 * 24 * 60 * 60);
	        
			rootCertificate   = createSignedCertificate(rootCertificate,rootCertificate,rootPrivateKey);
	        middleCertificate = createSignedCertificate(middleCertificate,rootCertificate,rootPrivateKey);
	        topCertificate    = createSignedCertificate(topCertificate,middleCertificate,middlePrivateKey);
	        
	        X509Certificate[] chain = new X509Certificate[3];
	        chain[0]=topCertificate;
	        chain[1]=middleCertificate;
	        chain[2]=rootCertificate;
	        
	        String alias = "mykey";
	        char[] password = "password".toCharArray();
	        String keystore = "testkeys.jks";
	        
	        //Store the certificate chain
	        storeKeyAndCertificateChain(alias, password, keystore, topPrivateKey, chain);
	        //Reload the keystore and display key and certificate chain info
	        loadAndDisplayChain(alias, password, keystore);
	        //Clear the keystore
	        clearKeyStore(alias, password, keystore);
		}catch(Exception ex){
			ex.printStackTrace();
		}
	}
	
	private static void storeKeyAndCertificateChain(String alias, char[] password, String keystore, Key key, X509Certificate[] chain) throws Exception{
		KeyStore keyStore=KeyStore.getInstance("jks");
		keyStore.load(null,null);
		
		keyStore.setKeyEntry(alias, key, password, chain);
		keyStore.store(new FileOutputStream(keystore),password);
	}
	
	private static void loadAndDisplayChain(String alias,char[] password, String keystore) throws Exception{
		//Reload the keystore
		KeyStore keyStore=KeyStore.getInstance("jks");
		keyStore.load(new FileInputStream(keystore),password);
		
		Key key=keyStore.getKey(alias, password);
		
		if(key instanceof PrivateKey){
			System.out.println("Get private key : ");
			System.out.println(key.toString());
			
			Certificate[] certs=keyStore.getCertificateChain(alias);
			System.out.println("Certificate chain length : "+certs.length);
			for(Certificate cert:certs){
				System.out.println(cert.toString());
			}
		}else{
			System.out.println("Key is not private key");
		}
	}
	
	private static void clearKeyStore(String alias,char[] password, String keystore) throws Exception{
		KeyStore keyStore=KeyStore.getInstance("jks");
		keyStore.load(new FileInputStream(keystore),password);
		keyStore.deleteEntry(alias);
		keyStore.store(new FileOutputStream(keystore),password);
	}
	
	private static X509Certificate createSignedCertificate(X509Certificate cetrificate,X509Certificate issuerCertificate,PrivateKey issuerPrivateKey){
		try{
			Principal issuer = issuerCertificate.getSubjectDN();
	        String issuerSigAlg = issuerCertificate.getSigAlgName();
	        
	        byte[] inCertBytes = cetrificate.getTBSCertificate();
	        X509CertInfo info = new X509CertInfo(inCertBytes);
	        info.set(X509CertInfo.ISSUER, new CertificateIssuerName((X500Name) issuer));
	        
	        //No need to add the BasicContraint for leaf cert
	        if(!cetrificate.getSubjectDN().getName().equals("CN=TOP")){
		        CertificateExtensions exts=new CertificateExtensions();
		        BasicConstraintsExtension bce = new BasicConstraintsExtension(true, -1);
		        exts.set(BasicConstraintsExtension.NAME,new BasicConstraintsExtension(false, bce.getExtensionValue()));
		        info.set(X509CertInfo.EXTENSIONS, exts);
	        }
	        
	        X509CertImpl outCert = new X509CertImpl(info);
	        outCert.sign(issuerPrivateKey, issuerSigAlg);
	        
	        return outCert;
		}catch(Exception ex){
			ex.printStackTrace();
		}
		return null;
	}
}

我們將在未來的文章中介紹憑證的不同擴展。

JAVA CERTIFICATE CHAIN KEYSTORE

  RELATED

  COMMENTS

10
Anonymous
Nov 21, 2017 at 7:57 am

the above code give that error to me when i run this on java netbeans.

java.security.cert.CertificateException: Issuer class type invalid.

at sun.security.x509.X509CertInfo.setIssuer(X509CertInfo.java:860)

at sun.security.x509.X509CertInfo.set(X509CertInfo.java:403)

at certchain.CertificateChainGeneration.createSignedCertificate(CertificateChainGeneration.java:123)

at certchain.CertificateChainGeneration.main(CertificateChainGeneration.java:56)

java.lang.NullPointerException

at certchain.CertificateChainGeneration.createSignedCertificate(CertificateChainGeneration.java:118)

at certchain.CertificateChainGeneration.main(CertificateChainGeneration.java:57)

java.lang.NullPointerException

at certchain.CertificateChainGeneration.createSignedCertificate(CertificateChainGeneration.java:118)

at certchain.CertificateChainGeneration.main(CertificateChainGeneration.java:58)

java.lang.NullPointerException

at sun.security.provider.JavaKeyStore.engineStore(JavaKeyStore.java:577)

at sun.security.provider.JavaKeyStore$JKS.engineStore(JavaKeyStore.java:56)

at sun.security.provider.KeyStoreDelegator.engineStore(KeyStoreDelegator.java:195)

at sun.security.provider.JavaKeyStore$DualFormatJKS.engineStore(JavaKeyStore.java:70)

at java.security.KeyStore.store(KeyStore.java:1377)

at certchain.CertificateChainGeneration.storeKeyAndCertificateChain(CertificateChainGeneration.java:85)

at certchain.CertificateChainGeneration.main(CertificateChainGeneration.java:70)

Ke Pi
Nov 21, 2017 at 11:45 am

Which version of Java you are using? 

Anonymous
Nov 22, 2017 at 8:50 am

thanks its resolved now !

but i can u tell me how i convert jks file in .cert file i want to deploy certificate chain file in my browser.

please let me now ASAP .

Ke Pi
Nov 22, 2017 at 10:43 am

You can simply use the keytool provided by JDK. 

To list all certificates, run

keytool -list -keystore test.jks -rfc

To list a certificate or certificate chain with specific alias, run

keytool -list -alias leaf -keystore test.jks -rfc

You simply need to copy the below portion to a cert file.

-----BEGIN CERTIFICATE-----

MIICmjCCAligAwIBAgIESf24ljALBgcqhkjOOAQDBQAwDTELMAkGA1UEAxMCQ0EwHhcNMTUxMjE3

MTI0NDUxWhcNMTYwMzE2MTI0NDUxWjAPMQ0wCwYDVQQDEwRMZWFmMIIBuDCCASwGByqGSM44BAEw

ggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbL

m1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNa

FpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7L

vKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwW

eotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFM

O/7PSSoDgYUAAoGBAJeZBwSThPLWJgKqGGYovL+867P4e+U3rjYvQtYMuX1cS+dEds3hxgWGUlcW

6/ss43N2L1XG2jn5okiwL5JDGShmVkIqZ00ndjhGpDx86pj8p6VvNlFjvKU+huLk5OnLqdgtBZzE

xvw/qJ2RA332POV88hpOwo4nzoYOpXXnx9pio0IwQDAfBgNVHSMEGDAWgBQkZybun0K+v86ei02O

Hr2vl4I95DAdBgNVHQ4EFgQUIxnQWEhrQUsOJEI6/2A4afFjERIwCwYHKoZIzjgEAwUAAy8AMCwC

FAJsk2SwPh1svZwmTqOmrEbtf3OqAhQyoNCxJff8HfTktjOSqutkjme43w==

-----END CERTIFICATE-----

 

Anonymous
Jan 3, 2018 at 1:44 am

How do you solved this exception?

Vivek
Sep 25, 2018 at 9:56 am

I am getting below exceptions, when executing the given code :

 

java.security.cert.CertificateException: Issuer class type invalid.

at sun.security.x509.X509CertInfo.setIssuer(X509CertInfo.java:860)

at sun.security.x509.X509CertInfo.set(X509CertInfo.java:403)

at testsample.Cert.createSignedCertificate(Cert.java:114)

at testsample.Cert.main(Cert.java:47)

java.lang.NullPointerException

at testsample.Cert.createSignedCertificate(Cert.java:109)

at testsample.Cert.main(Cert.java:48)

java.lang.NullPointerException

at testsample.Cert.createSignedCertificate(Cert.java:109)

at testsample.Cert.main(Cert.java:49)

java.lang.NullPointerException

at sun.security.provider.JavaKeyStore.engineStore(JavaKeyStore.java:577)

at sun.security.provider.JavaKeyStore$JKS.engineStore(JavaKeyStore.java:56)

at sun.security.provider.KeyStoreDelegator.engineStore(KeyStoreDelegator.java:195)

at sun.security.provider.JavaKeyStore$DualFormatJKS.engineStore(JavaKeyStore.java:70)

at java.security.KeyStore.store(KeyStore.java:1377)

at testsample.Cert.storeKeyAndCertificateChain(Cert.java:76)

at testsample.Cert.main(Cert.java:61)

 

 

Please help, I am using jdk 1.8.162 version.

Vivek
Sep 26, 2018 at 1:04 pm

I am able to execute the code and it is working fine. But when I am trying to list the certificates using KeyTool with command "keytool -list -keystore test.jks -rfc" then I am getting below message :

 

Enter keystore password:

Keystore type: JKS

Keystore provider: SUN

 

 

Your keystore contains 0 entries

 

 

It is not showing any entry, please help

Ke Pi
Sep 27, 2018 at 9:52 am

The output shows that the keystore contains no entry. Are you sure you saved the keystore correctly? Also can you add -v when you run the list command.

ankit
Apr 6, 2019 at 3:33 am

will itworkwith java 9 and latest versions..

i believe sun.security is not supported by java 9

Ankit
Apr 6, 2019 at 3:35 am

pl help me with latest codes for self signed X509 certificate generation on java 9 or latest versions..