Generate signed certificate from CSR in Java

  sonic0002        2020-10-24 07:03:17       7,886        10    

In our previous tutorial, we have explained how to generate CSR which can be sent to CA for generating a signed certificate. In this tutorial, we will explain how to generate the signed certificate from CSR in Java. We will not use an actual CA but a self-signed certificate to act as a CA certificate.

Since the CSR contains the subject information where a certificate needs to be generated and signed for. The key here is to extract the subject information from the CSR and then set it as the subject of the newly generated certificate.

The source code can be found below which has a complete example of generating and signing the certificate from CSR.

package security.signcsr;

import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Random;

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;

import sun.misc.BASE64Encoder;
import sun.security.pkcs10.PKCS10;
import sun.security.provider.X509Factory;
import sun.security.tools.keytool.CertAndKeyGen;
import sun.security.util.DerValue;
import sun.security.x509.AlgorithmId;
import sun.security.x509.CertificateAlgorithmId;
import sun.security.x509.CertificateExtensions;
import sun.security.x509.CertificateSerialNumber;
import sun.security.x509.CertificateSubjectName;
import sun.security.x509.CertificateValidity;
import sun.security.x509.CertificateVersion;
import sun.security.x509.CertificateX509Key;
import sun.security.x509.Extension;
import sun.security.x509.KeyUsageExtension;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;

public class CSRSigner {
	private static final String SIGNATURE_ALGORITHM = "SHA1WITHRSA";
	private static final long VALIDITY_DAYS = 365L;

	public static byte[] sign(PKCS10 csr, X509CertImpl signerCert, PrivateKey signerPrivKey) throws CertificateException, IOException, InvalidKeyException, SignatureException {
	    /*
	     * The code below is partly taken from the KeyTool class in OpenJDK7.
	     */
	    X509CertInfo signerCertInfo = (X509CertInfo) signerCert.get(X509CertImpl.NAME + "." + X509CertImpl.INFO);
	    X500Name issuer = (X500Name) signerCertInfo.get(X509CertInfo.SUBJECT + "." + CertificateSubjectName.DN_NAME);

	    /*
	     * Set the certificate's validity:
	     * From now and for VALIDITY_DAYS days 
	     */
	    Date firstDate = new Date();
	    Date lastDate = new Date();
	    lastDate.setTime(firstDate.getTime() + VALIDITY_DAYS * 1000L * 24L * 60L * 60L);
	    CertificateValidity interval = new CertificateValidity(firstDate, lastDate);

	    /*
	     * Initialize the signature object
	     */
	    Signature signature;
	    try {
	        signature = Signature.getInstance(SIGNATURE_ALGORITHM);
	    } catch (NoSuchAlgorithmException e) {
	        throw new RuntimeException(e);
	    }
	    signature.initSign(signerPrivKey);

	    // create the certificate info
	    X509CertInfo certInfo = new X509CertInfo();
	    certInfo.set(X509CertInfo.VALIDITY, interval);
	    certInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(new Random().nextInt() & 0x7fffffff));
	    certInfo.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
	    try {
	        certInfo.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(AlgorithmId.get(SIGNATURE_ALGORITHM)));
	    } catch (NoSuchAlgorithmException e) {
	        throw new RuntimeException(e);
	    }
	    certInfo.set(X509CertInfo.ISSUER, issuer);
	    certInfo.set(X509CertInfo.KEY, new CertificateX509Key(csr.getSubjectPublicKeyInfo()));
	    certInfo.set(X509CertInfo.SUBJECT, csr.getSubjectName());

	    /*
	     * Add x509v3 extensions to the container
	     */
	    CertificateExtensions extensions = new CertificateExtensions();

	    // Example extension.
	    // See KeyTool source for more.
	    boolean[] keyUsagePolicies = new boolean[9];
	    keyUsagePolicies[0] = true; // Digital Signature
	    keyUsagePolicies[2] = true; // Key encipherment
	    KeyUsageExtension kue = new KeyUsageExtension(keyUsagePolicies);
	    byte[] keyUsageValue = new DerValue(DerValue.tag_OctetString, kue.getExtensionValue()).toByteArray();
	    extensions.set(KeyUsageExtension.NAME, new Extension(
	            kue.getExtensionId(),
	            true, // Critical
	            keyUsageValue));

	    /*
	     * Create the certificate and sign it
	     */
	    X509CertImpl cert = new X509CertImpl(certInfo);
	    try {
	        cert.sign(signerPrivKey, SIGNATURE_ALGORITHM);
	    } catch (NoSuchAlgorithmException e) {
	        throw new RuntimeException(e);
	    } catch (NoSuchProviderException e) {
	        throw new RuntimeException(e);
	    }

	    /*
	     * Return the signed certificate as PEM-encoded bytes
	     */
	    ByteOutputStream bos = new ByteOutputStream();
	    PrintStream out = new PrintStream(bos);
	    BASE64Encoder encoder = new BASE64Encoder();
	    out.println(X509Factory.BEGIN_CERT);
	    encoder.encodeBuffer(cert.getEncoded(), out);
	    out.println(X509Factory.END_CERT);
	    out.flush();
	    return bos.getBytes();
	}
	
	public static void main(String[] args) {
        try{
            CertAndKeyGen keyGen=new CertAndKeyGen("RSA","SHA1WithRSA",null);
            keyGen.generate(1024);
             
            PrivateKey privKey = keyGen.getPrivateKey();
            
            //Generate self signed certificate(act as CA)
            X509Certificate[] chain=new X509Certificate[1];
            chain[0]=keyGen.getSelfCertificate(new X500Name("CN=ROOT"), (long)365*24*3600);
            
            X509CertImpl certImpl = new X509CertImpl(chain[0].getEncoded());
            
            // Generate CSR
            CSRGenerator csrGeneration = new CSRGenerator();
            KeyPair keyPair = csrGeneration.generateKeyPair("RSA", 1024);
            System.out.println("KeyPair generated");
             
            PKCS10 csrData = csrGeneration.generateCSR("SHA256WithRSA", keyPair);
            System.out.println("CSR : "+ new String(csrData.getEncoded(), StandardCharsets.UTF_8));
            
            // Get the signed certificate
            byte[] outBytes = sign(csrData, certImpl, privKey);
             
            String s = new String(outBytes, StandardCharsets.UTF_8);
            System.out.println("Certificate : " + s);
        }catch(Exception ex){
            ex.printStackTrace();
        }
	}
}

