Introduction
This is a library to access PKCS#11 modules from the Java programming language.
It uses the Java Native Interface to access the PKCS#11 modules of smart cards
or other hardware security modules (HSM). People at IBM had the idea of
implementing such a wrapper much earlier. Their wrapper also works very well,
but one cannot use their implementation for commercial purposes or redistribute
it for any other purpose.
Please notice that this library does not come with a
JCA or JCE provider implementation. For this purpose there is a different
product - the IAIK PKCS#11 Provider.
The Layer Model of the System
Figure 1 shows the layer model of this
library. This library consists of the Object Oriented (OO) Java Wrapper API for
PKCS#11, the (non-Object Oriented) Java Wrapper API for PKCS#11 and the Native
Module of the Wrapper, the green layers in the figure. The following paragraphs
describe these parts. The lowest layer, the PKCS#11 Module of the Smart Card, is
the PKCS#11 module that the smart card manufacturer supplies. This is normally a
DLL or shared library. As the arrows show, the uppermost layer depends on the
Java Wrapper for PKCS#11, but not vice versa. This means you can use the Java
Wrapper for PKCS#11 directly and build your application upon it without using
the OO layer. This can be useful to create smaller applications, because you do
not need most of the classes of the package iaik.pkcs.pkcs11 and no class from
iaik.pkcs.pkcs11.objects and iaik.pkcs.pkcs11.parameters. The only classes from
iaik.pkcs.pkcs11 you need are the exception classes.
Figure
1
The Object-Oriented Java API for PKCS#11
This object-oriented Java API resides in the packages iaik.pkcs.pkcs11,
iaik.pkcs.pkcs11.objects and iaik.pkcs.pkcs11.parameters. It provides a straight
forward mapping of the PKCS#11 v2.20 standard to a set of classes and
interfaces. The package iaik.pkcs.pkcs11.objects is a model of the object
hierarchy presented in this PKCS#11 standard. The package
iaik.pkcs.pkcs11.parameters provides classes for objects that act as parameters
for mechanisms which require specific arguments. This layer solely builds upon
the Java API for PKCS#11 as implemented by the Java Wrapper for PKCS#11.
The Java API for PKCS#11
The non-Object Oriented Java Wrapper API for PKCS#11 is a set of Java classes
and interfaces that reflects the PKCS#11 API. It is a straightforward
realization of the data structures as defined in PKCS#11. For each structure in
the pkcs11t.h header file of PKCS#11, there is a corresponding class in the
package iaik.pkcs.pkcs11.wrapper. Notice, that this is not an object oriented
approach at this level; it is just a straightforward mapping of the data
structures to Java. All adoptions to the PKCS#11 API, including wrapping into an
object oriented approach, appear in the Object Oriented Java Wrapper API for
PKCS#11. The interface PKCS11 in the iaik.pkcs.pkcs11.wrapper package is the
interface to a PKCS#11 module and provides access to the functions defined by
PKCS#11. All names of classes, data structures and methods are the same as the
corresponding PKCS#11 counterpart. The PKCS11Connector instantiates an object
that implements this PKCS11 interface. The returned object gives access to the
PKCS#11 module of the smart card; it is the Java-Counterpart to the
CK_C_GetFunctionList returned by the C_GetFunctionList function in PKCS#11. The
Module class in the object-oriented layer provides the respective functionality.
Have a look at the demo.pkcs.pkcs11 package in the demo directory for sample
programs.
The Native Module of the Wrapper
This native module of the wrapper is responsible for translation of the Java
data structures, which the Java API for PKCS#11 part defines, to native PKCS#11
data structures and vice versa. This module of the system does not include any
additional logic, it only provides a straightforward mapping from the Java API
for PKCS#11 to the PKCS#11 Module of the Smart Card. This layer is necessary,
because the JNI requires the native functions to have a special signature that
is defined by JNI itself. PKCS#11 and JNI are not compatible as they are, and
this is the reason why this layer is necessary at all. In compiled form, this
module is a native DLL or shared library.
Compatibility
This implementation should be compatible to JDK 1.3 and higher and JNI
1.1. It relies on the PKCS#11 version 2.20 but it should also work with any 2.x driver.
The native code is written in C and can be compiled on different Windows and Unix
platforms.
Performance
Tests showed that the calls through the Java Native Interface (JNI) and the
parameter conversions do not take much time. We did a short test on an AMD
Athlon 1.4 GHz using SUN JDK 1.3.1_04. It showed that an update call to a digest
through the wrapper, providing a 1024 bytes block of data, takes not even 0.01
milliseconds on average. This time includes the Java call in the PKCS#11
Wrapper, in the native code of the wrapper (including conversion of parameters
from Java to PKCS#11 structures) and down to the call to the PKCS#11 module.
This excludes the time for the calculation time in the PKCS#11 module. We tested
this by using a dummy PKCS#11 module that does nothing in its digest functions.
The core code from the testing routine looks like this:
long t0 = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
session.digestUpdate(dataBuffer);
}
long t1 = System.currentTimeMillis();
We took a time difference of about 90 milliseconds between t1 and t0, which
results in 0.009 milliseconds per call. This value is roughly the same for a
data buffer of 1024 bytes and 4096 bytes.
Sending a file with 4.372.615 bytes to the PKCS#11 module took about 70
milliseconds sending the data in 1024 byte blocks; this results in 4271 calls to
the update method. Increasing the block size to 4096 bytes improves the
performance significantly. The test with the file includes reading the data
directly from file and feeding it to the PKCS#11 Wrapper on the fly. However, we
read the complete file once, before we did the test run, what causes the
operating system the have the file cached in memory for the real test run. Then
sending the same amount of data takes 30 milliseconds; this results in 1068
calls to the update method.
During the performance tests it showed out that it is even worth to calculate
relatively simple cryptographic operations likes hashes through a PKCS#11
module. For example, we compared a pure Java implementation and C implementation
of the SHA- 1 hashing algorithm. Both use very similar code; i.e. the
compression function is nearly a copy and paste from Java to C. However, the C
implementation, accessed through the PKCS#11 Wrapper, is about double as fast as
the Java implementation (using the same environment as before).
These tests unquestionably prove that this library is suitable for high
performance server applications.
License
We provide this software under an Apache style license. The complete license text is as follows.
Copyright (c) 2002 Graz University of Technology. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- The end-user documentation included with the redistribution, if any, must include the following acknowledgment:
"This product includes software developed by IAIK of Graz University of Technology."
Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear.
- The names "Graz University of Technology" and "IAIK of Graz University of Technology" must not be used to endorse or promote products derived from this software without prior written permission.
- Products derived from this software may not be called "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior written permission of Graz University of Technology.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
References
-
PKCS#11, Version 2.20, by RSA Laboratories
-
Java SE Platform, by Oracle
-
Java Native Interface 1.1, by Oracle
-
PKCS#11 API for Java, by IBM Alphaworks