Initial Setup

First you have to create a new private key within an existing or new keystore using keytool:

keytool -genkeypair -keyalg rsa -keystore keystorename -storepass keystorepassword -alias my_new_key
  • to protect the new private key by its own keypassword within the keystore you have to add the keypass option
  • if you don’t use the keypass option the keystore password is used to protect the private key
  • accordingly in order to delete a key password (which is not possible with keytool btw), you have to copy the keystore password to the key password
  • if you want to use the key as a client certifcate use RSA as key algorithm, instead of default DSA, because many servers (e.g IBM MQ) only accept RSA client certs

The next task is to generate a CSR, even if you want to create a self signed certifcate:

keytool -certreq -alias my_new_key -keystore keystorename -storepass keystorepassword -file my_new.csr

Now it is time to either send the CSR to the CA of your choice, or to sign it by your own CA using openssl:

openssl x509 -req -in my_new.csr -CA my_ca.crt -CAkey my_ca.key -out my_new.crt -days 365 -CAcreateserial -CAserial my_ca.seq

In case your certificate is not selfsigned, you first have to import the certificate of the CA, and in case all intermediate CAs, that signed your CSR. After that, by importing the certficate the chain of trust will be established.

keytool -import -alias my_ca -file ca.crt -keystore keystorename -storepass keystorepassword

You have to enter either “yes” or use.

Finally the signed certificate has to be imported into the keystore using the same alias as the private key:

keytool -import -alias my_new_key -file my_new.crt -keystore keystorename -storepass keystorepassword

Examing the keystore

To see what’s inside any given keystore:

keytool -list -keystore keystorename

for example:

Keystore type: jks
Keystore provider: SUN

Your keystore contains 2 entries

my_key, Sep 26, 2007, keyEntry,
Certificate fingerprint (MD5): BA:22:E1:9E:9D:83:05:5A:99:42:5E:EF:62:77:DE:5A
my_ca, Sep 26, 2007, trustedCertEntry,
Certificate fingerprint (MD5): 4E:B5:B6:7A:02:F8:F8:6E:5E:79:FB:84:65:75:42:68

To get detailed information, like issuer for an alias use “-v”!

Change keystore passpharse

To change to keystore passphrase use the following keytool command:

keytool -storepasswd -keystore keystorename

If you use JDK 1.6 keytool you have to change the keypasswd for all private keys within the keystore as well!

OpenSSL and Keystores

A common task is to exchange keys and certificates between apache webserver, ssl loadbalancer or java application server such as tomcat or BEA Weblogic. This means to convert keys and certificates from PEM,DER or PKCS12 to or from java keystores. The standard keytool is able to import or export certificates, but there is no way to do so with private keys.

Export certifcate:

keytool -export -rfc -alias my_cert -file cert.crt -keystore keystorename -storepass keystorepassword

Import certificate:

keytool -import -alias my_cert -file cert.crt -keystore keystorename -storepass keystorepassword

Import private key:

In order to import an exisiting private key you first have to get and compile the ImportKey.java, see end of the page, tool. I added options to import keys and certs into an existing keystore as well as setting the keystore passphrase via the command line.

Usage: java ImportKey keyfile certfile [alias] [keystore] [keystore_passphrase]

The key has to be in DER format, which can be easily done with openssl:

openssl pkcs8 -topk8 -nocrypt -in key.pem -inform PEM -out key.der -outform DER

In case of a self signed certifcate use:

openssl x509 -in cert.pem -inform PEM -out cert.der -outform DER

If the certifcate is signed by a foreign CA or even signed by intermediate CA(s) use:

openssl crl2pkcs7 [-certfile ca_intermediate.pem] -certfile ca.pem -in cert.pem -inform PEM -out cert.der -outform DER -nocrl

This will create a PKCS#7 container using DER format including the correct certificate chain.

Then build a new keystore using both key and certificate:

java ImportKey key.der cert.der my_alias

Export private key:

This is based on information from Mark Foster’s wiki.

In order to export any private key from an existing keystore download and compile ExportPriv.java. After compiling it run:

java ExportPriv > exported.key

The key will be exported into exported.key file in PKCS#8 PEM format. This can be converted into RSA format which is needed by apache with:

openssl pkcs8 -inform PEM -nocrypt -in exported.key -out exported_rsa.key

Various needful commands

Convert PEM to PKCS12

To create a pkcs12 container from a pem private key and cert use:

openssl pkcs12 -export -in cert.pem -inkey key.pem -out cred.p12

Export key and cert from PKCS12 to PEM

If you have a pkcs12 container and its passphrase. use the following command to extract the private key and client certificate only (-clcerts), without encrypting the exported private key again (-nodes):

openssl pkcs12 -in cred.p12 -out certkey.pem -nodes -clcerts

As you will probably notice, both key and certificate are combined into one file. If you need them seperatly you can either split the file using your favorite editor by simply save everything between (and including) each of the —–BEGIN—– and —–END—– lines to separate files or use the following two commands to export them seperatly:

openssl pkcs12 -in cred.p12 -out cert.pem -nodes -clcerts -nokeys
openssl pkcs12 -in cred.p12 -out key.pem -nodes -nocerts

Remove passphrase of private key

It will prompt for current passphrase:

openssl rsa -in oldkey.pem -out newkey.pem

Change passphrase of private key

It will prompt for old passphrase and twice for new one:

openssl rsa [-des3|-aes128] -in oldkey.pem -out newkey.pem

View details of a certificate signing request CSR

openssl req -noout -text -in server.csr

Links

Graphical Keytool Tool