The code should be self-explained. In main(), we will first generate the CA private and public key and certificate so that they will be used to sign the CSR. And then the step to generate the CSR, the code can be found in previous tutorial.

The output of the generated and signed certificate would be like:

-----BEGIN CERTIFICATE-----
MIIBnDCCAQWgAwIBAgIEGuKmyzANBgkqhkiG9w0BAQUFADAPMQ0wCwYDVQQDEwRST09UMB4XDTIw
MTAyNDExMzYyMFoXDTIxMTAyNDExMzYyMFowFjEUMBIGA1UEAxMLRVhBTVBMRS5DT00wgZ8wDQYJ
KoZIhvcNAQEBBQADgY0AMIGJAoGBAKtN4BPnLSCD5kOObh2w11AhLr+uWMClPMQ8oMXpc63r1ez5
r1V+lCeAyqmL7cu5Oycy0s3nbTgAIpdqt1SMy+6SyuNSLtXHkkGx5Dcb188CNIM+DBvRoOE1UVep
vCFFuBOwqcgFI9yvmKeyZoONP9mDd4c7rMiJk4LkXTjrSuK1AgMBAAEwDQYJKoZIhvcNAQEFBQAD
gYEACPBIwGV5IFqrsbWk2C7cLpr8VW6djt5TzGRDEMAQVksm+V7tHn1ue//Ly19QJIUe78UBB+RA
qTnCou6jEiIYomU+wWxqsesUfLePNKNBKPQFc4jfEDx+r+/iIV06PXAUAj8NnKvaUU7xu3a/Ipms
fjWN9x7LrPUn1eBvGFbM7HU=
-----END CERTIFICATE-----

If checking the certificate information, can find its subject is EXAMPLE.COM and its issuer is ROOT which is expected. 

This code has been tested on Java 8. It may need some adjustment on other versions of Java but the general flow should be the same.

SIGN CERTIFICATE  CSR  JAVA 

       

  RELATED


  10 COMMENTS


Anonymous [Reply]@ 2020-10-24 08:06:58
// Generate CSR
            CSRGenerator csrGeneration = new CSRGenerator();
            KeyPair keyPair = csrGeneration.generateKeyPair("RSA", 1024);
            System.out.println("KeyPair generated");
             
            PKCS10 csrData = csrGeneration.generateCSR("SHA256WithRSA", keyPair);
            System.out.println("CSR : "+ new String(csrData.getEncoded(), StandardCharsets.UTF_8));

Why are we generating the csr here. If we have received a csr from the user then we only need to read that csr and generate the certificate, why there is a need of generating this csr here?.

If I have a GUI(suppose a textfield) in which user has entered the csr then how can I read that csr from there and generate certificate?

Ke Pi [Reply]@ 2020-10-24 08:17:22

this is an example. you can load the CSR from a file as well. this is just for demonstration purpose.

Anonymous [Reply]@ 2020-10-24 09:04:48

Okay

But if I want to read the csr from a textfield so then can I omit this part(generate csr) completely?

Ke Pi [Reply]@ 2020-10-25 03:21:26

that should be straight forward. just read the CSR data from the GUI as a string and convert it into a CSR object. there should be tons of samples of the web about how that can be done.

Anonymous [Reply]@ 2020-10-27 01:27:32
@Ke Pi 

Okay... thank u so much

Anonymous [Reply]@ 2020-11-26 05:23:32

How can I get a decrypted form of the output of this code?

Like here we are getting the output in encoded form, how can it be decoded and obtained in human readable certificate?

Anonymous [Reply]@ 2020-11-26 05:35:28

   PKCS10 csrData = csrGeneration.generateCSR("SHA256WithRSA", keyPair);

The above line of code is showing the following error:

"incompatible types: byte[] cannot be converted to PKCS10"

How to resolve this issue?

Anonymous [Reply]@ 2020-11-28 00:35:43

 PKCS10 csrData = csrGeneration.generateCSR("SHA256WithRSA", keyPair);

The above line of code is showing the following error:

"incompatible types: byte[] cannot be converted to PKCS10"

How to resolve this issue?

PLZ someone answer this!!

Anonymous [Reply]@ 2020-12-12 23:15:25
NfYnbxvpoiGXmZs
Anonymous [Reply]@ 2020-12-13 09:34:24

 PKCS10 csrData = csrGeneration.generateCSR("SHA256WithRSA", keyPair);

The above line of code is showing the following error:

"incompatible types: byte[] cannot be converted to PKCS10"

How to resolve this issue?

PLZ someone answer this!!



  RANDOM FUN

PHP is not affected by the bug