This two-part series of articles will demonstrate the use of Java Card™ technology to enhance the security of Java 2 Platform, Micro Edition (J2ME) applications. This first article begins with an introduction to smart card and Java Card technologies. I'll examine the workings of a sample e-bank application in which Java Cards will serve J2ME clients. I'll also demonstrate how to load and install Java applications onto Java Cards. Next, I'll explain the exchange of messages that occurs when a J2ME client invokes the services of a Java Card. Finally, I demonstrate how the different classes of the sample Java Card application work.
Smart cards and Java Card technology
Let's start by introducing smart card technology and describing what it offers. Smart cards are plastic cards that comply with the ISO 7816 standard (see Resources for a link). They have a silicon chip embedded on the plastic. Possible uses of smart cards include credit cards and SIM cards in cellular devices. The silicon chip on a smart card contains memory to permanently hold data and, possibly, smart card applications. The chip may also contain the processing capability needed to run smart card applications.
Smart cards are generally used in conjunction with a smart card reader device. This device normally also provides the electrical input to power up the smart card, and may contain host applications that communicate with applications residing on the smart cards.
Smart cards are the highly enhanced successors to magnetic strip cards. The smart card has three main advantages over magnetic strip cards:
- A smart card's storage capacity is several hundred times that of a magnetic strip card.
- A smart card has processing capability that cannot be added to a magnetic strip card.
- Because a smart card has processing capability, powerful authentication mechanisms can be implemented to access the data stored in that card. This means that your data is much more secure on a smart card than it is on a magnetic strip card.
Resources contains links to some interesting articles that describe smart card technology in detail.
All Java Cards are essentially smart cards with one extra feature. The Java Card technology allows different vendors to use the Java language to develop smart card applications that are hosted on an individual card. For example, if the SIM card in your cell phone is a Java Card, it could contain value-added Java Card applications that, for instance, would manage your insurance policy, your medical records, your electronic wallet, and so on.
In this series of articles, I will focus on the use of Java Card technology with J2ME devices, although Java Card technology is not limited to the J2ME platform. The Security and Trust Services API (SATSA) enables the use of Java Card technology in J2ME devices. I will demonstrate the use of SATSA in this series of articles.
To begin, let's see how such value-added applications would work on a J2ME-enabled mobile phone with a Java Card inside. (Note that such a mobile phone would itself serve as the Java Card reader device.)
The Java Card technology for wireless applications
Let's consider two use case scenarios from the financial services and health care industries to elaborate some potential uses of Java Card technology.
A Java Card might carry medical records, such as your blood group, allergies, medical history, emergency instructions, and so on. Your doctor could access the medical records in the card to learn your medical history and prescribe medication. Drug stores could access the Java Card to verify a prescription. Your hospital might access your Java Card to provide appropriate treatment and also update your medical history. Similarly, in case of an emergency, the hospital could access emergency instructions from your Java Card. If your insurance premium depended on your health condition, your insurance company might also access your Java Card to check your medical records. The Java Card would contain authentication and authorization logic to determine who is authorized to access the various pieces of information stored on it.
A Java Card application could also work as an authentication module in a J2ME-based e-bank application. The e-bank application would allow its users to access their bank accounts using their cell phones. The Java Card application on the Java Card would contain the authentication logic that ascertained who was trying to credit or debit an account. The J2ME device would contain a MIDlet that would present an easy-to-use GUI for account access.
In this series of articles, I will use the latter example -- an e-bank application -- to demonstrate the potential of Java Card technology. To get started, let's examine the architecture of a Java Card application, look at its components, and see how it serves J2ME-based client applications.
Java Card technology offers an open architecture for smart card application development. A Java Card contains a virtual machine (called a Java Card Virtual Machine, or JCVM for short) and a set of APIs (collectively known as the Java Card API). Some of the classes and interfaces in the Java Card API are exposed for use by J2ME MIDlets and other client applications. Throughout this series of articles, you will see examples of the classes and interfaces that are exposed to client applications. (One such example is a class named RMIService, which I will introduce later while examining Listing 4.) Such classes and interfaces, together with the JCVM, are collectively known as the Java Card Runtime Environment, or JCRE for short.
In this series of articles, I will demonstrate the use of Java Card APIs in J2ME applications using a sample application. Before you can start developing the sample application, you will need to download a few freely available software packages, which have been listed in a readme.txt file included in the source code download of this article.
Let's first briefly discuss what the sample application will do. This will help you understand Java Card technology's usage model.
The architecture of an e-bank application
The sample application in this series of articles is the same Kerberos-based J2ME application that I developed in my earlier series, entitled "Lock down J2ME applications with Kerberos" (see Resources for links to all three parts). I will add Java Card features to this Kerberos application and show how the combination of Java Card and Kerberos technologies strengthens the security of J2ME applications.
The sample application lets bank account holders use their J2ME-enabled cell phones to securely access their bank accounts, make and receive payments, and check their balances. Let's call this application an e-bank application. I will develop the e-bank application in three components. There will be a Java Card application called JavaCardKerberosKey. All Java Card applications work as applets, so JavaCardKerberosKey will actually be a Java Card applet. The second component will be a MIDlet called KerberosEBank. The main purpose of this MIDlet is to provide a graphical user interface to the e-bank application. The third part of the application is the e-bank's server-side component. (At this point, you may want to go through my "Lock down J2ME applications with Kerberos" series of articles to understand the terms for the Kerberos components in the application, such as a key distribution center (KDC), a ticket granting ticket (TGT), and a session key, as well as the use of secret keying in Kerberos-based security, if those concepts are unfamiliar to you.)
The JavaCardKerberosKey applet works as a secret key manager. It contains a Kerberos secret key that is used to secure communication between a J2ME cell phone user and the bank's business logic. The secret key is used to decrypt the encrypted portion of a TGT. (I described the structure of a TGT in the "Exchange of Kerberos messages" section of the first article of my earlier series.) The encrypted portion contains the session key, which an application can only extract using the Kerberos secret key. Therefore, knowing the secret key is essential for using a TGT.
The secret key consists of eight bytes, which the e-bank application will divide into two portions of four bytes each:
The first part is the user's key, which both the e-bank and the user will know. The e-bank will install this key on the account holder's Java Card at the same time that it installs the
JavaCardKerberosKeyapplet. (I will demonstrate this installation process shortly.)The user's key will be a simple alphanumeric PIN code. The customer will provide the user's key every time she wants to access her e-bank account. Here, note that the customer needs to use both her key and the specific Java Card in which the e-bank installed the user's key to access her e-bank account. If someone stole the user's key, it would not be operative unless the same individual also stole the physical Java Card for that particular account. This is sometimes referred to as dual factor security, which is considered quite effective. In dual factor security, authentication is based both on something that a user knows (such as a PIN code) and on something that a user carries or possesses (such as a Java Card).
The second part of the key is the e-bank's key, which only the e-bank will know. The e-bank will install this key when it installs the Java Card applet. The Java Card technology ensures that the e-bank's key is never exposed to any client application accessing the Java Card application.
The e-bank will set the user's and e-bank's keys in the JavaCardKerberosKey applet when it installs the applet on the user's Java Card.
The KerberosEBank MIDlet is a client of the JavaCardKerberosKey applet, which means that the KerberosEBank MIDlet will use the JavaCardKerberosKey applet to decrypt the encrypted portion of the TGT and extract the session key. The KerberosEBank MIDlet will request a TGT from the e-bank's KDC server. On receipt of the TGT, the KerberosEBank MIDlet will extract the encrypted portion of the TGT and hand it over to the JavaCardKerberosKey applet. The KerberosEBank MIDlet will also provide the user's key to the JavaCardKerberosKey applet. The JavaCardKerberosKey applet will authenticate the user; if the authentication succeeds, it will decrypt the encrypted portion of the TGT, extract the session key, and return the session key to the KerberosEBank MIDlet. The KerberosEBank MIDlet will use the decrypted session key to secure communication with the e-bank server.
Now, let's see how the e-bank will load the JavaCardKerberosKey applet onto the user's Java Card.
Loading a Java Card application onto a Java Card
Java Card applications work as applets having a definite life cycle: they are compiled, copied onto a Java Card, installed, and executed. The top-level class in all Java Card applications has to extend the javacard.framework.Applet class, which is part of the Java Card framework.
Java Card applications are compiled as normal Java 2 Platform, Standard Edition (J2SE) applications (for example, using a Java IDE like Eclipse). Suppose the e-bank application vendor has successfully compiled its JavaCardKerberosKey applet and is now ready to install it in the JCRE of a Java Card. The e-bank will need to follow a few steps in order to do so.
After compiling the Java Card application code into a set of .class files, the e-bank will pack, or cap, the .class files into a single .cap file, which will contain the complete Java Card application. The e-bank can cap its Java Card application using the converter tool that comes with the Java Card Development Kit, called JCDK for short. If you want to follow along on your own machine, you can download JCDK as a single zip file named java_card_kit-2_2_1.zip (see the Resources section for download details). I will use JCDK extensively in this series of articles, so it's a good idea to do this now. When you unzip java_card_kit-2_2_1.zip, you will find a folder named bin. The converter and other utility tools that I will use in this article are in this folder.
The e-bank wraps the Java Card application data in the .cap file using the command-line statement shown in Listing 1.
Listing 1. The converter tool command-line statement
converter -applet 0xa:0x0:0x0:0x0:0x62:0x3:0x1:0x1
KerberosCardApplet.JavaCardKerberosKey
-classdir X:\KerberosCardApplet
-exportpath X:\java_card_kit-2_2_1\api_export_files
KerberosCardApplet 0xa0:0x0:0x0:0x0:0x62:0x3:0x1:0x0 1.0
|
You can see from the command line provided above that the converter tool takes three options: applet, classdir, and exportpath.
-
The
appletoption specifies the application ID (or AID for short) and the qualified name of theJavaCardKerberosKeyapplet. All Java Card applets have AIDs. Client applications (such as theKerberosEBankMIDlet) identify the different applets in a Java Card through their AIDs. The first five bytes of an AID are a fixed value (0xa0:0x0:0x0:0x0:0x62). You can specify an additional 0 to 11 bytes to uniquely identify your application. -
The
classdiroption specifies the path of the .class files that you want to cap. -
The
exportpathoption specifies the location path to export files. The export files tell where to find the Java Card API implementation. JCDK comes with all the required export files. When you unzip the java_card_kit-2_2_1.zip file, you will find a folder named api_export_files, which contains all the export files you need. You just need to include the complete path of the api_export_files folder here.
The string KerberosCardApplet in Listing 1 specifies the applet's package name. The applet is identified by this package name in the JCRE. The byte sequence 0xa0:0x0:0x0:0x0:0x62:0x3:0x1:0x0 specifies the AID of the KerberosCardApplet package. The last number in Listing 1 (1.0) specifies the version number of the applet.
The converter tool generates two output files, named KerberosCardApplet.cap and KerberosCardApplet.exp. The two files are stored in a directory named javacard at the classpath location specified in the classdir option to the converter tool. The KerberosCardApplet.cap file is the required cap file that I needed to generate. The KerberosCardApplet.exp file is an export file that you will need only if you want to use some classes of your e-bank application in some other Java Card application. I won't be using this export file in this series.
Now the KerberosCardApplet.cap file needs to be loaded (or copied) onto the Java Card. All Java Cards come loaded with an installer applet, whose job is to load new Java Card applications onto the Java Card. The AID of the installer applet is 0xa0:0x00:0x00:0x00:0x62:0x03:0x01:0x08:0x01.
The KerberosCardApplet.cap file cannot be directly loaded onto a Java Card. The installer applet, like all other Java Card applets, communicates with the outside world through sequences of bytes called Application Protocol Data Units, or APDUs for short. APDUs are the communication format that all Java Card applications use to communicate with client applications running outside the Java Card.
A tool named scriptgen (which comes with the JCDK) transforms the KerberosCardApplet.cap file into a script file named KerberosCardApplet.src. KerberosCardApplet.scr will contain the KerberosCardApplet.cap file in the required form of a set of APDUs. The installer applet accepts the sequence of APDUs from the KerberosCardApplet.src file. The following command line generates a set of APDUs for KerberosCardApplet.cap and stores the output APDUs in KerberosCardApplet.scr.
scriptgen -o KerberosCardApplet.scr KerberosCardApplet.cap |
The KerberosCardApplet.scr file generated by scriptgen is not complete; you'll need to edit it manually. Open the KerberosCardApplet.scr in a text editor and make the following changes in the file:
-
Insert the string
powerupin the first line of the file. As you will shortly see, I will use another tool namedapdutool(which also comes with the JCDK) to upload the APDUs contained in the KerberosCardApplet.scr file to the installer applet. Thepowerupcommand prepares the two ends (theapdutooland the installer applet) for communication. -
I also need to add the AID of the installer applet. The AID will occur immediately after the
powerupcommand. This specifies the applet (in this case, the installer applet) that theapdutoolwill ask the card reader device to invoke for APDU exchange. -
Insert the string
powerdownat the end of the file. This command marks the end of APDU exchange between theapdutooland the installer applet.
The source code download in this article contains files named KerberosCardApplet_BeforeEditing.scr and KerberosCardApplet_AfterEditing.scr. These files illustrate what the KerberosCardApplet.scr file looks like before and after manual editing.
But where is the Java Card and its reader device to which you will upload the applet using apdutool? The JCDK provides a tool called cref that simulates a Java Card in a card reader. So, before you can use the apdutool, you must start the cref simulator by using the following command-line statement:
start cref -o KerberosCardApplet.eeprom
This command line starts the cref simulator in a separate window, listening at its default port, 9025. The -o option specifies the name of an output file with an .eeprom extension.
When you run the command-line statement above, a file named KerberosCardApplet.eeprom is created in the command line execution directory. This file simulates the electrically erasable programmable read only memory (EEPROM) portion of a Java Card. You don't need to understand the details of a Java Card's EEPROM to write Java Card applications; just note that the EEPROM portion of the card contains the Java Card applets.
Now run apdutool using the following command-line statement. The KerberosCardApplet.eeprom file will be populated with the .scr file.
apdutool X:/KerberosCardApplet/javacard/KerberosCardApplet.scr
After populating the KerberosCardApplet.eeprom file with the required data, the cref simulator will close the connection with apdutool. After that's happened, you should manually shut down the cref simulator by closing the simulator window.
Note that the cref simulator works according to the Java Card platform specification. Therefore, when you work with a real Java Card reader, you'll use apdutool just as you do here.
The JavaCardKerberosKey applet is now loaded in the Java Card simulator. Next, you'll learn how to install this applet.
Installing a Java Card application
In the previous section, you learned how to load a Java Card application onto a Java Card. Now the JavaCardKerberosKey applet resides inside the Java Card. The next step is to install the applet, so that the KerberosEBank MIDlet client can use its services.
Installing the JavaCardKerberosKey applet means instantiating the applet class in the JCRE. I need to write a new .scr file (install.scr) to install the JavaCardKerberosKey applet. You can see the contents of this file in Listing 2.
Listing 2. The install.scr file to install the JavaCardKerberosKey applet
powerup; 0x80 0xB0 0x00 0x00 0x00 0x7F; // Command APDU for the AID of the installer applet. 0x00 0xA4 0x04 0x00 0x09 0xa0 0x00 0x00 0x00 0x62 0x03 0x01 0x08 0x01 0x7F; // Command APDU for the AID of the JavaCardKerberosKey applet // along with user and e-bank keys. 0x80 0xB8 0x0 0x0 0x12 0x08 0xa0 0x0 0x0 0x0 0x62 0x03 0x0 0x01 0x08 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x7F; 0x80 0xBA 0x00 0x00 0x00 0x7F; powerdown; |
The install.scr file in Listing 2 is very simple. It starts with the powerup command and ends with the powerdown command. In between, there are two AIDs wrapped inside their respective command APDUs. The first AID identifies the installer applet and the second identifies the applet to be installed (that is, the JavaCardKerberosKey applet).
The e-bank application will choose its own AID for its JavaCardKerberosKey applet. There are two other pieces of data that the e-bank application will need to include with the applet AID data: the user's key and the e-bank's key that I want to provide to the JavaCardKerberosKey applet at the time of installation. You need to include these two keys within the applet AID data in the install.scr file, because later on you will have no chance to send the keys to the JavaCardKerberosKey applet.
Now there are three bits of data -- the AID bytes, the user's key, and the e-bank's key -- wrapped in the command APDU for the AID of the JavaCardKerberosKey applet. If the AID for the JavaCardKerberosKey applet you supplied is already occupied by some other applet on the Java Card, the apdutool will receive an error from the installer applet.
After writing the install.scr file, you will need to launch the cref simulator, using the same command-line statement as before.
start cref -o KerberosCardApplet.eeprom |
This starts the cref simulator in a separate window. The cref simulator is now waiting for apdutool to send applet installation instructions. Use the apdutool to send the install.scr file APDUs to the cref simulator and install the applet on the Java Card. The following command-line statement shows the use of apdutool to install the JavaCardKerberosKey applet.
apdutool install.scr |
Here you can see that the AID bytes of the install.scr file that the apdutool sends to the installer applet are plain text bytes without any encryption. Therefore, you are assuming that the installation of the JavaCardKerberosKey applet takes place over a trusted secure network (the e-bank's private network within its premises, say, or perhaps a virtual private network). In the next article in this series, I will demonstrate how Java Card applications can also communicate securely with the outside world.
On receipt of the install command, the installer applet calls the install() method of the JavaCardKerberosKey applet.
The install() method of all Java Card applets is static, which means that it can be called without instantiating the applet. You can see the install() method implementation of the JavaCardKerberosKey applet in Listing 3.
Listing 3. The install() method of JavaCardKerberosKey
public static void install(
byte[] installationData, short offset, byte length) {
new JavaCardKerberosKey(installationData, offset, length);
}//install()
|
As you can see, the install() method does just one job: it instantiates a new JavaCardKerberosKey object by calling its constructor. The install() method is called once at the time of installation, so only one instance of the JavaCardKerberosKey applet will exist in the course of the applet's lifetime.
Notice that the install() method receives three parameters from the installer applet:
- The first parameter is a byte array named
installationData, which contains the AID of theJavaCardKerberosKeyapplet, the user's key, and the e-bank's key. - The second parameter specifies the starting position of content in the
installationDatabyte array. - The third parameter specifies how many bytes are for your use after the starting position.
The install() method passes the three parameters to the JavaCardKerberosKey applet constructor. The applet constructor processes the three parameters during the installation process. Let's see how.
The JavaCardKerberosKey constructor
This installation process provides the applet being installed with a chance to perform application-specific start-up processing. For example, the JavaCardKerberosKey applet wants to store the e-bank's and user's keys during the installation process for later use during user authentication.
You can see the JavaCardKerberosKey constructor in Listing 4.
Listing 4. The JavaCardKerberosKey applet constructor
public JavaCardKerberosKey(byte[] installationData, short offset, byte length) {
//**** Step1 *****
byte[] userKey = new byte[PIN_LENGTH];
byte[] eBankKey = new byte[PIN_LENGTH];
//getting offset of key data in installationData byte array.
byte aidLength = installationData[offset];
short kdOffset = (short)(offset+aidLength+1);
byte[] appletAID = new byte[aidLength];
Util.arrayCopy(appletAID, (short)0, installationData, (short)(offset+1),(short)aidLength);
Util.arrayCopy(userKey, (short)0, installationData, (short)(kdOffset+1), PIN_LENGTH);
Util.arrayCopy(eBankKey, (short)0, installationData, (short)(kdOffset+5),PIN_LENGTH);
//**** Step2 *****
UserPIN userPIN = new UserPIN (userKey);
EBankPIN ebankPIN = new EBankPIN(userKey, eBankKey);
//**** Step3 *****
SecurityService secService =
new KerberosSecurityService(userPIN);
//**** Step4 *****
Remote keyManager =
new KerberosKeyManager(secService, ebankPIN);
//**** Step5 *****
RMIService rmiService = new RMIService(keyManager);
//**** Step6 *****
disp = new Dispatcher( (short)2);
disp.addService(secService, Dispatcher.PROCESS_COMMAND);
disp.addService(rmiService, Dispatcher.PROCESS_COMMAND);
//**** Step7 *****
register(appletAID, (short)0, aidLength);
}//JavaCardKerberosKey()
|
The JavaCardKerberosKey constructor performs seven steps (you can use the comments in the listing to follow along in the code):
-
The
installationDatabyte array contains the e-bank's key and the user's key appended to the AID bytes. So the first step is to extract the two keys and the AID bytes from theinstallationDatabyte array. In Step 1 of Listing 4, I have instantiated three byte arrays namedeBankKey,userKey, andappletAID, and used a utility method namedUtil.arrayCopy()to copy the corresponding key data from theinstallationDatabyte array into their respective byte arrays. - In the second step, I instantiate two PIN classes named
UserPINandEBankPIN. You'll see how these classes work in the next article of this series; for now, just note that theUserPINclass wraps the user's key bytes that you got in Step 1, and thatEBankPINclass wraps both the user's and e-bank's keys. The two classes will use the keys for authentication and decryption later on. - In Step 3, I instantiate a
KerberosSecurityServiceobject and pass theUserPINobject (from Step 2) to its constructor. TheKerberosSecurityServiceclass provides an authentication service to the e-bank application. It uses theUserPINclass for data decryption and user authentication purposes. - In Step 4, I have instantiated a
KerberosKeyManagerobject. TheKerberosKeyManagerclass implements the business logic of the e-bank application. The business logic here takes an encrypted Kerberos structure and extracts a Kerberos session key from that structure. A client application (such as theKerberosEBankMIDlet) will use the business logic of the e-bank application by calling the methods of theKerberosKeyManagerclass. Later, in Using a Java Card applet with a J2ME client application, I'll explain how I'll expose the methods of theKerberosKeyManagerclass to the client for remote access, how the remote client will gain access to a reference of theKerberosKeyManagerobject, and how the JCRE will route method invocation requests from remote clients to theKerberosKeyManagerclass. - In Step 5, I instantiate an
RMIServiceclass. TheRMIServiceclass is used to service remote method invocation requests from remote clients. For example, theKerberosEBankMIDlet client will first get the reference to theKerberosKeyManagerclass and then make a remote method invocation request using the remote reference. TheRMIServiceclass will handle all such remote requests. In other words, you can say that theRMIServiceclass will service the remote clients on behalf of theKerberosKeyManagerclass. Therefore, while instantiating theRMIServiceclass, I will pass theKerberosKeyManagerobject as a parameter to theRMIServiceconstructor. This identifies the class that theRMIServiceclass should use for serving RMI requests from remote clients. - The Java Card framework provides a well-defined mechanism for all service provider classes. In Java Card terminology, a service is defined as an object that processes a command from a client. Commands from clients come as APDUs.
All service provider classes are actually command APDU processing classes. Both
KerberosSecurityServiceandRMIServiceclasses are service provider classes; therefore, I must follow Java Card's service provision (or APDU processing) mechanism in order to use these two classes in theJavaCardKerberosKeyapplet. Later in this section, I will explain how the different service provider classes work in the Java Card framework. For now, just note that I must register all service provider classes with a class namedDispatcher.In Step 6, I instantiate a
Dispatcherobject and then call itsaddService()method. TheDispatcherconstructor takes just one parameter: the maximum number of services I want to register with theDispatcherobject.The
addService()method takes two parameters. The first is the instance of the service provider class that will handle a client's request for a service; the second is the identifier for a phase. The Java Card platform specification defines various APDU processing phases; you'll learn more about these in APDU processing in a Java Card application. For now, just note in Step 6 in Listing 4 that both the service provider classes (KerberosSecurityServiceandKerberosKeyManager) are registered in thePROCESS_COMMANDphase. -
Now I am all set. The applet is ready to serve its J2ME clients. Therefore, I will register the applet with the JCRE by calling the
register()method of thejavacard.framework.Appletclass. Theregister()method takes three parameters. The first is a byte array containing the AID of the applet, the one I got in Step 1, which the client uses to access this applet. If the AID for the applet is not unique, theregister()method raises an illegal AID exception and the applet registration with JCRE fails. The second parameter is an offset value specifying where the AID bytes begin in the byte array. The third parameter specifies the length of the AID bytes in the byte array.
APDU processing in a Java Card application
Now let's discuss the different phases of APDU processing in a Java Card application.
Recall that while discussing Steps 3 and 6 of the JavaCardKerberosKey constructor in Listing 4, I instantiated a KerberosSecurityService object and registered it with the Dispatcher object. The KerberosSecurityService class has a method named processCommand(), which you'll see in more detail later in Major classes in the e-bank application. When the Dispatcher receives some APDU from a client application, it will forward that APDU to the processCommand() method of the KerberosSecurityService class.
Any class that wants to act as a service provider (such as the KerberosSecurityService class, which acts as an authentication service provider) should implement an interface named Service, which is part of the javacard.framework.service package. The Java Card framework contains a convenience class named BasicService that implements the Service interface along with many helper methods to process incoming APDUs from requesting client applications. Therefore, instead of implementing the Service interface directly, it is better to extend BasicService. That's what I'll do while implementing the KerberosSecurityService class.
The Service interface contains methods named processDataIn(), processCommand(), and processDataOut(). Recall that I registered the KerberosSecurityService class for the PROCESS_COMMAND phase in step 6 of Listing 4. The PROCESS_COMMAND phase is actually one of the three available APDU processing phases; the other two are PROCESS_INPUT_DATA and PROCESS_OUTPUT_DATA.
The Java Card framework allows you to register as many services in any of the three phases as you like. The three phases work in the following sequence:
- When a Java Card applet receives an APDU from a client application, it hands over the APDU to the
Dispatcher, and thePROCESS_INPUT_DATAprocessing phase begins. TheDispatcherfirst checks to see how many service provider classes are registered with it for thePROCESS_INPUT_DATAphase. It will then call theprocessDataIn()methods of the classes one by one. The sequence ofprocessDataIn()method calls will be the same as the sequence in which the classes were registered with theDispatcher.You should keep in mind that any
processDataIn()method can stop further processing in thePROCESS_INPUT_DATAphase by returningtrue. If this happens, the JCRE will think that thePROCESS_INPUT_DATAphase is over, and will, therefore, not call theprocessDataIn()methods of the remaining service classes registered for thePROCESS_INPUT_DATAphase.In the
JavaCardKerberosKeyapplet, you don't need to do any processing in thePROCESS_INPUT_DATAphase. That's why I have not registered any service class with theDispatcherfor this phase. - After the
PROCESS_INPUT_DATAphase, thePROCESS_COMMANDphase takes place. The JCRE will call theprocessCommand()method of the service provider classes registered for thePROCESS_COMMANDphase one by one. If any of theprocessCommand()methods returntrue, thePROCESS_COMMANDphase will be terminated and no further calls to the remainingprocessCommand()methods will be made.Recall from Step 6 of the
JavaCardKerberosKeyconstructor of Listing 4 that theJavaCardKerberosKeyconstructor registered two service provider classes (firstKerberosSecurityServiceand thenRMIService) for thePROCESS_COMMANDphase. The JCRE will first call theprocessCommand()method of theKerberosSecurityServiceclass, which will provide authentication service to the application. If the requesting client is successfully authenticated, theprocessCommand()method of theKerberosSecurityServiceclass will returnfalse, so that theprocessCommand()method of theRMIServiceclass will be called. This method will use theKerberosKeyManagerclass to provide the actual Kerberos session key to the requesting client. -
After the
PROCESS_COMMANDphase is over, thePROCESS_OUTPUT_DATAphase begins. It is similar to the first two phases. TheprocessDataOut()methods of the service provider classes are called in this phase. I have not used this phase in the sample application.
Now it should be obvious why every service provider class needs to implement the Service interface: this interface contains the three APDU processing methods (processDataIn(), processCommand(), and processDataOut()).
The e-bank is now finished installing the Java Card application, and you have seen how to install and register the JavaCardKerberosKey applet in a Java Card. You have also seen the different APDU processing phases of a Java Card application. Now let's see how a J2ME application will select and execute a JavaCardKerberosKey to perform certain operations. Let's start by looking at the sequence of events that occurs in a communication session between the client application (that is, the KerberosEBank MIDlet) and the JavaCardKerberosKey applet.
Using a Java Card applet with a J2ME client application
There are two ways in which client applications will communicate with Java Card applets: synchronously or asynchronously. Synchronous communication is like calling a method of a class, and is blocking -- in other words, the application is blocked after making a method call until the method returns. Synchronous communication in Java Card applications uses the Remote Method Invocation (RMI) framework. On the other hand, asynchronous communication is like sending and receiving messages. Asynchronous communication is always non-blocking: you send a message and then start doing something else until you receive a response from the recipient.
The e-bank application will use the synchronous (RMI) method of communicating with Java Card applications. Let's see the sequence of events that occurs when the KerberosEBank MIDlet communicates synchronously with the JavaCardKerberosKey applet.
Suppose a J2ME cell phone user wants to check the balance in her e-bank account. The sequence of events shown in Figure 1 allows her to check the balance.
Figure 1. The sequence of events that occur when a J2ME mobile phone user checks her e-bank account

You can map the sequence numbers in Figure 1 to the following steps:
- The J2ME mobile phone user invokes the
KerberosEBankMIDlet in her J2ME cell phone and provides the user's key to theKerberosEBankMIDlet. - The
KerberosEBankMIDlet fetches a Kerberos ticket granting ticket (TGT) from a Kerberos distribution center (KDC). I discussed the details of fetching a Kerberos TGT from a KDC in the "Authoring a TGT request" section of the second article in my "Lock down J2ME applications with Kerberos" series. You can also refer to the "The request for a TGT" section of the same article, where I explained the structure of a TGT, which contains an encrypted portion namedenc-part. TheKerberosEBankMIDlet will extract this encrypted portion from the TGT. - Now the
KerberosEBankMIDlet wants to extract the session key from the encrypted portion. The session key will allow theKerberosEBankMIDlet to further communicate with the e-bank's server-side implementation. To do this, the MIDlet needs to communicate with theJavaCardKerberosKeyapplet. That's where you need a Security and Trust Services API (SATSA) implementation on the J2ME mobile phone. Without a SATSA implementation a J2ME device cannot communicate with a Java Card applet. SATSA provides a standard API for MIDlet applications to communicate with Java Card applets.The
KerberosEBankMIDlet will ask SATSA to select theJavaCardKerberosKeyapplet. The MIDlet will provide the AID of theJavaCardKerberosKeyapplet to SATSA and ask it to create a synchronous connection with the applet. Here you should recall that a J2ME mobile phone can itself act as a card reader device (if, for example, the SIM card in your phone is itself the Java Card that hosts theJavaCardKerberosKeyapplet). - SATSA sends an APDU to the
JavaCardKerberosKeyapplet. The APDU wraps the AID of theJavaCardKerberosKeyapplet (the applet that you want to select). The APDU sent at this stage is called theSELECTAPDU, the structure of which is clearly defined by the Java Card platform specification. I don't need to go into the details of the different types of APDUs, as SATSA manages the authoring and processing of all the types of APDUs that you need to communicate with Java Card applications. - A host application inside the Java Card reader device routes the
SELECTAPDU to the JCRE inside the Java Card. - The JCRE receives the
SELECTAPDU from the host application and identifies the Java Card applet by the AID wrapped inside theSELECTAPDU. - Now the JCRE finds the reference to an object that will be exposed to remote clients. In this case, the
KerberosKeyManagerobject exposes methods for theKerberosEBankMIDlet. Therefore, the JCRE will wrap a reference to theKerberosKeyManagerobject in aSELECTresponse APDU. - The JCRE returns the
SELECTresponse APDU to the host application. Note that theSELECTresponse APDU wraps a reference to theKerberosKeyManagerobject. The host application returns the
SELECTresponse APDU to theKerberosEBankMIDlet using SATSA.- The J2ME application will process the response APDU using SATSA and extract the reference to the
KerberosKeyManagerobject from the APDU. - The
KerberosEBankMIDlet can remotely invoke the different methods of theKerberosKeyManagerobject. Suppose the MIDlet invokes a method namedgetKey()on theKerberosKeyManagerobject. The MIDlet passes the user's key (from Step 1) and the encrypted portion of the TGT (from Step 2) in encrypted form to thegetKey()method. - The control goes back to SATSA. The SATSA framework prepares an
INVOKEAPDU containing thegetKey()method call and sends the APDU to the host application inside the Java Card reader device. - The host application sends the
INVOKEAPDU to the JCRE. - The JCRE hands over the
INVOKEAPDU to theJavaCardKerberosKeyapplet. - The
JavaCardKerberosKeyapplet receives theINVOKEAPDU and hands over the APDU to theDispatcher. - The
Dispatcherchecks to see which service provider should get control of theINVOKEAPDU. It finds that thePROCESS_COMMANDphase requires that theKerberosSecurityService.processCommand()method gain control. (If theKerberosSecurityService.processCommand()method had returnedfalse, theRMIServiceclass would have gain control.) - Therefore, the
Dispatcherforwards theINVOKEAPDU to theKerberosSecurityService.processCommand()method. - The
KerberosSecurityService.processCommand()method performs data decryption and authentication steps. If the decryption of the data fails, it raises an invalid data exception; otherwise, it proceeds with user authentication. If authentication is successful, the result is stored for future use, and the method returnsfalse. - If the
KerberosSecurityService.processCommand()method returnsfalse, theDispatchertransfers control to theRMIServiceclass and hands over theINVOKEAPDU to theRMIService. - The
RMIServiceclass now has theINVOKEAPDU. It processes the APDU to confirm that it is anINVOKEAPDU, meaning that it actually contains an RMI call. Next, theRMIServiceclass extracts the name of theRemoteobject and its method that theINVOKEAPDU is asking to invoke. In my case, the name of the remote object isKerberosKeyManagerand the method that should be invoked isgetKey(). Therefore, theRMIServiceclass invokes theKerberosKeyManager.getKey()method. While invoking the method, it also parses theINVOKEAPDU to extract the data that goes along with the method call as a parameter. In my case, thegetKey()method needs two pieces of information: the user's key (from Step 1) and the encrypted portion of the TGT (from Step 2). - The
KerberosKeyManager.getKey()method decrypts the encrypted portion of the TGT, extracts the session key from the decrypted data, and returns the session key toRMIService. - The
RMIServicereturns the session key to theDispatcher. - The
Dispatcherhands over the session key to the JCRE. - The JCRE authors a response APDU and sends it to the host application.
- The host application routes the response APDU to the
KerberosEBankMIDlet. The MIDlet uses SATSA to extract the session key from the APDU and then uses the session key for further communication with the e-bank.
Notice from the sequence of events that if the user either forgets her PIN code or does not have her Java Card, she will not be able to use her e-bank account.
I've finished discussing the sequence of events that result in the working of Java Card applications. I have already introduced the two important Java Card classes of the e-bank application (KerberosSecurityService and KerberosKeyManager). Now let's see how those classes work.
Major classes in the e-bank application
In the previous two sections, I introduced the following Java Card classes, which perform different tasks in the e-bank application:
KerberosSecurityServiceKerberosKeyManager
Now it's time to demonstrate how these classes work.
The KerberosSecurityService class
The KerberosSecurityService class shown in Listing 5 provides an authentication service to the e-bank application. The KerberosSecurityService class authenticates the user who tries to access the e-bank application.
Listing 5. The KerberosSecurityService class
public class KerberosSecurityService
extends BasicService implements SecurityService {
private UserPIN userPIN = null;
private byte userAuthenticated = 0;
private static final byte INS_INVOKE = (byte)0x38;
public KerberosSecurityService (UserPIN userPin) {
this.userPIN = userPin;
userAuthenticated = 0;
}//KerberosSecurityService
public boolean isAuthenticated(short principal)
throws ServiceException {
return (userAuthenticated == principal);
}
public boolean isCommandSecure(byte properties)
throws ServiceException {
return true;
}
public boolean isChannelSecure(byte prop) {
return true;
}
public boolean processCommand(APDU apdu) {
//**** Step 1 ****
if (isInvokeAPDU(apdu)) {
receiveInData(apdu);
//**** Step 2 ****
if (userPIN.check(apdu.getBuffer(), (short)5, (byte)4)) {
//**** Step 3 ****
userAuthenticated = PRINCIPAL_CARDHOLDER;
return false;
} else {
fail(apdu, ISO7816.SW_DATA_INVALID);
}
}
return false;
}//processCommand
private boolean isInvokeAPDU (APDU apdu) {
return (getINS(apdu) == INS_INVOKE);
}
}
|
Now let's see how the different methods of the KerberosSecurityService class shown in Listing 5 work.
The KerberosSecurityService constructor
Recall that the KerberosSecurityService constructor was called during the installation phase in Step 3 of Listing 4. Look at the KerberosSecurityService constructor in Listing 5, which takes just one parameter, named userPIN; this is a UserPIN object. The UserPIN class keeps the user's key stored with it for authentication later on. I'll explain the UserPIN class in the next article of this series.
The KerberosSecurityService constructor stores the UserPIN object for later use and also initializes an authentication flag. This flag is set after authentication.
The most important method of the KerberosSecurityService class is processCommand(), which I introduced earlier in APDU processing in a Java Card application. Let's now see how this method works.
The processCommand() method
The processCommand() method receives an APDU object as a parameter. This APDU contains two things: an encrypted Kerberos structure (that contains the Kerberos session key in encrypted form) and the user's key; I'll use the latter to authenticate the user. I am not interested in processing the Kerberos structure in the KerberosSecurityService class; I'll do this after authenticating the user. (You'll see this happen when I discuss the KerberosKeyManager class in the next section.)
The processCommand() method performs the following authentication steps, as shown in Listing 5:
- In Step 1, I check to see if the incoming APDU is an
INVOKEAPDU. I have used a helper method namedisInvokeAPDU()that checks the APDU and returnstrueif it is anINVOKEAPDU andfalseotherwise. If it is not anINVOKEAPDU, I don't need to do anything, and returnfalse. - Next, I check the validity of the user's key. The
processCommand()method passes the APDU object to theUserPIN.check()method, which extracts the user's key from the APDU and returnstrueonly if the user's key matches the one I installed in theUserPINobject in Step 2 of theJavaCardKerberosKeyapplet constructor (Listing 4). - If the comparison is successful, the
processCommand()method sets an authentication flag and returnsfalse.
The KerberosSecurityService class also implements the SecurityService interface, which is part of the javacard.framework.service package. Every class that wants to act as an authentication service provider should implement the SecurityService interface. This interface defines methods that provide services for user authentication and data integrity checking. For example, a method named isAuthenticated() will use the authentication flag set in Step 3 of the processCommand() method to indicate whether the user has successfully authenticated or not. The KerberosKeyManager class will call the isAuthenticated() method.
Now, let's see how the KerberosKeyManager class will process a user's request to extract the Kerberos session key from a Kerberos structure.
In the Java Card framework, any class that wants to process RMI requests must implement the java.rmi.Remote interface. This is an empty interface, and Java Card applications define their own Remote interface by extending java.rmi.Remote. I have extended the Remote interface in an interface named KeyManager, shown in Listing 6.
Listing 6. The KeyManager interface
public interface KeyManager extends Remote {
public static final short INVALID_DATA = (short)0x6002;
public static final short INVALID_PIN = (short)0x6003;
public static final short CORRUPTED_DATA = (short)0x6004;
public byte[] getKey(byte[] encKeyData)
throws RemoteException, UserException;
}
|
The KeyManager interface contains just one method, named getKey(). This method contains the business logic of the e-bank application. The KerberosKeyManager class will implement the KeyManager interface as shown in Listing 7.
As I mentioned earlier in Installing a Java Card application, the e-bank application's business logic uses RMI-based synchronous communications with client applications. That's why in Step 4 of the JavaCardKerberosKey constructor (Listing 4), I instantiated the KerberosKeyManager object, passed it to RMIService, and registered RMIService with the Dispatcher for the PROCESS_COMMAND phase.
As a result of the SELECT APDU exchange in the previous section, the e-bank application sent (or exported) a reference to the same KerberosKeyManager object to the KerberosEBank MIDlet. The MIDlet can now call the methods exposed by the KerberosKeyManager class. The KerberosKeyManager class uses the authentication services of the KerberosSecurityService class. The authentication check allows only authenticated clients to execute the methods of the KerberosKeyManager class remotely.
Listing 7. The KerberosKeyManager class
public class KerberosKeyManager
extends CardRemoteObject implements KeyManager
{
private EbankPIN ebankPIN;
private KerberosSecurityService securityService;
public KerberosKeyManager(
KerberosSecurityService srv, EbankPIN ebankPIN){
super();
securityService = srv;
this.ebankPIN = ebankPIN;
}//KerberosKeyManager
public byte[] getKey(byte[] encKerberosData) throws
RemoteException, UserException {
if(!securityService.isAuthenticated
(SecurityService.PRINCIPAL_CARDHOLDER)) {
UserException.throwIt(INVALID_PIN);
}
byte[] sessionKey = ebankPIN.getDecryptedSessionKey(encKerberosData);
if(sessionKey == null)
UserException.throwIt(INVALID_DATA);
return sessionKey;
}//public getKey()
}
|
Notice in Listing 7 that the KerberosKeyManager class extends a class named CardRemoteObject. The CardRemoteObject class is part of the Java Card framework and is included in the javacard.framework.service package. Recall from the previous section that you need to export a reference to the KerberosKeyManager object to the KerberosEBank MIDlet. The CardRemoteObject class contains the logic that handles all the issues related to the export of a Java Card object to the JCRE, which in turn manages the export to external clients like the KerberosEBank MIDlet.
Therefore, in order to develop a Java Card class whose reference I want to export to the JCRE, now I just need to do two more things:
- Extend the
CardRemoteObjectclass. - Call the
CardRemoteObjectconstructor in theKerberosKeyManagerconstructor (theCardRemoteObjectconstructor automatically exports a reference to theKerberosKeyManagerclass to the JCRE).
You can see in Listing 7 that I have done these two things in the KerberosKeyManager class. Note in this listing that KerberosKeyManager has just two methods: a constructor and a method named getKey(). I called the KerberosKeyManager constructor from the JavaCardKerberosKey constructor, while discussing the install() method in Listing 3. Now let's see how the constructor works.
The KerberosKeyManager constructor
The KerberosKeyManager constructor takes two parameters. The first (secService) is an instance of the KerberosSecurityService object, and the second is an EBankPIN instance. I have already explained how the KerberosSecurityService class works. The EBankPIN class wraps the two keys -- the user's and e-bank's. I'll demonstrate how the EBankPIN class works in the next article in this series. For now, just note that the KerberosKeyManager stores the two objects in class-level variables for future use.
Now let's see how the getKey() method works.
The getKey() method
The KerberosEBank MIDlet will call the getKey() method. The getKey() method shown in Listing 7 takes a byte array, which contains two pieces of information. The first structure is the user's key, which I will use for authentication. The second is a byte array that contains an encrypted structure, which in turn contains the Kerberos session key. If the user's key authenticates successfully, I will decrypt the encKerberosData array, extract the session key from the decrypted data, and return the session key to the calling client MIDlet application.
The getKey() method uses the KerberosSecurityService class to check user authentication. It calls the KerberosSecurityService.isAuthenticated() method to check user authentication. isAuthenticated() returns true if the user is successfully authenticated.
After doing the authentication check, the getKey() method proceeds with decrypting the encKerberosData array. In order to decrypt the array, the getKey() method uses the services of the EBankPIN class. Notice in Listing 7 that the getKey() method calls the EBankPIN.getDecryptedSessionKey() method, passing the encrypted structure along with the method call.
Recall that the EBankPIN class holds the user's and e-bank's keys. The getDecryptedSessionKey() method will decrypt the encrypted structure, extract the session key from the decrypted structure, and return the key to the calling application. I'll discuss the programming logic of EBankPIN class in the next article of this series.
I have included the UserPIN and EBankPIN classes in the source code download of this article. This is only to help readers compile the code that I have developed so far. I'll develop the actual code for these two classes in the next article of this series.
In this article, I thoroughly discussed the life cycle of a Java Card application. I used the Kerberos-based e-bank application as a sample to demonstrate the working of Java Card applets. I discussed how to install a Java Card application onto a Java Card, and also explained how a client application uses the services offered by a Java Card application. Finally, I provided the sequence of events that takes place when a client invokes a Java Card application.
I'll start the next article by demonstrating how the UserPIN and EBankPIN classes work. I will then introduce and explain SATSA and demonstrate how to use the SATSA classes. I will also implement the J2ME-based client-side functions of the KerberosEBank application to demonstrate how to use SATSA.
| Name | Size | Download method |
|---|---|---|
| wi-satsasource.zip | 17 KB | HTTP |
Information about download methods
Learn
- The official Java Card Platform Specification gives you set of enhancements to ease the alignment with smart card industry standards.
- The ISO 7816-4 specification gives you more information about the Application Protocol Data Unit (APDU) format from the IEC.
-
In the "Lock down J2ME applications with Kerberos" series, Faheem Khan builds a sample J2ME MIDlet that uses Kerberos to protect financial data:
- Part 1 (developerWorks, October 2003)
- Part 2 (developerWorks, November 2003)
- Part 3 (developerWorks, February 2004)
-
"Build smart J2ME mobile applications" (developerWorks, April 2005) provides a step-by-step guide for developing J2ME applications.
- Introduction to Smart Cards provides an introduction to this technology.
- Using WebSphere Studio Device Developer to Build Embedded Java Applications is a guide to develop Java-based mobile (embedded) applications for WebSphere Studio.
- IBM's secure smart card solutions are based on Java Card technology.
- Simplify enterprise Java authentication with single sign-on (developerWorks, September 2003) explains how to implement SSO on the Java platform.
Get products and technologies
- Download the Java Card development kit for the complete development environment for applets.
Faheem Khan is an independent software consultant specializing in enterprise application integration (EAI) and B2B solutions. Contact Faheem at fkhan872@yahoo.com.