import java.security.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.DataInputStream;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.security.spec.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Collection;
import java.util.Iterator;

/**
 * ImportKey.java
 *
 * <p>This class imports a key and a certificate into a keystore
 * (<code>$home/keystore.ImportKey</code>). If the keystore is
 * already present, it is simply deleted. Both the key and the
 * certificate file must be in <code>DER</code>-format. The key must be
 * encoded with <code>PKCS#8</code>-format. The certificate must be
 * encoded in <code>X.509</code>-format.</p>
 *
 * <p>Key format:</p>
 * <p><code>openssl pkcs8 -topk8 -nocrypt -in YOUR.KEY -out YOUR.KEY.der
 * -outform der</code></p>
 * <p>Format of the certificate:</p>
 * <p><code>openssl x509 -in YOUR.CERT -out YOUR.CERT.der -outform
 * der</code></p>
 * <p>Import key and certificate:</p>
 * <p><code>java comu.ImportKey YOUR.KEY.der YOUR.CERT.der</code></p><br />
 *
 * <p><em>Caution:</em> the old <code>keystore.ImportKey</code>-file is
 * deleted and replaced with a keystore only containing <code>YOUR.KEY</code>
 * and <code>YOUR.CERT</code>. The keystore and the key has no password;
 * they can be set by the <code>keytool -keypasswd</code>-command for setting
 * the key password, and the <code>keytool -storepasswd</code>-command to set
 * the keystore password.
 * <p>The key and the certificate is stored under the alias
 * <code>importkey</code>; to change this, use <code>keytool -keyclone</code>.
 *
 * Created: Fri Apr 13 18:15:07 2001
 * Updated: Fri Apr 19 11:03:00 2002
 *
 * @author Joachim Karrer, Jens Carlberg
 * @version 1.1
 **/
public class ImportKey  {

    /**
     * <p>Creates an InputStream from a file, and fills it with the complete
     * file. Thus, available() on the returned InputStream will return the
     * full number of bytes the file contains</p>
     * @param fname The filename
     * @return The filled InputStream
     * @exception IOException, if the Streams couldn't be created.
     **/
    private static InputStream fullStream ( String fname ) throws IOException {
        FileInputStream fis = new FileInputStream(fname);
        DataInputStream dis = new DataInputStream(fis);
        byte[] bytes = new byte[dis.available()];
        dis.readFully(bytes);
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        return bais;
    }

    /**
     * <p>Takes two file names for a key and the certificate for the key,
     * and imports those into a keystore. Optionally it takes an alias
     * for the key.
     * <p>The first argument is the filename for the key. The key should be
     * in PKCS8-format.
     * <p>The second argument is the filename for the certificate for the key.
     * <p>If a third argument is given it is used as the alias. If missing,
     * the key is imported with the alias importkey
     * <p>The name of the keystore file can be controlled by setting
     * the keystore property (java -Dkeystore=mykeystore). If no name
     * is given, the file is named <code>keystore.ImportKey</code>
     * and placed in your home directory.
     * @param args [0] Name of the key file, [1] Name of the certificate file
     * [2] Alias for the key.
     **/
    public static void main ( String args[]) {

        // change this if you want another password by default
        String keypass = "changeit";

        // change this if you want another alias by default
        String defaultalias = "acpcas";

        // change this if you want another keystorefile by default
        String keystorename = System.getProperty("keystore");

        if (keystorename == null)
            keystorename = "keystore.ImportKey";

        // parsing command line input
        String keyfile = "";
        String certfile = "";
        if (args.length < 2 || args.length>5) {
            System.out.println("Usage: java comu.ImportKey keyfile certfile [alias] [keystore] [keystore_passphrase] ");
            System.exit(0);
        } else {
            keyfile = args[0];
            certfile = args[1];
            if (args.length>2)
                defaultalias = args[2];
            if (args.length>3)
                keystorename = args[3];
            if (args.length>4)
                keypass = args[4];
        }

        try {
            // initializing and clearing keystore
            KeyStore ks = KeyStore.getInstance("JKS", "SUN");

            try {
		ks.load(new FileInputStream ( keystorename ), keypass.toCharArray());
                System.out.println("Using keystore-file : "+keystorename);
	    } catch ( IOException e) {
                System.out.println("Creating keystore : "+keystorename);
                ks.load( null , keypass.toCharArray());
                ks.store(new FileOutputStream ( keystorename  ), keypass.toCharArray());
            }

            // loading Key
            InputStream fl = fullStream (keyfile);
            byte[] key = new byte[fl.available()];
            KeyFactory kf = KeyFactory.getInstance("RSA");
            fl.read ( key, 0, fl.available() );
            fl.close();
            PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key );
            PrivateKey ff = kf.generatePrivate (keysp);

            // loading CertificateChain
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            InputStream certstream = fullStream (certfile);

            Collection c = cf.generateCertificates(certstream) ;
            Certificate[] certs = new Certificate[c.toArray().length];

            if (c.size() == 1) {
                certstream = fullStream (certfile);
                System.out.println("One certificate, no chain.");
                Certificate cert = cf.generateCertificate(certstream) ;
                certs[0] = cert;
            } else {
                System.out.println("Certificate chain length: "+c.size());
                certs = (Certificate[])c.toArray();
            }

            // storing keystore
            ks.setKeyEntry(defaultalias, ff,
                           keypass.toCharArray(),
                           certs );
            System.out.println ("Key and certificate stored.");
            System.out.println ("Alias:"+defaultalias+"  Password:"+keypass);
            ks.store(new FileOutputStream ( keystorename ),
                     keypass.toCharArray());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

}// KeyStore
Advertisements