Showing posts with label OpenSSL. Show all posts
Showing posts with label OpenSSL. Show all posts

Dumping out JKS private key

This post explains how you could programmatically access a java key store and dump its private key out.

To start with, let's create a key store with java keytool.

C:\>keytool -genkey -keystore wso2.jks -storepass wso2123 -keypass wso2123 -alias wso2
Let's look at the code now. It's self-explanatory with the attached comments.

package org.wso2;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.Key;
import java.security.KeyStore;

public class KeyExplorer {

private final static String KEY_STORE_FILE = "c:\\wso2.jks";
private final static String KEY_STORE_PASSWORD = "wso2123";
private final static String PRIVATE_KEY_PASSWORD = "wso2123";
private final static String KEY_ALIAS = "wso2";
private final static String KEY_STORE_TYPE = "jks";
private final static String OUT_PUT_FILE = "c:\\wso2.key";

public static void main(String[] args) {

KeyStore keystore = null;
Key privateKey = null;
FileOutputStream outFile = null;

try {
keystore = KeyStore.getInstance(KEY_STORE_TYPE);
keystore.load(new FileInputStream(KEY_STORE_FILE), KEY_STORE_PASSWORD.toCharArray());

if (keystore.containsAlias(KEY_ALIAS)) {
privateKey = keystore.getKey(KEY_ALIAS, PRIVATE_KEY_PASSWORD.toCharArray());
} else {
return;
}

// Returns true if the entry identified by the given alias was
// created by a call to setKeyEntry, or created by a call to
// setEntry with a PrivateKeyEntry or a SecretKeyEntry.
if (keystore.isKeyEntry(KEY_ALIAS)) {
System.out.println("PrivateKeyEntry");
}

// Returns the standard algorithm name for this key. For example,
// "DSA" would indicate that this key is a DSA key.
System.out.println("Algorithm: " + privateKey.getAlgorithm());

// Returns the name of the primary encoding format of this key, or
// null if this key does not support encoding. The primary encoding
// format is named in terms of the appropriate ASN.1 data format, if
// an ASN.1 specification for this key exists. For example, the name
// of the ASN.1 data format for public keys is SubjectPublicKeyInfo,
// as defined by the X.509 standard; in this case, the returned
// format is "X.509". Similarly, the name of the ASN.1 data format
// for private keys is PrivateKeyInfo, as defined by the PKCS #8
// standard; in this case, the returned format is "PKCS#8".
System.out.println("Key format: " + privateKey.getFormat());

outFile = new FileOutputStream(OUT_PUT_FILE);
outFile.write(privateKey.getEncoded());
outFile.flush();

} catch (Exception e) {
e.printStackTrace();
} finally {
if (outFile != null) {
try {
outFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
The above will output the private key in a binary format - let's see how we could convert it to Base64 with OpenSSL.

You can download OpenSSL for Windows from here.

openssl enc -in wso2.key -out wso2-txt.key -a
The "enc" command does various types of encryptions and encodings and "-a" is for Base64 - just type "openssl enc -help" - you'll see all available options.

OpenSSL on WINDOWS

This post explains all the steps you need to create your own CA.

Let me summarize what we intend to do here.

First we will create a public cert and a private key for CA.

Then we'll create a public/private key pair for the server [say WSAS].

Next step is to generate CSR [Certificate Signing Request] for the server and submit it to the CA.

CA signs the certificate.

Then we need to convert both CAs public cert as well as the server's signed cert from PEM to DER.

After the conversion, the server will import the CA's public cert and server's signed certificate to it's key store.

That's it and we are done.

Let's get started.

First you need to download Visual C++ 2008 Redistributables from here and install it locally.

Then download and install OpensSSL from here.

Also make sure you have added [JAVA_HOME]\bin to the PATH env variable.

Let's create the folder structure for our example.

Make sure you have the following folder structure.

[SAMPLE]\ca
[SAMPLE]\ca\certs
[SAMPLE]\ca\crl
[SAMPLE]\ca\newcerts
[SAMPLE]\ca\private
[SAMPLE]\ca\index.txt
[SAMPLE]\wsas

Copy [OPENSSL_HOME]\bin\openssl.cfg to [SAMPLE]\.

Copy [OPENSSL_HOME]\bin\PEM\demoCA\serial to [SAMPLE]\ca.

Lets edit [SAMPLE]\ca\openssl.cfg - add the following section to the end of the file - make sure you do not violate the existing file structure.

####################################################################
[ WSO2WSAS_CA ]

dir = ./ca
certs = $dir/certs
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir/newcerts

certificate = $dir/cacert.pem
serial = $dir/serial
crlnumber = $dir/crlnumber

crl = $dir/crl.pem
private_key = $dir/private/cakey.pem
RANDFILE = $dir/private/.rand

x509_extensions = usr_cert


default_days = 365
default_crl_days = 30
default_md = sha1
preserve = no

policy = policy_anything

[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
Find the following section in [SAMPLE]\ca\openssl.cfg - and edit as below.

####################################################################
[ ca ]
#default_ca = CA_default
default_ca = WSO2WSAS_CA

####################################################################
Lets create public/private key pair for CA first. Once you are asked to input, do it approriately.

[SAMPLE]\>openssl req -x509 -newkey rsa:1024 -keyout ca\private\cakey.pem -out ca\cacert.pem -config openssl.cfg
Now we can create the public/private key pair for server and generate the CSR.

[SAMPLE]\>keytool -genkey -alias wso2wsas -keyalg RSA -keystore wsas\wso2wsas.jks

[SAMPLE]\>keytool -certreq -keystore wsas\wso2wsas.jks -alias wso2wsas -file wsas\wso2wsas.cert.req
Next, CA can sign the server cert.

[SAMPLE]\>openssl ca -config openssl.cfg -out wsas\wso2wsas.pem -infiles wsas\wso2wsas.cert.req
Now we need to convert both CAs public cert as well as the server's signed cert from PEM to DER.

[SAMPLE]\>openssl x509 -outform DER -in wsas\wso2wsas.pem -out wsas\wso2wsas.cert

[SAMPLE]\>openssl x509 -outform DER -in ca\cacert.pem -out wsas\wso2wsasca.cert
After the conversion, the server can import the CA's public cert and server's signed certificate to it's key store.

[SAMPLE]\>keytool -import -file wsas\wso2wsasca.cert -alias wso2wsasca -keystore wsas\wso2wsas.jks

[SAMPLE]\>keytool -import -file wsas\wso2wsas.cert -alias wso2wsas -keystore wsas\wso2wsas.jks
That's it and we are done.

Creating a new JKS with an existing private key and a signed certificate

You have your own private key and a CA signed certificate - and now you want to import both the key and the certificate to a new JKS.

This is how we do it and you need to have OpenSSL installed.

For Windows you can download Win32 OpenSSL v0.9.8g from here.Once installed make sure you add C:\OpenSSL\bin [i.e [INSTALLED_LOCATION]\bin] to the PATH env variable.

If your key and certificate are in PEM format, then you need to convert them into DER format. [privateKey.pem & signedCert.pem]

:\> openssl pkcs8 -topk8 -nocrypt -in privateKey.pem -inform PEM -out privateKey.der -outform DER

:\>openssl x509 -in signedCert.pem -inform PEM -out signedCert.der -outform DER


Copy the resulted signedCert.der and privateKey.der to c:\keys.

Java keytool does not support a direct way of importing an existing private key to a new key store. So, we'll be doing it programmatically.

You can download the code from here and copy it to c:\keys.

c:\keys\>javac BuildJKS.java

c:\keys\>java BuildJKS privateKey.der signedCert.der mykeyalias MyJKS.jks keypassword storepassword


The above will create a JKS with the name MyJKS.jks and the key store password will be storepassword while the private key password is keypassword. Also the alias of the imported key is mykeyalias.

To verify that the JKS being created properly just issue the following command to list certificates stored in the key store.

c:\keys\>keytool -list -keystore MyJKS.jks -storepass storepassword

Deploying WSO2 Identity Solution in production with custom certificates

WSO2 Identity Solution comes with a certificate for the 'localhost' signed by a sample CA.

In a production environment you need to setup your own certificate to work with the WSO2 Identity Solution and this post explains how to do it.

These are the steps you need to do.

1. Create a private/public key pair for your server [say, identity-provider]
2. Create a sample CA
3. Get your public key signed by your CA
4. Download and install WSO2 Identity Solution
5. Configure Identity Solution to use your certificate for identity-provider

In this case, we'll be creating the certificate for the host name 'identity-provider' - to test this scenario as it is, please add the following entry to the C:\windows\system32\drivers\etc\hosts file.

127.0.0.1 identity-provider

We use OpenSSL to build the required CA infrastructure. For Windows you can download Win32 OpenSSL v0.9.8g from here.Once installed make sure you add C:\OpenSSL\bin [i.e [INSTALLED_LOCATION]\bin] to the PATH env variable.

Create a folder "keystore" locally and inside that folder create two sub folders, "CA" and "IS".

From the "keystore" folder,

:\> cd IS

Creating private/public key pair for the server.

:\> keytool -genkey -alias identity-provider -keyalg RSA -sigalg MD5withRSA -keysize 1024 -dname "CN=identity-provider,L=SL,S=WS,C=LK" -keypass wso2is -keystore wso2is.jks -storepass wso2is

Creating a certificate signing request.

:\> keytool -certreq -v -alias identity-provider -file ../CA/csr.pem -keypass wso2is -storepass wso2is -keystore wso2is.jks

Building the CA infrastructure.

:\> cd ../CA

Creating CA public/private key pair - you need to give a password when requested.

:\> openssl req -x509 -newkey rsa:1024 -md5 -keyout wso2cakey.pem -out wso2cacert.crt

Signing the server certificate.

:\> openssl x509 -req -days 365 -md5 -in csr.pem -CA wso2cacert.crt -CAkey wso2cakey.pem -CAcreateserial -out ../IS/iscert.crt

:\> cd ../IS

Importing CA public certificate to the server keystore.

:\> keytool -import -alias wso2ca -file ../CA/wso2cacert.crt -keystore wso2is.jks -storepass wso2is

Importing the signed server certificate to the server keystore.

:\> keytool -import -alias identity-provider -file iscert.crt -keystore wso2is.jks -storepass wso2is -keypass wso2is

At the end of this process, you'll end up with a keystore, wso2is.jks at [keystore]\IS. The password we provided for this keystore and it's private key is wso2is.

Now let's download the WSO2 Identity Solution from here and unzip it to a local location.

You also need to download Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 5.0 from here and copy the two jar files from the extracted jce directory (local_policy.jar and US_export_policy.jar) to $JAVA_HOME/jre/lib/security.

Now copy [keystore]\IS\wso2is.jks to [IS_UNZIPPED_LOCATION]\conf and replace the existing one.

Open the file [IS_UNZIPPED_LOCATION]\conf\server.xml and do a find for 'localhost' and do a replace all with 'identity-provider'.

That's all you need to do - to get this working.

Anyway following section in the same file is useful to have a look.

<KeyStore>
  <!-- Keystore file location-->
  <Location>${wso2wsas.home}/conf/wso2is.jks</Location>
  <!-- Keystore type (JKS/PKCS12 etc.)-->
  <Type>JKS</Type>
  <!-- Keystore password-->
  <Password>wso2is</Password>
  <!-- Private Key alias-->
  <KeyAlias>identity-provider</KeyAlias>
  <!-- Private Key password-->
  <KeyPassword>wso2is</KeyPassword>
</KeyStore>

Now, you can start the server with [IS_UNZIPPED_LOCATION]\bin\wso2is.bat.

Just type https://identity-provider:12443 to access the Identity Provider home page.

You may see browser indicating a warning here - that is because our CA is not trusted by the browser. To avoid that you can simply add our CA cert to the trusted CA certificate store.