A CSR(Certificate Signing Request) is a kind of request generated by an application and is to be sent to a Certificate Authority to create a signed certificate which can be distributed. It usually contains certificate information such as subject name, public key info and signature info.
In Java, keytool can be used to generate a certificate request with option -certreq. But sometimes if an application wants to create a CSR programmatically, keytool will not do a favor, instead you should use APIs provided by Java to generate CSRs.
Basically the steps to generate a CSR are :
- Get the keypair which the CSR is requested for. It can be generated with KeyPairGenerator or can get loaded from keystore(Preferred)
- Create the subject for the certificate request and also create a signature for the certificate request
- Sign the certificate request with the private key from the keypair in #1
- Get the encoded certificate request data and store it and sent it to the CA to create the certificate.
For a demo purpose, we will get the keypair using KeyPairGenerator, but in real application, it's better to have the keypair stored in a keystore.
Below is an example to create the certificate request with RSA.
public class CSRGenerator { public static void main(String[] args) { CSRGenerator csrGeneration = new CSRGenerator(); // Generate key pair KeyPair keyPair = csrGeneration.generateKeyPair("RSA", 1024); System.out.println("KeyPair generated"); byte[] csrData = csrGeneration.generateCSR("SHA256WithRSA", keyPair); System.out.println(new String(csrData)); } /** * Generate the desired CSR for signing * * @param sigAlg * @param keyPair * @return */ byte[] generateCSR(String sigAlg, KeyPair keyPair) { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); PrintStream printStream = new PrintStream(outStream); try { X500Name x500Name = new X500Name("CN=EXAMPLE.COM"); Signature sig = Signature.getInstance(sigAlg); sig.initSign(keyPair.getPrivate()); PKCS10 pkcs10 = new PKCS10(keyPair.getPublic()); // pkcs10.encodeAndSign(new X500Signer(sig, x500Name)); // For Java 6 pkcs10.encodeAndSign(x500Name, sig); // For Java 7 and Java 8 pkcs10.print(printStream); byte[] csrBytes = outStream.toByteArray(); return csrBytes; } catch (Exception ex) { ex.printStackTrace(); } finally { if(null != outStream) { try { outStream.close(); } catch (IOException e) { e.printStackTrace(); } } if(null != printStream) { printStream.close(); } } return new byte[0]; } /** * Generate the desired keypair * * @param alg * @param keySize * @return */ KeyPair generateKeyPair(String alg, int keySize) { try{ KeyPairGenerator keyPairGenerator = null; keyPairGenerator = KeyPairGenerator.getInstance(alg); keyPairGenerator.initialize(keySize); return keyPairGenerator.generateKeyPair(); } catch (Exception ex) { ex.printStackTrace(); } return null; } }
Note that there is some difference between Java 6 and Java 7 while calling PKCS10.encodeAndSign(). Java 7 doesn't have X500Signer anymore.
If you are using IBM Java instead of Oracle Java, it's different on how the certificate request can be generated. See below.
public class CSRGenerator { public static void main(String[] args) { CSRGenerator csrGeneration = new CSRGenerator(); // Generate key pair KeyPair keyPair = csrGeneration.generateKeyPair("RSA", 1024); System.out.println("KeyPair generated"); byte[] csrData = csrGeneration.generateCSR("SHA256WithRSA", keyPair); System.out.println(new String(csrData)); } /** * Generate the desired CSR for signing * * @param sigAlg * @param keyPair * @return */ byte[] generateCSR(String sigAlg, KeyPair keyPair) { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); PrintStream printStream = new PrintStream(outStream); try { X500Name x500Name = new X500Name("CN=EXAMPLE.COM"); CertificateExtensions ext = new CertificateExtensions(); PKCSAttributes attrs = new PKCSAttributes().addAttribute(new PKCSAttribute(PKCSOID.EXTENSION_REQUEST_OID, ext)); CertificationRequestInfo certInfo = new CertificationRequestInfo(x500Name, keyPair.getPublic(), attrs); CertificationRequest request = new CertificationRequest(certInfo); request = request.sign(sigAlg, keyPair.getPrivate()); request.print(printStream); byte[] csrBytes = outStream.toByteArray(); return csrBytes; } catch (Exception ex) { ex.printStackTrace(); } finally { if(null != outStream) { try { outStream.close(); } catch (IOException e) { e.printStackTrace(); } } if(null != printStream) { printStream.close(); } } return new byte[0]; } /** * Generate the desired keypair * * @param alg * @param keySize * @return */ KeyPair generateKeyPair(String alg, int keySize) { try{ KeyPairGenerator keyPairGenerator = null; keyPairGenerator = KeyPairGenerator.getInstance(alg); keyPairGenerator.initialize(keySize); return keyPairGenerator.generateKeyPair(); } catch (Exception ex) { ex.printStackTrace(); } return null; } }
The certificate request generated in BASE64 encoding should look like below :
-----BEGIN NEW CERTIFICATE REQUEST----- MIIBZjCB0AIBADAWMRQwEgYDVQQDEwtFWEFNUExFLkNPTTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw gYkCgYEAgXneACRkW0QvpuuNhzo8OOmxe7xPzd3UZJ9MOEA5VhP5QvWGMGFNITGmubL1I2AWmsHz yMxwO0SHPFNclo4oSm+Cu2d67d28vingYBGEBrVXIwg3j1CVADcGjb39TcYL77fofBem8XNDCw0N WKLaTqpnVaAtqvnE0+r7O3BZZg8CAwEAAaARMA8GCSqGSIb3DQEJDjECMAAwDQYJKoZIhvcNAQEL BQADgYEAb5jNx6ASGpgTXTNz5UrD6BrTyLZYyTmlQwI0EjhG0lVY5sYiQGz7t6JQP62aqRFfM7vo dYMnKxeuApp5LSY3EdyY1F5I20PPTbpSSP529pV5gIQZk4FZMoth7dvWgBH3pqB0BkHQ1g+wdWof m2imkOR1D+7Yn6xvQ/Be9mXienU= -----END NEW CERTIFICATE REQUEST-----
Hope this help you if you are struggling with the certificate request generation in Java.