Monday, March 8, 2010

Spring JCE / PKCS11

At work we have a need to integrate JCE with network crypto boxes. Turns out, with Spring, it's almost completely trivial.

If you're going to be using either a smart card or a network crypto provider, what you're likely to wind up with is a PKCS11 module for your platform. Sun provides for JCE a PKCS11 JCE Provider shim.

First, there is a very handy Spring idiom for adding providers to JCE at runtime. Here's how you can load BouncyCastle, for example, in a Spring application context as a throw-away bean (from this post at the SpringSource forums):


<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="java.security.Security.addProvider"/>
<property name="arguments">
<list>
<bean class="org.bouncycastle.jce.provider.BouncyCastleProvider"/>
</list>
</property>
</bean>


You can add the PKCS11 provider in almost exactly the same way. The only change is how you declare the actual provider bean within the <list>:


<bean class="sun.security.pkcs11.SunPKCS11">
<constructor-arg>
<bean class="PKCS11ConfigFactoryBean">
<property name="modulePath" value="path/to/pkcs11/module"/>
</bean>
</constructor-arg>
</bean>


The PKCS11ConfigFactoryBean's job is to spit out an InputStream, which it creates from a mock configuration file that it creates from various properties. You can check the PKCS11 provider's documentation for the complete list of the contents of the config file, but at the very least, it has to contain a line that says "library=path/to/pkcs11/module". After filling a StringBuffer with the configuration options (don't forget to separate each line with \n), the getObject() method should return new ByteArrayInputStream(string.toBytes()).

Once you have the provider, you'll want to obtain a keystore. Your actual working code should be in the form of a bean that has a java.security.KeyStore property. You'll use the KeyStore to obtain the certificates and keys that are stored in the hardware. Spring provides the KeyStoreFactoryBean to fetch, load and initialize the keystore and plug it into your code. Just specify that you want a type "PKCS11" keystore and use the PIN as the password. You can then look up the certs and private keys and use them as normal. Of course, the PrivateKey object you get back won't actually be the key - calling getEncoded() on it, for example, won't work - it'll just be a sham object that provides a pointer to the actual key when it comes time to use it.

3 comments:

Unknown said...

FYI, all classes that are in packages that begin with sun. (instead of java. or javax.) are not considered to be exposed as the public API of java and should not be used.

http://java.sun.com/products/jdk/faq/faq-sun-packages.html

Nick said...

You're right - the PKCS11 provider is not a feature of the JCE or java API, but it is a feature of the Sun implementation of the JRE.

All the better reason that this is all set up via IoC. You can parameterize the class name if you need to run with an alternate implementation that has a different provider.

Lakshman said...

You code is unreadable. I'am unable to copy the code. Please post it in a syntax highting block. THanks