| Adding New Smart Card Drivers |
This tutorial explains the steps involved when adding a new smart card driver to the SmartCard API. A “smart card driver” refers to a pair of classes: one class representing a particular type (model) of smart card, and the other class representing a communications session with a physical smart card. A new driver is implemented by extending the two abstract classes SmartCard and SmartCardSession.
The following sections outline and illustrate the requirements for each.
Extending SmartCard
A SmartCard object represents the kind (or model) of a physical smartcard, as opposed to unique smartcard. The first step in creating a new smart card driver is to implement a subclass extending SmartCard. The subclass should be implemented Persistable, and should not contain any state information.
The UI functionality is implemented in the base class, and subclasses should not need to do this. The following code example illustrates the abstract methods that must be implemented.
public class MySmartCard extends SmartCard implements Persistable
{
/**
* The ATR (answer to reset) of the card.
* The ATR is the first data block returned to the reader after a card is powered up.
* The ATR contains information about what protocol the card uses, and data identifying the type of card.
* The ATR is specified in ISO 7816-3.
**/
private final static byte atrString[] = { (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67,
(byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef,
(byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67,
(byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef,
(byte)0x01, (byte)0x23 };
private final static AnswerToReset _atr = new AnswerToReset( atrString );
/**
* This method returns the appropriate subclass of SmartCardSession, used to establish a
* communications session with a physical smart card.
**/
protected SmartCardSession openSessionImpl( SmartCardReaderSession readerSession ) throws SmartCardException
{
return new MySmartCardSession( this, readerSession );
}
/**
* This method returns true if this SmartCard implementation should be used to
* communicate with a physical smart card having the given AnswerToReset.
**/
public boolean checkAnswerToReset( AnswerToReset atr )
{
return _atr.equals( atr );
}
/**
* This method returns a label associated with the kind of smart card.
* The string should not include the words "smart card", as this method will
* be used to generate strings such as ( "Please insert your %s smart card", getLabel ( ) )
**/
public String getLabel()
{
return “RIM sample“;
}
/**
* This method returns the SmartCardCapabilities of the smart card.
*/
public SmartCardCapabilities getCapabilities()
{
return new SmartCardCapabilities( SmartCardCapabilities.PROTOCOL_T0 );
}
}
Extending SmartCardSession
A SmartCardSession object represents a communications session with a physical smartcard. Over the communications session, APDUs (“application protocol data units”) are exchanged with the smartcard to provide the desired functionality. A subclass extending SmartCardSession must be implemented when creating a new smart card driver. The subclass may provide any additional functions appropriate to the application.
Again, the UI functionality is implemented in the base class, and subclasses should not need to do this. The following code example illustrates the abstract methods to be implemented.
public class MySmartCardSession extends SmartCardSession
{
/**
* The constructor creates a new SmartCardSession.
* Parameter smartCard refers to the SmartCard object associated with this session.
* Parameter readerSession refers to the underlying reader session.
**/
protected MySmartCardSession( SmartCard smartCard, SmartCardReaderSession readerSession )
{
super( smartCard, readerSession );
}
/**
* This method closes the session with the smart card.
* Implementations should not close the underlying SmartCardReaderSession,
* but do any cleanup that might
* be required for the particular application.
**/
protected void closeImpl()
{
// Do any cleanup required for your particular application
}
/**
* This method transmits an APDU to the smartcard, and blocks until a response is received.
* (APDUs (Application Protocol Data Units) are
* messages exchanged between card readers and smart cards).
**/
public void sendAPDUImpl( CommandAPDU commandAPDU, ResponseAPDU responseAPDU ) throws SmartCardException
{
SmartCardReaderSession readerSession = getSmartCardReaderSession();
readerSession.sendAPDU( commandAPDU, responseAPDU );
}
/**
* This method returns the maximum number of login attempts allowed,
* or Integer.MAX_VALUE if unlimited attempts are allowed.
**/
protected int getMaxLoginAttemptsImpl() throws SmartCardException
{
return MAX_LOGIN_ATTEMPTS;
}
/**
* Returns the remaining number of login attempts allowed before the smartcard will lock.
* Implementation should not bring up UI.
*/
protected int getRemainingLoginAttemptsImpl() throws SmartCardException
{
return getRemainingLoginAttempts( getSmartCardReaderSession() );
}
/**
* Attempts to log the user into the smartcard with the given password.
* return true if the user was successfully logged, or false otherwise.
* throws SmartCardLockedException if the smart card is locked.
**/
protected boolean loginImpl( String password ) throws SmartCardException
{
if ( ! securityCheck() ) {
throw new SmartCardAccessDeniedException();
}
return true;
}
/**
* This method returns a SmartCardID object, which represents a specific smart card
* within a family of smart cards.The ID is a unique number identifying this particular
* smartcard. For example, the ID could be a personnel number.
* The label is a human readable string that identifies this specific smart card to the user.
* For example, label could be the name of the card holder.
**/
public SmartCardID getSmartCardIDImpl() throws SmartCardException
{
String id = “smartcard ID string”;
byte [] idBytes = id.getBytes();
long idLong = CRC32.update( -idBytes.length, idBytes, 0, idBytes.length );
String label = “John A Smith”;
return new SmartCardID( idLong , label, getSmartCard() );
}
/**
* Retrieves generic information from the smart card.
*/
public Object getInformation(long id, Object parameter, Object defaultValue) throws SmartCardException
{
return null;
}
}
Drivers for Smart Cards with Cryptographic Applications
Smart cards are sometimes used to perform cryptographic applications such as public and symmetric key encryption, digital signature creation and verification. Smart cards used for such purposes have some common functionality beyond that for other smart cards. Much of this additional functionality is provided by the abstract classes CryptoSmartCard and CryptoSmartCardSession, which extend SmartCard and SmartCardSession.
To create a driver for a new smart card with cryptographic applications, the classes CryptoSmartCard and CryptoSmartCardSession should be extended (instead of directly extending SmartCard and SmartCardSession as above). All of the abstract methods described above must be implemented, as well as the following additional abstract methods.
public class MyCryptoSmartCard extends CryptoSmartCard implements Persistable
{
...
...
// This method returns the names of all the algorithms supported by this token, eg "RSA", "DSA".
public String[] getAlgorithms()
{
return new String [] { "RSA", "DSA" };
}
/**
* Returns a crypto token that supports the given algorithm.
* Crypto tokens are used to store and distribute cryptographic information
* Parameter algorithm is a String representing the name of the algorithm.
* This method throws NoSuchAlgorithmException if the specified algorithm is invalid, and
* throws CryptoTokenException if there is a token related problem.
*/
public CryptoToken getCryptoToken( String algorithm ) throws NoSuchAlgorithmException, CryptoTokenException
{
if ( algorithm.equals( "RSA" ) ) {
return new MyRSACryptoToken();
}
if ( algorithm.equals("DSA") ) {
return new MyDSACryptoToken();
}
throw new NoSuchAlgorithmException();
}
}
public class MyCryptoSmartCardSession extends CryptoSmartCardSession
{
...
...
/**
* Returns a KeyStore associated with key data stored on the card.
* The returned Keystore should contain all the private keys, public keys
* and certificates on the card. If the key store contains public keys, they
* must be valid PublicKeys. Public key cryptographic operations will be handled
* by the device and not by the smartcard.
* If the Keystore contains certificates, they must be valid Certificates.
* This method throws SmartCardException if an error occurs when
* communicating with the smart card, and
* throws CryptoTokenException if there is a token related problem.
**/
public KeyStore getKeyStoreImpl() throws SmartCardException, CryptoTokenException
{
try {
RIMKeyStore keyStore = new RIMKeyStore( “My Key Store name” );
RSACryptoSystem rsa1024 = new RSACryptoSystem();
RSACryptoToken token = new RSACryptoToken();
CertificateStatus certStatus = new CertificateStatus();
KeyStoreTicket ticket = keyStore.getTicket();
RSAPrivateKey rsaPrivate = new RSAPrivateKey( rsa1024, new MyCryptoTokenData() );
keyStore.set( null,
“label 1”,
rsaPrivate,
null,
KeyStore.LOW,
ticket );
return keyStore;
} catch ( CryptoUnsupportedOperationException e ) {
throw new SmartCardException( “unsupported operation string” );
} catch ( InvalidKeyException e ) {
throw new SmartCardException( “invalid key string” );
} catch ( UnsupportedCryptoSystemException e ) {
throw new SmartCardException( “unsupported CryptoSystem string” );
} catch ( KeyStorePasswordException e ) {
throw new SmartCardException( “keystore password exception string” );
} catch ( CryptoTokenException e ) {
throw new SmartCardException( “CryptoToken exception string” );
} catch ( InvalidKeyEncodingException e ) {
throw new SmartCardException( “invalid key encoding exception” );
} catch ( NoSuchAlgorithmException e ) {
throw new SmartCardException( “no such algorithm string” );
}
}