Base OCF Reference Implementation Changes for OCF version 1.1 Changes for OCF version 1.1.1
Configuration OpenCard Home

Please read the License!
News and Changes in OCF 1.2
Changes
This section gives an overview of the changes OCF has undergone from version
1.1.1 to 1.2. The changes that have been implemented are mostly changes
which result from Requests for Comments (RFC) elaborated by the members
of the OpenCard Consortium.
Changes Visible for Application Developers
OCF Installer
Application Management
Internal and External Authentication
Card Holder Verification
OCF for Embeded Devices
OCF Support for Java Cards
API Streamlining
Bug Fixes
Changes Visible for CardService Developers
Bug Fixes
Changes Visible for CardTerminal Developers
Terminal Locking
Bug Fixes
Change Details
OCF Installer
OCF 1.2 provides an easy to use OCF Installer package that provides
developers with a quick way to get started with OpenCard development. This
package consists of a single Java class file that contains all OCF components
that were previously provided in the Convenience.zip file plus the full
OpenCard API documentation and the OCF Programer's Guide. A graphical installation
process guides the user through the configuration of the OpenCard Framework
according to the installed hard- and software. On Microsoft Windows 9x/NT
an OpenCard folder is added to the startup menu that contains links to
available documentation and a few demo programs. To use the OpenCard
Framework a working installation of CardTerminal classes provided by the
card reader manufacturer and Sun's Java Communications API need to be installed.
The OCF Installer package has been tested on Microsoft Windows 95/98/NT.
To run it you need JDK version 1.1 or higher.
Application Management
The Application and Card Management Card Service has been entirely changed
and enhanced for OCF 1.2.
The base classes for describing and managing applets are moved from
the pacakage opencard.opt.management to the package opencard.opt.applet.
The term "applet" as we use it in this documentation can be either a
program, which is executed on the card itself (like a typical Java Card
applet). Or it can be an application specific set of files and directory
structures (as we will find on ISO compliant file system oriented cards).
In both cases an AppletID is used to identify the applet in a
world-wide unique way. There are standards which define how each smart
card should hold a directory of AppletIDs, allowing any card-external
application to decide, if it supports a particular card or not. Card-resident
applets are described by meta-information encapsulated in AppletInfo
objects.
This meta-information includes
-
the user-friendly label,
-
the AppletID and
-
the SecurityDomain to which the applet belongs.
You can obtain the AppletInfos from your SmartCard object using
the AppletAccessCardService's list method. AppletID is
a subclass of ID and has been formely named as ApplicationID.
In OCF 1.1.1, the AppletInfo has been named as ApplicationTemplateclass.
The ID class can be used as superclass for any other kind of identification
(such as a GUID).
In the package opencard.opt.applet a very primitive CardService named
BasicAppletCardService
is introduced, which is only able to select a specific applet on a card.
The two Application and Card Management Card Service known from OCF
1.1.1 are renamed in OCF 1.2 as AppletAccessCardService and AppletManagerCardService.
Both are defined in the package opencard.opt.applet.mgmt. Their
functionality has been changed slightly:
The AppletAccessCardService includes the methods
-
list(),
-
exists() and
-
getInfo().
The AppletManagerCardService provides the methods
-
installApplet(),
-
registerApplet() and
-
removeApplet().
Implementations of these Card Services will be added to OCF as soon as
they will get available. They will be placed in specific domain sub-packages
like opencard.opt.javacard.mgmt or opencard.opt.emv.mgmt
instead of being placed in the same opencard.opt.mgmt package.
It is intended that the AppletInfo class can be extended and
that new features/types of information can be added for specific domains
(e.g. JavaCardAppletInfo, placed in the package opencard.opt.javacard.mgmt).
A new abstract class named AppletCode is introduced. This class
models the actual code of a card applet to be installed in the card. It
can be constructed either by specifying a file name that is supposed to
contain the code, or giving all bytes of the code in parameter. This class
is the generic type that is passed as parameter to an install method. As
in the previous case, it is intended that subclasses can be defined, with
new features and/or different ways of reading a file to get the actual
applet code.
Internal and External Authentication
In OCF version 1.1, the general assumption about access conditions that
have to be satisfied is that an application should not have to worry about.
The implementation of the FileAccessCardService for IBM's MFC
smartcards, for example, deals with external authentication transparently,
provided that the application passed appropriate credentials to the service
before using it.
One drawback of this approach is that an application has no control
about the access conditions that are satisfied. Internal authentication
is not supported at all, since it is not an access condition enforced by
the smartcard. The credentials that have been provided to a service are
used at the service's discretion, and the application has little or no
control of what the service does with them.
There may be applications that require more control of the security
features as is provided in OCF 1.1.1. These applications should be given
a way to perform external and internal authentication explicitly. Also,
applications should be able to undo an achieved external authentication.
By defining a card service for this purpose, applications can take control
of the security features using this service. Applications that do not need
this control may still rely on the transparent mechanism.
-
Key Referencing
ISO 7816-4 specifies two commands for authentication, INTERNAL AUTHENTICATE
and EXTERNAL AUTHENTICATE. The latter is used to satisfy access conditions
that may be imposed by the smartcard, it therefore authenticates the external
world to the card. The other one is the reverse operation, it authenticates
the card to the external world.
In both cases, authentication is based on the knowledge of a secret.
This can be either a secret key, using a symmetric cryptographic algorithm,
or a private key in the case of an asymmetric algorithm. The authenticating
party (challenger) has to know either the same secret key or the matching
public key.
The party to be authenticated receives a random challenge, encrypts
it with the secret and sends the result back to the challenger. The challenger
uses the same key (in the case of a symmetric algorithm) or the matching
public key (in the case of an asymmetric algorithm) to verify that the
secret is know to it's partner.
For external authentication, the smartcard needs information about
the key (secret or public) to be used for verifying the outside world's
knowledge of the secret. For internal authentication, the smartcard needs
information about the secret for which to prove the knowledge. In OCF 1.1
CardService interfaces, only the CardServices in opencard.opt.signature
explicitly reference keys, using interfaces defined in opencard.opt.security.
The CardServices in opencard.opt.signature deal with asymmetric
cryptography, and the key referencing interfaces cover only public and
private keys. No provisions are made for referencing symmetric, secret
keys.
For the sake of consistency, an interface for authentication should
use a key referencing mechanism similar to that used in opencard.opt.signature.
To allow for referencing secret keys, a new interface SecretKeyRef
has to be introduced in opencard.opt.security. To allow the definition
of a single interface for authentication, regardless of the symmetricity
of the underlying cryptographic algorithm, a common base interface for
all three kinds of keys has to be introduced, resulting in the following
inheritance tree:
KeyRef (new)
|
+--- PublicKeyRef (exists)
|
+--- PrivateKeyRef (exists)
|
+--- SecretKeyRef (new)
This relationship can be duplicated in the default implementations of
the interfaces, also provided by OCF 1.1 in opencard.opt.security.
This requires introduction of new classes KeyFile and SecretKeyFile,
as well as changes to the existing classes PublicKeyFile and PrivateKeyFile.
These changes can be implemented in a compatible way.
-
Interface Details
For external authentication, a challenge has to be obtained from the
card and sent back encrypted. The result is checked by the card. The secret
can be easily encapsulated by the existing interface SignCredential
in the package opencard.opt.security, although the descriptive
comments have to be adapted to asymmetric algorithms, where the length
of the random challenge does not have to match the block size of the key.
In addition to the credential, a reference to the respective key on the
smartcard has to be passed.
For internal authentication, a challenge has to be given to the smartcard.
The encrypted challenge has to be checked, either in software or by using
a Secure Access Module (SAM) or backend host system. The result of the
internal authentication is a boolean value that specifies whether the card
is in posession of the secret in question or not. Using a credential here
is not appropriate, since the interpretation of the smartcard's response
cannot be the responsibility of the CardService. Internal authentication
is performed to verify that the smartcard can be trusted. The implementation
of the CardService for internal authentication has been selected by OCF
to match the inserted card, so it cannot yet be trusted either. The application
has to be sure that the final, boolean result has not been forged by an
entity associated with the yet untrusted card.
When passing a credential, the application would have to query from
the credential whether the internal authentication was successful. This
means that the credential is used as a callback mechanism by the CardService
as well as directly by the application. This complex usage pattern neutralizes
the ease of use achieved by credentials in other places.
Instead, this RFC proposes a lower level interface for internal authentication,
where the random challenge is passed in as a byte array, and the encrypted
response is returned as another byte array. The application may still use
a credential for obtaining the challenge and verifying the response, but
the role as a mediator between the SAM or backend and the card becomes
more obvious.
There is the question of the length of the random challenge. For symmetric
algorithms, the block size is usually 8 bytes. For asymmetric algorithms,
challenges of various, larger sizes may be acceptable, since these algorithms
use larger block sizes and the challenge will be padded to the appropriate
length. Security can be improved by providing a challenge that is larger
than 8 byte. A method to query the required length for the challenge is
needed anyway, in case an algorithm does not accept an 8 byte challenge,
or a SAM enforces a larger challenge. That method has to return the block
size in the case of a symmetric algorithm, and should return the maximum
allowed length of the challenge for an asymmetric one. In both cases, the
application can be sure that the smartcard will be able to handle a challenge
of the length returned by that method.
External authentication, like Card Holder Verification, is used to
satisfy access conditions imposed by the smartcard. In consequence, an
application will also want to reset these access conditions when it is
finished. The respective method will have to reset external authentications,
but may as well reset Card Holder Verifications and other access conditions.
Since it will typically be called by an application when the smartcard
is no longer needed, this behavior will not cause problems. However, the
name of the method should not mention authentication or keys, to avoid
confusion with the application programmers, and to avoid implementations
of the same functionality under different names with CardService implementors.
Card Holder Verification
In OCF version 1.1, the general assumption about access conditions that
have to be satisfied is that an application should not have to worry about.
The implementation of the FileAccessCardService for IBM's MFC smartcards,
for example, deals with Card Holder Verification without any involvement
of the applications using it.
One drawback of this approach is that an application has no control
about which Card Holder Verifications are performed at what time. For example,
it is generally not possible to check whether the user has already been
prompted for a password. Also, it is not possible to simply enforce card
holder verification at application startup, or to reset the card holder
verification when the application is done with the card. There may be applications
that require more control of the Card Holder Verification as is currently
provided. These applications should be given a way to perform card holder
verification explicitly. Also, applications should be able to undo a successful
card holder verification.
By defining a card service for this purpose, applications can take
control of the card holder verification. Applications that do not need
this control may still rely on the transparent mechanism, as long as the
CardService to be used supports it.
The transparent mechanism for Card Holder Verification may still be
useful. However, it's use is severly restricted by the definition of the
interface opencard.core.service.CHVDialog, which returns a String
holding the password or PIN. The card channel that evaluates this String
can only apply a default conversion and paste the resulting byte array
into a prepared command APDU. This is appropriate only for alphanumeric
passwords in the locale of the Java environment in which the OpenCard Framework
is running. It also assumes that the password has to be presented in plain
format, not with secure messaging.
Performing Card Holder Verification is a complex task with multiple
dependencies. Requesting the password from the card holder depends on the
hardware that is available. For example, a screen dialog may be popped
up, or an attached card reader's display and pinpad can be used. The command
or commands to verify the password depend on the card OS. Length, encoding,
padding, and the range of valid characters depend on the application and
on the card layout. When specifying a CardService for Card Holder Verification,
it has to be decided which of these dependencies shall be handled by the
CardService, and which will have to be dealt with by the applications.
There is no one, perfect solution to this problem.
Specifying a CardService at this level of abstraction does not rule
outthe specification of other CardServices, performing the same task at
a higher level of abstraction. There may still be CardServices for Card
Holder Verification that do convert a string presented by an application
to an encoding appropriate for the card.
A CardService for Card Holder Verification obviously needs a method
that performs Card Holder Verification with the smartcard. Typical file
system based SmartCards, like the German GeldKarte, support different passwords
for subtrees of the file system, and also multiple passwords within the
same subtree. On JavaCards, each applet may specify it's own set of passwords,
too. Parameters to the verification method have to indicate the subtree
or applet as well as the password within that subtree.
To specify the subtree on a file system card or the applet on a JavaCard,
the tag interface opencard.opt.security.SecurityDomain can be
used. It is implemented by class opencard.opt.iso.fs.CardFilePath,
and may in the future be implemented by classes that identify security
domains in other cards.
To specify the password within a security domain, a simple integer
should be sufficient. The GeldKarte, already mentioned above as an example,
supports passwords 0 and 1, IBM's MFC smartcards passwords 1 and 2, Gemplus'
GPK cards passwords 0 to 7. Although all these are file system based cards,
it seems likely that an integer allows to distinguish the passwords on
other cards, too.
The third argument to the password verification method is the password
itself. It should be passed as a byte array, giving the application full
control of the encoding of the password. To use a protected PIN path, in
which the application does not get to know the password at all, null can
be passed instead. In this case, it is the service's responsibility to
query the password, to encode it, and to prepare an appropriate APDU to
send to the smartcard. If the terminal supports it, this responsibility
may be delegated to it. Using a protected PIN path prevents the application
from specifying an encoding for the password, but that problem is inherent
in the concept of a protected PIN path. If the password has to be presented
to the card using secure messaging, it is the service's responsibility
to perform the required cryptographic operations. The return value for
performing Card Holder Verification is a boolean that indicates whether
the password was correct or not. Since the return value is generated by
the CardService, it can only be trusted if the CardService is trusted.
Passing the password as a byte array leaves the question of the length
of the byte array. File system based, ISO 7816-4 compliant smartcards have
a password length of 8 byte. However, considering JavaCard and the flexibility
of applets, other password lengths may also occur. To allow the application
to prepare a byte array of appropriate length, there should be a method
to query the required length. For ISO cards, this method can simply be
implemented to return a constant 8, causing minimal overhead.
Other properties of the password, for example the encoding and padding
rules, can be rather complex and may depend on application data that is
not accessible to the CardService.
If the application is able to perform Card Holder Verification explicitly,
thereby satisfying access conditions for data on the card, it should also
be able to reset those access conditions. On file system based smartcards,
this can typically be done by a SELECT operation that leaves the directory
on the smartcard. Even if this is not possible, a reset of the smartcard
can clear access conditions. Either way, all access conditions for the
respective subtree of the file system or, in general, the security domain,
are invalidated at once. The method does therefore not require a password
number as an argument, the security domain is sufficient.
-
Change in Interface opencard.core.service.CHVDialog
OpenCard Framework implements features for a protected PIN path, in
which neither the terminal or host application nor the CardService get
to know the PIN. If a CardTerminal implements this feature, that implementation
is used. Otherwise, a default replacement in opencard.core.service
gets invoked. The default replacement uses a GUI dialog to query for the
password, then converts the string to a byte array, and pastes it into
an APDU that has been prepared by a CardService. The GUI dialog can be
replaced by the application, which may be used to inform the user of the
security domain for which the password is required.
There are several steps in processing a PIN. The string entered by
the user must be encoded into a byte array, padded to the appropriate length,
packed into a command APDU and finally sent to the card, which may involve
secure messaging. In the default implementation, the encoding is done in
a predefined way in opencard.core.service, the padding is implicitly done
by the CardService that prepares the APDU, and secure messaging is not
supported at all. The flexibility of this approach can be considerably
enhanced by encoding the PIN within the GUI dialog and returning a byte
array instead of the string. The default GUI can be implemented to achieve
the same behavior as before, but the applications would be free to implement
replacement GUIs that use other kinds of encoding, for example BCD. The
fact that the application thereby gets access to the PIN that is entered
does not weaken the security, since the currently supported application-defined
GUIs can do the same.
While the responsibility for encoding and padding are transferred to
the application by this change, secure messaging is still not supported.
There is no need to overload the OpenCard Framework with support for features
that are rarely used.
To implement this change, the method defined in interface CHVDialog
was changed from
public String getCHV(int chvNumber);
to
public byte[] getPassword(int chvNumber, int length);
Java Card/Multi Application Card support
OpenCard Framework 1.1 only defined interfaces and access methods for file
system oriented cards. The only support for JavaCards in OCF1.1 was an
interface named JavaCardCardService in the package opencard.opt.javacard.
This interface only declared a method that sends a given APDU to a given
applet.
OCF 1.2 offers classes that provide basic functions like sending a particular
APDU to a particular applet on the card. Furthermore, they support the
programmer of proxy classes for applets in applet state handling. The same
classes may also be used for multi application cards that allow application
selection by application identifier.Therefore, in this section we use the
term "applet" in a generic sense, for referring to JavaCard applets as
well as applications on multi application cards.
The following classes and interfaces are added to the package opencard.opt.applet:
-
BasicAppletCardService - This class implements the basic functionality
needed to communicate with applets. It provides send-methods in three versions:
The first sends a given command APDU to a given applet on the card, the
second sends a given command APDU to a given applet on the card using a
preallocated card channel provided by the calling method of the derived
class, and the third sends a verify CHV command APDU to the card after
filling in the password obtained from the CHV dialog associated with the
BasicAppletCardService.
-
CardState - This class represents the state of the JavaCard or
Multi Application Card, i.e. the currently selected applet. The state information
allows the BasicAppletCardService to send select-APDUs only when
necessary, i.e. only when an APDU shall be sent to an applet other than
the currently selected applet.
-
AppletProxy - This class is derived from the class BasicAppletCardService.
It adds an attribute that holds the application identifier of the applet
to which the applet proxy is associated. It provides methods similar to
those of the base class, but does not require the application identifier
parameter because every AppletProxy implicitly knows the application
identifier of the associated applet.
-
AppletState - This class is an abstract base class from which
concrete implementations for particular applets can be derived. It declares
an abstract method named appletDeselected() that can be called
from the BasicAppletCardService when selecting another applet.
The purpose of this method is to reset parts of the state that become invalid
as a result of applet deselection.
-
AppletSelector - This is an interface
that defines a method that selects an applet with a given name.
-
ISOAppletSelector - This class
that implements the AppletSelector
interface for ISO compliant cards and is used by the BasicAppletCardService
as a default.
Terminal Locking
OCF 1.1 provides no means for locking a terminal or individual slots. These
features are added to OCF 1.2 without changing the basic design of OCF
and without breaking any existing code. Entire CardTerminal objects as
well as individual slots can be locked and unlocked. Consistent behavior
of the card service layer is assured. The right to use a locked terminal
is bound to the thread that has locked the terminal
The Terminal Locking mechanism is based on four requirements we see
for a card terminal and slot locking mechanism:
-
When no locking is required, the behavior of OCF shall be unchanged. OCF
Programs that need no locking shall run without change.
-
When a card terminal or slot is locked, only the owner of the lock shall
be able to use the terminal or slot.
-
The service layer must respect the locking mechanism, i.e.when a slot is
locked, SmartCard objects may only be created for the owner of the lock.
-
The locking methods should not be a mandatory part of the CardTerminal
interface, but form a separate, optional interface to be implemented by
lockable card terminals.
We expect this interface to be implemented by CardTerminal implementations
for use with PCs, NCs etc, where we have multi-application/multi-thread
scenarios. The locking interface will probably not be implemented by CardTerminals
implementations to be used on dedicated, single-application devices.
-
API Modifications
The OpenCard API has been augmented as follows:
Additional Interface: opencard.opt.terminal.Lockable
public java.lang.Thread lock() throws CardTerminalException
Locks the entire card terminal, including all slots as well as pin
pad and display if available, returns a reference to the new lock owner
on success, else throws a TerminalLockedException.
Alternative: public boolean lock()
Returns true if successfull, false if already locked
public java.lang.Thread lockSlot(int) throws CardTerminalException
Locks the slot with the given slot number, returns a reference to the
new slot owner on success, else throws a TerminalLockedException.
public void unlockSlot(int) throws CardTerminalException
Unlocks the slot with the given slot number.
public void unlock() throws CardTerminalException
Unlocks the entire card terminal, including all slots as well as pin
pad and display if available.
Additional method for the class SlotChannel:
public Object getSlotOwner()
Gets the current slot owner of the associated slot. Required by the
CardServiceRegistry
to determine whether a given thread may obtain a SmartCard object
for the card in the associated slot or not. The type of the slot owner
is Object instead of Thread to avoid a dependence of the opencard.core.terminal
package on threads.
Additional exception: opencard.opt.terminal.TerminalLockedException
extends opencard.core.terminal.CardTerminalException
Change constructor of SlotChannel:
in addition to public SlotChannel(CardTerminal terminal, int slotID)
SlotChannel(CardTerminal terminal, int slotID, Object slotLockOwner)
-
Implementation
A thread can call CardTerminal.lock() to lock a card terminal
and all of its slots and CardTerminal.unlock() to return ownership
of the lock. The lock() method can only be called successfully
when the card terminal has no slot channels open and no other thread has
locked a slot. The lock() call also prevents other threads from
using the pin pad and display of the card terminal and from sending terminal
commands.
A thread can call CardTerminal.lockSlot() to lock a particular
slot and CardTerminal.unlockSlot() to return ownership of the
lock. The lockSlot() method can only be called successfully when
there is no open SlotChannel for the slot to be locked.
The CardTerminal class has a reference to the thread that
currently has the lock (lockOwner). If this reference is not null,
it is locked. If the reference lockOwner is null, the terminal
is free.
In addition, for each slot number, the CardTerminal holds
a reference to the thread that currently owns the terminal's slot. If the
reference is not null, slot i is locked. If the reference is null, the
slot is free.
CardTerminal objects give out SlotChannels to arbitrary
threads only if lockOwner is null and the relevant slotOwner entry
is null. While these references refer to a thread, SlotChannels
are only given to that thread.
Note that this does not prevent a lock owner from deliberately or accidentially
passing the SlotChannel reference to another thread.
The SlotChannel class has slotOwner reference that
identifies the owner. This reference is set at creation of a SlotChannel
object and does not change within its lifetime. The reference slotOwner
is null if the associated slot has not been locked or refers to the owner
if the associated slot has been locked.
When the CardTerminal's unlock() method is called, all open
SlotChannels
are closed.
The CardServiceRegistry singleton returns a SmartCard
object for a smart card in a slot associated with a particular SlotChannel
to arbitrary threads only if the slotOwner reference of the associated
SlotChannel
object is null. If there is a lock owner, the CardServiceRegistry
creates SmartCard objects only for the lock owner. Thus, only
the thread that called CardTerminal.lock() can obtain a SmartCard
object for a card in a locked reader.
If a multithreaded application needs access to a locked terminal from
multiple threads the SmartCard object can be passed from the thread
that has locked the terminal to the other threads. Thus the SmartCard
object plays the role of a gate object at the card service layer as the
SlotChannel
plays the role of the gate object at the card terminal layer
The OCF 1.1 implementation of SmartCard.waitForCard() used
the CardWaiter to wait for a card. The CardWaiter is
a CardTerminal event listener which creates a SmartCard
instance in the CardTerminalRegistry polling thread. Since the
polling thread is not allowed to allocate a SlotChannel on a locked
terminal this code has been changed as follows:
When a card inserted event is received by the card waiter it must notify
the waiting thread and the waiting thread must then try to obtain the SmartCard
object. If the card inserted does not match the card request the CardWaiter
must then continue to wait for card insertion events. Thus the call to
allocate the SlotChannel is moved from the polling thread to the
thread actually waiting for the card, which has the right to access the
locked terminal.
-
Convenience class AbstractLockableTerminal
The implementation details described above are security sensitive.
To avoid that each card terminal implementor has to deal with the complexity
of security implications a new class opencard.opt.AbstractLockableTerminal
is introduced which handles most of the locking specific processing.
Implementers of lockable Terminals would then subclass AbstractLockableTerminal
and implement the methods
-
internalLock(), internalLockSlot(slotid) internalUnlock(), internalUnlockSlot(slotid)
-
lockableOpenSlotChannel() instead of internalOpenSlotChannel
API Streamlining
The changes for the API Steamlining bring a number of minor changes to
the OpenCard Framework which are meant to make the API simpler, and implementations
smaller.
-
Removal of Deprecated Features:
A number of features are already deprecated in OCF 1.1.1. Some of these
are removed for OCF 1.2. Here is a list of the deprecated features:
opencard.core.event.CardTerminalEvent:
Supports events that indicate addition and removal of card terminals.
This was required in OCF in pre-1.0 releases, when listener for card terminal
events were registered directly at all card terminals. The listeners had
to be aware of the fact that a new card terminal was added, so they could
register for the new terminal's events. In the meantime, listeners for
card terminal events, that is for events that indicate card insertion or
removal, are tracked in the card terminal registry. Events are no longer
broadcasted directly by the card terminals, but given to the card terminal
registry, which distributes them to the registered listeners. A listener
will now get the events from newly added card terminals automatically.
The events that indicate changes in the set of card terminals are therefore
obsolete and should be moved. The CardTerminalEvent class contains
some more deprecated methods that are related to the the int/Slot duality
addressed below. These methods can not be removed, but must be un-deprecated
instead.
opencard.core.event.CTRListener
Interface for listeners to events that indicate added or removed card
terminals. As pointed out before, the events for added and removed card
terminals are obsolete.
opencard.core.terminal.CardTerminal
Contains methods for adding and removing listeners at the terminal.
The events listened to indicate card insertion and removal. As pointed
out before, these events are now distributed via the card terminal registry,
and filtering for events from particular card terminals is easy. Direct
registering at a card terminal is therefore obsolete, the respective methods
are removed.
opencard.core.terminal.CardTerminalRegistry
Contains methods for broadcasting events that indicate added and removed
card terminals, and for registering listeners to these events. As pointed
out before, this feature is obsolete and the respective methods are removed.
opencard.core.service.SmartCard
Contains methods for registering listeners to events that indicate
card insertion and removal. These are convenience methods that are identical
to the respective ones in the card terminal registry. They are removed.
opencard.opt.signature.SignatureCardService
Contains the methods from the anachronistic version of this interface.
Every implementor of the SignatureCardService currently has to
implement these methods as dummies that throw an exception. They are also
removed.
-
Removal of Dual APIs
In the packages opencard.core.terminal and opencard.core.event,
there is a duality in the usage of int values and Slot objects, respectively,
to identify a card terminal's slots. In implementations of card terminals,
only int values are used. Slot objects are mapped to int values in the
base class. This duality is an anachronistic feature left over from pre-1.0
versions of OCF. Originally, the Slot class provided features for example
to communicate with that card. All these features have been moved to the
class SlotChannel, leaving the Slot class basically meaningless.
Apart from the internal operation of the OCF core, it is used only in events
that indicate card insertion and removal to specify the source of the event.
Replacing the Slot objects in these events by an int value is simple, since
the card terminal for which the slot number is valid is stored explicitly
in the event, anyway. The class opencard.core.terminal.Slot is
deprecated, and removed in a future release of OCF. Likewise, all methods
that relate to Slot objects, especially in the class opencard.core.terminal.CardTerminal,
are deprecated and later on removed, since the dual methods using int values
can be used instead. The class opencard.core.event.CardTerminalEvent
is extended by a method that returns the originating slot as an int value,
and the methods and constructors referring to Slot objects are deprecated.
Any other methods that relate to Slot objects in OCF are deprecated. If
required, methods that accept int values can be added as replacements.
-
Removal of Convenience Methods
opencard.core.service.SmartCard.getSmartCard(CardTerminalEvent)
This method is obsolete. There is a method with the same name, taking
a CardTerminalEvent and a CardRequest argument. Invoking
that method with null for the CardRequest results in the same
behavior as invoking the single-argument method. This method therefore
is deprecated, and removed in a future OCF release.
opencard.core.service.CardRequest
This class is basically a collection of attributes, which can be used
to specify a filter for cards an application is interested in. Besides
these attributes, it offers an overwhelming number of constructors that
accept various subsets of the attributes as parameters, and set/get methods
for the attributes. Interestingly, the constructor that would have been
used most often in IBM code samples (package demos.samples), that
is one that takes NEWCARD/ANYCARD as it's single argument, is not available
since it's method signature would be the same as the one taking a timeout
argument.
Most of the currently provided constructors and setXXX-methods are
deprecated. Instead, only the following new constructor and setXXX-methods
are provided:
-
constructor with wait behavior (NEWCARD or ANYCARD), a CardTerminal, and
a CardService as arguments. For the terminal and service arguments, null
can be passed as a "don't care" value.
-
setTimeout, which allows to disable timeout handling without defining a
magic number for this purpose
-
setFilter, since filtering is a rarely used feature that should not be
reflected as a required argument of the only remaining constructor
-
Removal of Obsolete Features
The class opencard.core.service.CardServiceScheduler
supports customized card channels, that can be provided by a card service
factory. This feature was probably used only by the IBM MFC card services
and is obsolete, since the problems solved with it can now be solved using
the default card channel's setState/getState methods. The support for customized
card channels in the scheduler, that is methods setCustomChannel,
useDefaultChannel,
and isCustomized should be deprecated and removed in a future
release of OCF.
The class opencard.core.terminal.CardTerminal defines an abstract
method named internalFeatures. In most implementations, this method
just returns it's argument. Instead of requiring every card terminal implementation
to define this method empty, this should be the default implementation
in the base class. Card terminals that specify internal features can still
override the methods, others can ignore it.
-
Removal of Unimplemented Features
The class opencard.core.terminal.CardTerminal provides several
methods that take a timeout as an argument, either required or optional.
Timeout handling, however, has never been implemented in a satisfactory
way. Actually, PC/SC does not provide means to change timeout values, so
the PC/SC wrapper terminal implementation has no chance to implement timeout
handling. In consequence, timeouts should be removed from the terminal
layer API. The API of the service layer is not affected by this change,
since it does not support terminal layer timeouts. In the terminal layer,
the classes Slot, SlotChannel, CardTerminal,
and the interface VerifiedAPDUInterface are affected. In the classes
Slot
and SlotChannel, the methods getCardID and sendAPDU
with timeout argument are simply deprecated. In VerifiedAPDUInterface,
the method sendVerifiedAPDU with timeout argument is deprecated,
and a default implementation calling the method without timeout is added
to class CardTerminal, so implementing that interface does not
require to implement a deprecated method. In class CardTerminal,
the following methods are affected:
Method |
abstract |
with timeout |
w/o timeout |
getCardID |
yes |
yes |
yes |
internalReset |
yes |
yes |
no |
internalSendAPDU |
yes |
yes |
no |
reset |
no |
yes |
no |
Of these methods, only getCardID and reset
are publicly visible. To minimize the changes for existing card terminal
implementations, the following changes are made:
-
getCardID with timeout argument was deprecated, and a default
implementation that invokes getCardID without timeout was provided.
The default implementation is required so that new card terminal implementations
need not define a deprecated method.
-
the reset method with timeout argument was deprecated. A reset
method without timeout argument was provided instead.
That way, the API to be implemented by new terminals is a subset of the
API that currently has to be implemented. Existing card terminal implementations
can still be used, provided they are able to deal with the default timeout
values that are substituted for the actual arguments. By deprecating the
timeout features of the public terminal API, application programmers are
aware of the fact that timeouts are not supported. The deprecated methods
will be removed in a future release of OCF.
Changes for Reduced Package Dependencies
In OCF1.1.1, the packages opencard.core.terminal and opencard.core.event
are recursively dependent on each other. The classes in the terminal package
deal with event handling, and therefore depend on the event package. On
the other hand, the class CardTerminalEvent in the event package
stores the event source, that is a reference to a card terminal, and therefore
depends on the terminal package. As the name suggests, the package opencard.core.event
should deal with events in OpenCard. To achieve this, a variety of changes
are required. All changes are made in a way such that current implementations
of card terminals can still be used with deprecated methods. The recursive
dependency between the packages, however, will remain until the deprecated
methods are removed in a future release of OCF.
The primary action to move the event handling to the event package
was to introduce a class opencard.core.event.EventGenerator which
takes the following responsibilities from the CardTerminalRegistry:
-
track the pollable terminals
-
define the polling thread
-
generate the detected events
-
track the event listeners
-
distribute the generated events
As a result, a listener for card terminal events must be registered at
the new EventGenerator, not at the CardTerminalRegistry.
This can be hidden by deprecating the respective methods in the registry
and redirecting them to the event generator. To avoid changing existing
card terminals or card terminal factories, there was a need to invoke the
EventGenerator
from the CardTerminalRegistry. Unlike with registering event listeners,
this feature is not deprecated, so the invocation cannot be direct. Instead,
an interface Observer is defined in opencard.core.terminal, which
defines the two invocations required:
-
updateCards(terminal, slot, inout)
Invoked when a card is inserted or removed. The terminal and slot argu
ments specify the event source, the inout boolean value indicates insertion
or removal.
-
updateTerminals(terminal, addrem)
Invoked when a card terminal is added or removed. The terminal argument
indicates the terminal affected, the addrem boolean value indicates that
the terminal has been added or removed, respectively. Unfortunately, it
is not possible to deal with event listeners in the same way. The interface
CTListener
is defined in the event package, so all references to it was removed from
the terminal package.
The interface opencard.core.terminal.Observer is implemented by
the class opencard.core.event.EventGenerator. The CardTerminalRegistry
is extended by a method to install an instance of Observer. This
method will be invoked by the EventGenerator on initialization.
-
Changes to the Behavior
The class opencard.core.service.CardServiceScheduler implemented
it's own queueing mechanism, which required two inner classes for a queue
and it's elements. By relying on the respective JVM's queueing mechanism,
which is accessible through the methods java.lang.Object.{wait|notify},
the complexity and size of CardServiceScheduler is dramatically
reduced.
-
Extension for Versioning
It has been discussed several times to have an OCF feature to obtain
version information. Since Java 2, with it's builtin versioning via the
class java.lang.Package, does not seem to gain acceptance as fast
as expected, it seemed still reasonable to introduce a simple version information
in OCF. In the class opencard.core.service.SmartCard, the method
public
static String getVersion() was introduced. It returns a string of
the form "OCF1.2;IBM Reference Implementation, Build Hudson, 21-May-1999".
The first part indicates the API. It always starts with "OCF", followed
by an API version number, and terminates by a semicolon. Currently, this
API version number is simply the OCF release number. When a formal OCF
specification becomes available, it would refer to the version of that
specification it implements. After the semicolon, vendor specific information
is included. The format of the vendor specific information is not specified.
Bug Fixes
-
New CardID constructor:
The CardID constructor so far assumed that the TCK byte in
the ATR was always present. The last byte is not a historical byte, but
the check character TCK as defined in ISO 7816-3 6.4 and 6.4.3.
"The value of TCK shall be such that the exclusive-oring of all bytes
from T0 to TCK included is null"
...
"If only T=0 is indicated, TCK shall not be sent. In all other cases,
TCK shall be sent".
opencard.core.CardID did not correctly respect this. It always
assumed the presence of byte TCK. The right way to do this is to parse
the ATR from the beginning (counting which interface characters are present)
instead of counting from the back end.
-
Problem in CardHolderVerificationGui
We removed the following variable which was never used
private static String BACKGROUND = System.getProperty(OpenCardConstants.OPENCARD_PROPERTY
+ "UserInteraction.image", "ZueriLab.gif");
and did not work correctly in native browser support.
-
Additional constructor in RSAPrivateKey
opencard.opt.security.RSAPrivateKey only had a constructor
from byte arrays but not from java.math.BigInteger which was inconvenient
in many cases.
The following constructor was added:
public RSAPrivateKey(BigInteger e, BigInteger m)
-
Bug fix in constructor of opencard.opt.security.DESKey:
The DESKey constructor did not copy the byte array passed
as argument. If the caller changed/reused her byte array the DESKey
got affected.
-
Typo in OCF11CardServiceFactory:
We had a bug in opencard.opt.service.OCF11CardServiceFactory.
We changed the class definition FROM
public abstract class OCF11CardServiceFactory extends CardServiceFactory
{
private Tracer ctracer = new Tracer(CardServiceFactory.class);
TO
public abstract class OCF11CardServiceFactory extends CardServiceFactory
{
private Tracer ctracer = new Tracer(OCF11CardServiceFactory.class);
-
Bug with long APDUs in opencard.opt.terminal.protocol:
The opencard.opt.terminal.protocol.T1Block class had a LEN
field of type byte. This lead to the problem that response APDUs of longer
than 127 bytes caused a timeout exception because the LEN field had a numeric
overflow and got negative.
OCF for Embedded Devices
OCF for embedded devices defines a subset of OCF that is suitable for embedded
devices with only one card reader, potentially with several slots. This
subset is implementable on Embedded Java Virtual Machines efficiently
and with small footprint.
OCF for embedded devices has the following properties:
-
As compatibile with OCF as possible - Meanwhile, there are several standards
and standard proposals that refer to OCF and assume stability of OCF. When
additions are made to the OCF API which are also advantageous for OCF for
embedded devices, these additions may also be made to OCF for embedded
devices.
-
No redundant APIs - In OCF, there are redundant APIs: Many methods are
available in several versions with different parameter lists. On embedded
devices, small footprint is more important than convenience. Therefore,
OCF for Embedded Devices defines an API that provides no convenience methods,
there is always exactly one method to handle a particular task.
-
CardTerminalRegistry: When running on PCs, OCF must potentially handle
several readers. Embedded devices have only one reader, potentially with
several slots. Therefore, OCF for Embedded uses a CardTerminal singleton
representing the single card reader, so that no CardTerminalRegistry is
needed for that purpose. The event handling functionality of CardTerminalRegistry
is moved to a new class opencard.core.event.EventGenerator.
-
The CardTerminalRegistry is moved to the event package in OCF for embedded
devices, since after the removal of the registration function, it is only
an event generator and multicaster. This makes the terminal layer independent
from the event layer. Renaming from "CardTerminalRegistry" to "EventGenerator"
makes the semantic of the class clearer and avoids confusion with the still
existing CardTerminalRegistry in OCF 1.x.
-
No Slot class: In the terminal layer of OCF there is a duality between
Slot objects and integers. At the end, each method that takes a Slot object
gets the slot number from the Slot object and calls the appropriate method
which takes an integer argument instead of a Slot object. OCF for Embedded
avoids the integer/Slot duality in OCF for embedded devices by omitting
the Slot class.
-
No waitForCard() mechanism: In OCF, there are two possibilities for obtaining
a SmartCard object: using the event-mechanism or using the waitForCard()-mechanism.
The waitForCard()-mechanism is implemented based on the event mechanism
and adds considerable footprint. In an event driven program it is never
needed and if it should be desired, it could be provided by a utility class
that does not need to be part of the core classes. OCF for Embedded devices
will not provide the redundant waitForCard()-mechanism.
-
No secure PIN path: OCF provides a mechanism that allows to transmit an
incomplete VERIFY_PIN command to a reader with a display and PIN pad and
let the reader add a PIN entered on its PIN pad by the user. When OCF runs
in an embedded device, this functionality is not required, because readers
in embedded devices do usually not have their own dedicated display and
PIN pad. OCF for Embedded Devices will not provide the classes and
interfaces for implementing a protected PIN path.
-
No start/shutdown mechanism with automatic registration of CardServiceFactories
and CardTerminalFactories listed in a property file: Inside of an embedded
device, there is not necessarily a file system. We assume that inside of
an embedded device, there is some kind of bootstrap code that is started
when the terminal is switched on and this bootstrap code registers the
required CardServices explicitly with the CardServiceRegistry. Additional
CardServices can be registered by applications when needed.OCF for Embedded
Devices does not provide methods for starting and automatically registring
services nor for shutting down.
-
Independency of card terminal layer: Even though the OCF for Embedded Devices
API subset is implemented in very small footprint, there may be applications
and devices where it may be useful to use the card terminal layer without
the event and service layers. Therefore, OCF for Embedded Devices avoids
all dependencies of the card terminal layers to event and card service
layers.
News and Changes in OCF 1.1.1
This section gives an overview of the changes OCF has undergone from version
1.1 to 1.1.1 The changes that have been implemented are mostly bug fixes
and streamlining of code, but include also some minor design changes which
result from Requests for Comments (RFC) elaborated by the members of the
OpenCard Consortium.
Changes
We assume that there are basically three kinds of developers that use OCF:
Application developers, CardService developers, and CardTerminal developers.
Below, there are three lists with the major changes that affect each kind
of developer. The hyperlinks will lead you to the detailed descriptions
of those changes in the next section.
Changes Visible for Application Developers
Changes Visible for CardService Developers
Changes Visible for CardTerminal Developers
Change Details
Native Browser support
Deploying OCF in a web browser environment has so far been limited to Sun's
java plug-in (also called Activator). OCF 1.1.1 introduces support for
the native Java Virtual machines and security concepts of potentially any
browser with specific support for Microsoft Explorer and Netscape Navigator.
Please see the OCF Programming Guide for instructions how to code/package
applets to run under these browsers.
The changes introduced for native browser support do not change existing
interfaces and are only relevant for developers who want to deploy OCF
from an applet running under those browser's JVM.
Changed CardServiceFactory interface
Card service factories can now communicate with the card to determine whether
they can instantiate the requested card service. In OCF 1.1 card service
factories could only use the CardID (ATR) to determine the type of card.
But often the ATR was insufficent to determine whether the card could be
supported.
New card service factories (subclasses of opencard.core.service.CardServiceFactory)
should implement the getCardType() and getClasses() methods.
Existing factories that implement the knows() and cardServiceClasses()
methods must now be derived from opencard.opt.service.OCF11CardServiceFactory
to compile without errors.
Changed behaviour of SmartCard.waitForCard()
SmartCard.waitForCard() does now block the caller until a card matching
the card request is found or until the timeout expires.
In OCF 1.1 waitForCard() returned whenever a new card was inserted,
regardless whether the card inserted matched the card request. The method
returned null when the card did not match the request.
News and Changes in OCF 1.1
This section gives an overview of the changes OCF has undergone from version
1.0 to 1.1. The changes that have been implemented are not restricted to
bug fixes, but include a considerable number of design changes.
The Rationale tells you why we decided to
change the OpenCard API. In Changes, you will find
lists of the changes that affect applications, CardServices, and CardTerminals
written for OCF 1.0. Detailed descriptions of the major changes are presented
in the Details section.
Rationale
Changing a published API in a way that breaks code written against it causes
trouble. It does not only require a considerable effort from our side to
adapt the reference services and terminals. It also requires effort from
your side to adapt your programs to the new API. However, we had good reasons
for changing the OCF API. This section is meant to give you an overview
on some of these reasons and motivate you to upgrade from OCF 1.0 to 1.1.
(We promise not to do it again - unless
the consortium members have overwhelming reasons.) The changes we implemented
have been guided by the following objectives:
Codesize Reduction
Several functions of OCF have been reduced to save code size. The
changes were discussed and agreed by the Core Workgroup and the CardService
Workgroup of the OpenCard consortium. The policy was to save code
that is rarely used and not essential while keeping incompatibility to
version 1.0 at a minimum. Version 1.1 of OCF allows to use the terminal
layer without the Service layer, which is an option for small systems with
memory limitations. In this case the size of the terminal layer (with
tracces removed and using the Jikes compiler) is 32 KBytes.
We have simplified and split some of the CardService interfaces. This
provides a chance for implementing smaller CardServices with support for
the most frequently needed functionality of a smartcard. There is an improved
layering between other parts of OCF, too. This allows for downsizing by
using only the lower layers. Additionally, it simplifies the task of getting
started with OCF. A developer can now start by looking at smaller parts
of OCF and move to the more complex APIs later.
Performance Tuning
In general, we have modified internal functions and parts of the structure
to allow for faster execution and reduced garbage collection overhead.
In the CardService area we have introduced a layering for the opt.iso.fs
package, where you can chose between highest abstraction and ease of programming
or highest execution efficiency. For example, the time we measured for
reading the 64 bytes card holder data in the Stockbroker demo was 0.65
seconds using OCF's java.io specializations, 0.52 seconds using
CardFile
and the file service directly, and 0.46 seconds using
CardFilePath
and the file service.
We have reduced the tracing information generated. The tracing
output was always composed before the tracer decided if the tracelevels
required to output it or not. This involved overhead in some functions
even if the trace was not used. This overhead was reduced.
In addition, the traces can be removed from the code completely using a
simple perl script.
We have allowed the reuse of exising objects instead of create/delete
cycles. This puts a small additional burdon on the programmer writing
a CardService implementation, but is transparent to application programmers.
The performance could be improved significantly. For example, by
making CardChannel objects reusable, the time for reading data
records has been reduced by 69% in one of our test programs, without breaking
any code.
We have replaced the OCFEventMulticaster by an implementation
that is dramtically faster for a small number of events, like typical OCF
setups have. Details
Error Handling
OCF exceptions were not checked in 1.0. This made programming errors
possible, where severe errors at runtime were not handled appropriately
by the application code. OCF 1.1 has moved to and enforces a stricter
control of exception handling, which is more consistent with other Java
frameworks. Unfortunately, this change will break existing code that
failed to handle OCF exceptions. Details
Documentation Enhancements
The API documentation has been greatly enhanced to provide more information.
Especially the CardService interfaces for file access and signature generation
have been documented in detail.
The Programmer's Guide to OCF has been reworked to reflect all
changes implemented in OCF 1.1. The code examples have been reviewed, simplified,
and explained in more detail.
Changes
We assume that there are basically three kinds of developers that use OCF:
Application developers, CardService developers, and CardTerminal developers.
Below, there are three lists with the major changes that affect each kind
of developer. The hyperlinks will lead you to the detailed descriptions
of those changes in the next section.
Changes Visible for Application Developers
Changes Visible for CardService Developers
Changes Visible for CardTerminal Developers
Change Details
Checked Exceptions
The exception hierarchy defined in OCF 1.0 has been reviewed and changed.
Some obsolete exceptions have been removed, others have been renamed. Finally,
seven exceptions have been moved from opencard.core.service to
opencard.opt.service.
To help programmers in developing error handling code, OpenCardException
and all exceptions derived from it are checked now. These exceptions must
be caught or declared in the throws clause of method declarations.
OpenCardException
is a subclass of java.io.IOException, so applications that use
the OCF specializations of the java.io package will require only
few changes.
CardID
In OCF 1.0, the class opencard.core.terminal.CardID served a dual
purpose. It represented a smartcard's ATR, and it could be used as a template
for matching a set of ATRs. In order to do this, it included methods that
tried to determine the card OS from the ATR. This functionality relied
on a particular structure of the ATR, which was not fully specified. It
also lead to a lot of confusion about OpenCard compliant ATRs and OpenCard
compliant smartcards.
In OCF 1.1, the CardID class simply represents a smartcard's
ATR, optionally along with the terminal and slot in which the card has
been inserted. Interpreting the ATR is the responsibility of the available
CardServiceFactories. The notion of OpenCard compliance has been removed
completely. There is no requirement that makes an ATR, or a smartcard,
OpenCard compliant. If there is a CardServiceFactory that recognizes the
ATR, OCF can deal with the smartcard.
For selecting particular ATRs in a CardRequest, the interface
CardIDFilter
has been introduced. It can be implemented by an application in any appropriate
fashion. The template functionality of CardID in OCF 1.0 did not
provide this flexibility.
Event Handling
The event handling in opencard.core.terminal has been simplified.
All terminal events are now broadcasted via the CardTerminalRegistry.
Registering as listener at a CardTerminal is still supported, but deprecated.
The registry events that notified applications about CardTerminals
that have been dynamically added or removed are no longer available. Since
an application gets the events of all CardTerminals via the CardTerminalRegistry,
there is no need for them anymore.
The event broadcast is done in a simple loop over a vector of listeners.
The class OCFEventMulticaster has been removed. Registering or
unregistering listeners at an event multicaster caused considerable overhead,
which is now avoided.
APDU classes
The classes APDU, CommandAPDU, and ResponseAPDU
have been changed to allow reuse of APDUs. For ResponseAPDU, the
majority of the changes is transparent. On the other hand, CommandAPDU
has changed considerably. Instead of the various constructors for different
ISO cases, there are only constructors to initialize a buffer. The actual
APDU is composed by invoking append methods that add bytes or byte arrays
to the buffered APDU. Optionally, an APDU can be prepared in a byte array
and passed to one of the constructors of CommandAPDU. This change
will affect all existing CardServices. Here is an example of reusing an
existing CommandAPDU object:
apdu.setLength(0);
apdu.append(cla);
apdu.append(ins);
apdu.append(p1);
apdu.append(p2);
The new class ISOCommandAPDU in opencard.opt.terminal
provides the constructors formerly found in CommandAPDU, along
with the extended diagnostic output in toString. It is meant as
a help for debugging, but should not be used in production code.
For consistency of method names, pduLength and pduBytes
have been renamed to getLength and getBytes, respectively.
This will require minor changes in existing CardTerminal implementations.
CardService Instantiation
In OCF 1.0, CardService instantiation used the java.lang.reflect
package. The dependency on the reflections package is a major drawback,
since OCF should support embedded devices with small memory resources,
too. To overcome this problem, a CardService for OCF 1.1 has to provide
a default constructor without arguments.
If the constructor with three arguments, as required for OCF 1.0, did
nothing but invoke the base class constructor, just define an empty public
default constructor. If the constructor performed initializations that
depend on those arguments, the method CardService.initialize has
to be overwritten. In this case, don't forget to invoke the base class
implementation of that method.
For sake of method name consistency, chvDialog has been renamed
to getCHVDialog. Also, the documentation of CardService
and it's methods has been extended.
IO classes
The java.io specializations provided by OCF in the opencard.opt.iso.fs
package have been reworked. The API offered some features that have never
been implemented, or refer to non-ISO functionality that can not be expected
of a file system based smartcard. Some of the changes are also related
to the revised File Services. In particular,
the following changes have been implemented:
-
Class CardFileOpenMode has been removed.
-
The class was an anachronism related to concepts that have been dropped
for OCF 1.0. Whether card access is blocking or not is specified at the
time a CardService is created. When creating an instance of CardFile,
it is already fixed and cannot be overridden. Removing this class resulted
in changes to the constructors of CardFile.
-
Class CardFileInfo has been replaced by an interface.
-
The class CardFileInfo imposed a fixed structure on the implementation
of a file service. For example, it required the service to cache whether
a PIN has been entered for accessing a file. And, obviously, the class
used by a service to represent file info had to be derived of CardFileInfo.
This situation has been relaxed by replacing the class by an interface.
The interface defines some methods to query standard information, for example
whether it is a directory or a data file. The amount of data that can be
queried has been reduced to what is needed for file access. For example,
there is no method to query access conditions since it is up to the file
service to deal with them.
-
Class CardFileType has been removed.
-
The class CardFileType, which indicated whether a file is a directory
or a data file with a particular structure, has been replaced by a set
of query methods in CardFileInfo (see above).
Instead of asking the file info for the file type and comparing the type
to a predefined constant, the file info can be asked directly whether it
is a directory, a cyclic file, and so on. This seems more natural in an
object-oriented environment and reduces the code size of the framework.
-
Class CardAccess has been removed.
-
Class CardAccess was meant to represent access conditions to files
on the smartcard. Unfortunately, not all kind of access conditions could
be represented by that class or a specialization of it. For example, disjunctions
of conditions, like "CHV or external authentication" could not be
dealt with. Apart from that, the class was needed only at two places: the
class CardFileInfo from which it has been removed (see above)
and when creating files, which is not part of the ISO 7816-4 functionality
(see below).
Implementing a request of the CardService workgroup, the class CardAccess
has therefore been removed. A file service implementation can represent
access conditions as part of the file info in any way suitable for the
particular smartcard. Applications should not have to deal with access
conditions at all, since it is the responsibility of the card service to
satisfy them.
-
Class CardFile has been revised.
-
The class CardFile in OCF 1.0 was modelled closely after the class
java.io.File.
This resulted in some methods that are hard or impossible to map to smartcards,
like list or readable. These have been removed, along
with some attributes that are not really needed, like
fileSeparator.
The references to the removed classes mentioned above had to be removed.
This implied changing all constructors to remove the reference to CardFileOpenMode.
The create method has been changed to the new FileSystemCardService
interface (see below). mkdir
has been removed completely, since it would have been identical to the
new create.
Some methods have been renamed for consistency. For example, path
is now getPath, length is now length, and fileInfo
became getFileInfo. Duplicate methods that accepted a string instead
of a CardFilePath have been removed, to minimize the number of
temporary objects that are created.
For convenience, CardFile implements the CardFileInfo
(see above). All methods are mapped
to invocations of the file info object returned by the underlying file
service. The advantage is that methods like isDirectory can be
invoked directly on the CardFile object instead of getting the
info first.
-
The key handling has been revised and moved.
-
The classes KeyStore and KeyBag defined a key handling
mechanism required for satisfying access conditions that involve cryptography.
This functionality is not specific to file system accesses, or even file
system based smartcards. The key handling has therefore been revised and
moved to the package opencard.opt.security. (Details)
File Services
The interface FileSystemCardService as defined in OCF 1.0 suffered
from several drawbacks. First of all, it required support for functionality
that is not defined in ISO 7816-4, like creating files. Second, it introduced
dependencies on many of the classes defined in the opencard.opt.iso.fs
package. Third, it defined key handling functionality that is not specific
to the file system, but could also be required for signature generation
or other operations supported by a smartcard. To overcome these drawbacks,
several changes have been implemented.
The key handling functionality has been moved from opencard.opt.iso.fs
to opencard.opt.security (see below).
The ISO functionality has been moved to a new, simpler interface named
FileAccessCardService.
The name has been chosen since ISO specifies only commands for accessing
files and their contents, but not the creation, deletion or comparable
operations typically found in a file system. The
FileSystemCardService
extends the file access interface by methods to do exactly that. It is
up to the developers of file services whether one or both interfaces are
implemented. Applications should use only the file access interface to
be independent of a particular smartcard.
To reduce the dependencies on other classes and interfaces in the iso.fs
package, the signatures of the methods in both service interfaces have
been changed. The dependencies are now restricted to the class CardFilePath
and the interface CardFileInfo. Dependencies on CardFileOpenMode,
CardFile,
CardFileType,
CardAccess,
CardRecord
(and maybe some more) have been removed. Unfortunately, this requires changes
in existing implementations of the file system service. Applications will
need some minor changes, too.
Here are the highlights of the changes in the file service interfaces:
-
The target files are specified by CardFilePath arguments rather
than CardFile arguments.
-
The mount methods have been removed. To obtain a CardFile
object for the master file, just pass the file service to the constructor
of that class. To refer to a file with an absolute path, the constructor
gets the file service and the path.
-
A method named getRoot has been introduced. It is meant to return
the path to the master file of the smartcard. That way, it is possible
to implement file services for cards with a master file id that is different
from the ISO-specified 0x3f00. (Yes, there are such cards.)
-
A method named readRecords has been introduced in the new FileAccessCardService.
It is meant for reading cyclic files. Along with a magic number, it can
also be used to read all records of a structured file. This is the only
way to read a linear variable file completely without having to catch an
exception at the end of the file.
-
The create method in FileSystemCardService has a new
interface. It expects a card-specific data block that describes the file
to be created, including file type and access conditions. Even with the
old interface, it was not really possible to create a file in a card-independent
way, but now it is obvious.
The new interface is intended for scenarios in which a card application
has to be loaded from a host to a smartcard. We assumed that the host is
able to prepare the card-specific data block and sends it to the OCF program
that invokes create. Besides, developers still have a chance to
create files on particular cards for testing purposes.
-
The API documentation of both file service interfaces has been greatly
enhanced. It should now be precise enough to implement and use the interfaces
conveniently.
Signature Services
The interface SignatureCardService as defined in OCF 1.1 suffered
from several drawbacks. First, it merged the functionality of generating
and verifying signatures with that of importing keys to the smartcard.
Second, the support was restricted to the RSA algorithm. DSA, or other
algorithms that may become important in the future could not be integrated.
Third, there was no interface for generating key pairs on the smartcard
itself, which is supported by some cards. Fourth, using the smartcards
for signatures may require satisfying access conditions similar to those
for file access (see File Services above),
but there was no way to pass authentication keys to the service. Last but
not least, the SignatureCardService in OCF 1.0 used CardFilePath
to refer to keys. The interface could therefore only be used for file system
based smartcards, but not for JavaCards.
To overcome these problems, the interface SignatureCardService
has been split, the method signatures have been changed to support various
public key algorithms, and a new interface for key generation on the card
has been defined. All interfaces extend SecureService (see Key
Handling below) so authentication keys can be provided. Of course,
the documentation of the methods has been enhanced.
Here are the three interfaces in opencard.opt.signature and
a short description of the functionality they define:
-
SignatureCardService
-
Provides methods to sign and to verify signatures on data or hashs on data.
References to the keys on the smartcard are generic and can be specialized
to paths or cardlets. The algorithm for signature generation or verification
can be specified by strings. The algorithm names are those defined by the
Java
Cryptography Architecture (JCA). Optionally, the padding algorithm
can be specified in the same way.
The OCF 1.0 methods to generate and verify signatures are still defined
in the interface, but deprecated. These methods introduce a dependency
on the opencard.opt.iso.fs package. They are likely to be removed
in future versions of OCF, for example for embedded devices.
-
KeyImportCardService
-
This extension of the SignatureCardService defines methods to
import private or public keys to a smartcard. Import can be done with plain
keys, or with keys that have a signature attached to them which will be
checked by the card. Generic references are used to specify the place to
put the key.
Generic key representations are used to pass the key data. A particular
implementation of this CardService interface will convert the generic representation
to a card specific one. In OCF 1.0, the key had to be passed in a card
specific representation.
-
KeyGenerationCardService
-
This extension of the SignatureCardService defines a method to
generate a key pair, that is a private key and matching public key, on
the card. A second method is defined to read the generated public key from
the card. The private key will never leave the card, which ensures a high
level of privacy.
Key Handling
In OCF 1.0, the FileSystemCardService interface was the only one
that defined support for secret keys. Such keys are used to satisfy access
conditions that involve cryptography. The concept for key handling was
that an application provides the keys, while the service contains the cryptographic
code to satisfy the access conditions. For OCF 1.1, several changes regarding
key handling have been implemented:
-
The key handling has been moved from opencard.opt.iso.fs to opencard.opt.security.
The interface SecureService in that package can be extended by
any CardService interface. Standard interfaces that do so are FileAccessCardService
(see File Services) and SignatureCardService
(see Signature Services). The interface
of SecureService uses generic identifiers for security domains,
instead of CardFile as in OCF 1.0. That way, the interface is
appropriate for JavaCards, too.
-
Keys have been replaced by credentials, in the concept as well as
in class names. Unlike a key, a credential may include cryptographic code
as well as the key material. Instead of using a key with it's own cryptographic
code, a CardService may use methods defined in a credential's interface
to encrypt, decrypt, compute a MAC, or generate a cryptographically strong
random number. This is a prerequisite for supporting a Secure Access
Module (SAM) that performs such operations without revealing the keys
stored in it.
This page was created by Frank Seliger, Roland Weber
and Lothar Merk.