// 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: // // 1. Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // // 2. 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. // // 3. 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. // // 4. 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. // // 5. 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. package iaik.pkcs.pkcs11; import iaik.pkcs.pkcs11.wrapper.CK_CREATEMUTEX; import iaik.pkcs.pkcs11.wrapper.CK_C_INITIALIZE_ARGS; import iaik.pkcs.pkcs11.wrapper.CK_DESTROYMUTEX; import iaik.pkcs.pkcs11.wrapper.CK_INFO; import iaik.pkcs.pkcs11.wrapper.CK_LOCKMUTEX; import iaik.pkcs.pkcs11.wrapper.CK_UNLOCKMUTEX; import iaik.pkcs.pkcs11.wrapper.PKCS11; import iaik.pkcs.pkcs11.wrapper.PKCS11Connector; import iaik.pkcs.pkcs11.wrapper.PKCS11Constants; import iaik.pkcs.pkcs11.wrapper.PKCS11Exception; import java.io.IOException; /** * Objects of this class represent a PKCS#11 module. The application should * create an instance by calling getInstance and passing the name of the * PKCS#11 module of the desired token; e.g. "slbck.dll". The application * must give the full path of the PKCS#11 module unless the module is in the * system's search path or in the path of the java.library.path system * property. * By default, it is assumed that the required pkcs#11-wrapper-library * is named "pkcs11wrapper" and is located in the system path. The name of the * library with the absolute path can also be passed as parameter. * According to the specification, the application must call the initialize * method before calling any other method of the module. * This class contains slot and token management functions as defined by the * PKCS#11 standard. * All applications using this library will contain the following code. *
* Module pkcs11Module = Module.getInstance("cryptoki.dll");
* pkcs11Module.initialize(null);
*
* // ... work with the module
*
* pkcs11Module.finalize(null);
*
* Instead of cryptoki.dll
, the application will use the name of
* the PKCS#11 module of the installed crypto hardware.
* After the application initialized the module, it can get a list of all
* available slots. A slot is an object that represents a physical or logical
* device that can accept a cryptographic token; for instance, the card slot of
* a smart card reader. The application can call
*
* Slot[] slots = pkcs11Module.getSlotList(Module.SlotRequirement.ALL_SLOTS);
*
* to get a list of all available slots or
*
* Slot[] slotsWithToken = pkcs11Module.getSlotList(Module.SlotRequirement.TOKEN_PRESENT);
*
* to get a list of all those slots in which there is a currently a token
* present.
*
* To wait for the insertion of a token, the application can use the
* waitForSlotEvent
method. For example, the method call
*
* Slot eventSlot = pkcs11Module.waitForSlotEvent(Module.WaitingBehavior.DONT_BLOCK, null);
*
* will block until an event for any slot of this module occurred. Usually such
* an event is the insertion of a token. However, the application should check
* if the event occurred in the slot of interest and if there is really a token
* present in the slot.
*
* @see iaik.pkcs.pkcs11.Info
* @see iaik.pkcs.pkcs11.Slot
* @author Karl Scheibelhofer
* @version 1.0
* @invariants (pkcs11Module_ <> null)
*/
public class Module {
/**
* This interface defines the required properties for a slot. The application
* uses one of the defined constants as parameter when calling getSlotList.
*
* @author Karl Scheibelhofer
* @version 1.0
* @invariants
*/
public interface SlotRequirement {
/**
* Causes getSlotList to return all slots of the system that the respective
* module supports.
*/
public static boolean ALL_SLOTS = false;
/**
* Causes getSlotList to return only those slots in which there is currently
* a token present; e.g. there is a smart card in the reader's slot.
*/
public static boolean TOKEN_PRESENT = true;
}
/**
* This interface defines the allowed constants for the wanted waiting
* behavior when calling waitForSlotEvent.
*
* @author Karl Scheibelhofer
* @version 1.0
* @invariants
*/
public interface WaitingBehavior {
/**
* Tells waitForSlotEvent to block until an event occurs.
*/
public static boolean BLOCK = false;
/**
* Tells waitForSlotEvent to return immediately.
*/
public static boolean DONT_BLOCK = true;
}
/**
* Interface to the underlying PKCS#11 module.
*/
protected PKCS11 pkcs11Module_;
/**
* Create a new module that uses the given PKCS11 interface to interact with
* the token.
*
* @param pkcs11Module The interface to interact with the token.
* @preconditions
* @postconditions
*/
protected Module(PKCS11 pkcs11Module) {
if (pkcs11Module == null) {
throw new NullPointerException("Argument \"pkcs11Module\" must not be null.");
}
pkcs11Module_ = pkcs11Module;
}
/**
* Get an instance of this class by giving the name of the PKCS#11 module;
* e.g. "slbck.dll".
*
* @param pkcs11ModuleName The name of the module; e.g. "slbck.dll".
* @return An instance of Module that is connected to the given PKCS#11
* module.
* @exception IOException If connecting to the named module fails.
* @preconditions (pkcs11ModuleName <> null)
* and (pkcs11ModuleName is a valid PKCS#11 module name)
* @postconditions
*/
public static Module getInstance(String pkcs11ModuleName)
throws IOException
{
if (pkcs11ModuleName == null) {
throw new NullPointerException("Argument \"pkcs11ModuleName\" must not be null.");
}
PKCS11 pkcs11Module = PKCS11Connector.connectToPKCS11Module(pkcs11ModuleName);
return new Module(pkcs11Module);
}
/**
* Get an instance of this class by giving the name of the PKCS#11 module, e.g. "slbck.dll"
* and the absolute path to the PKCS#11-wrapper native library.
*
* @param pkcs11ModuleName The name of the module; e.g. "slbck.dll".
* @param pkcs11WrapperPath The absolute path to the PKCS#11-wrapper native library.
* @return An instance of Module that is connected to the given PKCS#11
* module using the specified PKCS#11-wrapper native library.
* @exception IOException If connecting to the named module fails.
* @preconditions (pkcs11ModuleName <> null)
* and (pkcs11ModuleName is a valid PKCS#11 module name)
* @postconditions
*/
public static Module getInstance(String pkcs11ModuleName, String pkcs11WrapperPath)
throws IOException
{
if (pkcs11ModuleName == null) {
throw new NullPointerException("Argument \"pkcs11ModuleName\" must not be null.");
}
PKCS11 pkcs11Module = PKCS11Connector.connectToPKCS11Module(pkcs11ModuleName,
pkcs11WrapperPath);
return new Module(pkcs11Module);
}
/**
* Gets information about the module; i.e. the PKCS#11 module behind.
*
* @return A object holding information about the module.
* @exception TokenException If getting the information fails.
* @preconditions
* @postconditions (result <> null)
*/
public Info getInfo()
throws TokenException
{
CK_INFO ckInfo = pkcs11Module_.C_GetInfo();
return new Info(ckInfo);
}
/**
* Initializes the module. The application must call this method before
* calling any other method of the module.
*
* @param initArgs The initialization arguments for the module as defined
* in PKCS#11. May be null.
* @exception TokenException If initialization fails.
* @preconditions
* @postconditions
*/
public void initialize(InitializeArgs initArgs)
throws TokenException
{
CK_C_INITIALIZE_ARGS wrapperInitArgs = null;
if (initArgs != null) {
InitializeArgs castedInitArgs = initArgs;
final MutexHandler mutexHandler = castedInitArgs.getMutexHandler();
wrapperInitArgs = new CK_C_INITIALIZE_ARGS();
if (mutexHandler != null) {
wrapperInitArgs.CreateMutex = new CK_CREATEMUTEX() {
public Object CK_CREATEMUTEX()
throws PKCS11Exception
{
return mutexHandler.createMutex();
}
};
wrapperInitArgs.DestroyMutex = new CK_DESTROYMUTEX() {
public void CK_DESTROYMUTEX(Object pMutex)
throws PKCS11Exception
{
mutexHandler.destroyMutex(pMutex);
}
};
wrapperInitArgs.LockMutex = new CK_LOCKMUTEX() {
public void CK_LOCKMUTEX(Object pMutex)
throws PKCS11Exception
{
mutexHandler.lockMutex(pMutex);
}
};
wrapperInitArgs.UnlockMutex = new CK_UNLOCKMUTEX() {
public void CK_UNLOCKMUTEX(Object pMutex)
throws PKCS11Exception
{
mutexHandler.unlockMutex(pMutex);
}
};
} else {
wrapperInitArgs.CreateMutex = null;
wrapperInitArgs.DestroyMutex = null;
wrapperInitArgs.LockMutex = null;
wrapperInitArgs.UnlockMutex = null;
}
if (castedInitArgs.isLibraryCantCreateOsThreads()) {
wrapperInitArgs.flags |= PKCS11Constants.CKF_LIBRARY_CANT_CREATE_OS_THREADS;
}
if (castedInitArgs.isOsLockingOk()) {
wrapperInitArgs.flags |= PKCS11Constants.CKF_OS_LOCKING_OK;
}
wrapperInitArgs.pReserved = castedInitArgs.getReserved();
}
//pReserved of CK_C_INITIALIZE_ARGS not used yet, just set to standard conform UTF8
pkcs11Module_.C_Initialize(wrapperInitArgs, true);
}
/**
* Finalizes this module. The application should call this method when it
* finished using the module.
* Note that this method is different from the finalize
method,
* which is the reserved Java method called by the garbage collector.
* This method calls the C_Finalize(Object)
method of the
* underlying PKCS11 module.
*
* @param args Must be null in version 2.x of PKCS#11.
* @exception TokenException If finalization fails.
* @preconditions (args == null)
* @postconditions
*/
public void finalize(Object args)
throws TokenException
{
pkcs11Module_.C_Finalize(args);
}
/**
* Gets a list of slots that can accept tokens that are compatible with this
* module; e.g. a list of PC/SC smart card readers. The parameter determines
* if the method returns all compatible slots or only those in which there is
* a compatible token present.
*
* @param tokenPresent Can be SlotRequirement.ALL_SLOTS or
* SlotRequirement.TOKEN_PRESENT.
* @return An array of Slot objects. May be an empty array but not null.
* @exception TokenException If .
* @preconditions
* @postconditions (result <> null)
*/
public Slot[] getSlotList(boolean tokenPresent)
throws TokenException
{
long[] slotIDs = pkcs11Module_.C_GetSlotList(tokenPresent);
Slot[] slots = new Slot[slotIDs.length];
for (int i = 0; i < slots.length; i++) {
slots[i] = new Slot(this, slotIDs[i]);
}
return slots;
}
/**
* Waits for an slot event. That can be that a token was inserted or removed.
* It returns the Slot for which an event occured. The dontBlock parameter can
* have the value WaitingBehavior.BLOCK or WaitingBehavior.DONT_BLOCK.
* If there is no event present and the method is called with
* WaitingBehavior.DONT_BLOCK this method throws an exception with the error
* code PKCS11Constants.CKR_NO_EVENT (0x00000008).
*
* @param dontBlock Can be WaitingBehavior.BLOCK or
* WaitingBehavior.DONT_BLOCK.
* @param reserved Should be null for this version.
* @return The slot for which an event occured.
* @exception TokenException If the method was called with
* WaitingBehavior.DONT_BLOCK but there was no event
* available, or if an error occured.
* @preconditions (reserved == null)
* @postconditions (result <> null)
*/
public Slot waitForSlotEvent(boolean dontBlock, Object reserved)
throws TokenException
{
long flags = (dontBlock) ? PKCS11Constants.CKF_DONT_BLOCK : 0L;
long slotID = pkcs11Module_.C_WaitForSlotEvent(flags, reserved);
return new Slot(this, slotID);
}
/**
* Gets the PKCS#11 module of the wrapper package behind this object.
*
* @return The PKCS#11 module behind this object.
* @preconditions
* @postconditions (result <> null)
*/
public PKCS11 getPKCS11Module() {
return pkcs11Module_;
}
/**
* Returns the string representation of this object.
*
* @return The string representation of object
*/
public String toString() {
return (pkcs11Module_ != null) ? pkcs11Module_.toString() : null;
}
/**
* This finalize method tries to finalize the module by calling
* finalize()
of the Java object of the PKCS11 module.
* Note that this method does not call the finalize(Object)
* (C_Finalize(Objet)
) method of the PKCS11 module!
* This method is the reserved Java method called by the garbage collector.
* Don't get confused by the same name.
*
* @exception Throwable If finalization fails.
* @preconditions
* @postconditions
* @see #finalize(Object)
*/
public void finalize()
throws Throwable
{
pkcs11Module_.finalize();
super.finalize();
}
/**
* Compares the pkcs11Module_ this object with the other object.
* Returns only true, if those are equal in both objects.
*
* @param otherObject The other Module object.
* @return True, if other is an instance of Module and the pkcs11Module_ of
* both objects are equal. False, otherwise.
* @preconditions
* @postconditions
*/
public boolean equals(java.lang.Object otherObject) {
boolean equal = false;
if (otherObject instanceof Module) {
Module other = (Module) otherObject;
equal = (this == other) || this.pkcs11Module_.equals(other.pkcs11Module_);
}
return equal;
}
/**
* The overriding of this method should ensure that the objects of this class
* work correctly in a hashtable.
*
* @return The hash code of this object. Gained from the sessionHandle.
* @preconditions
* @postconditions
*/
public int hashCode() {
return pkcs11Module_.hashCode();
}
}