Chapter 5. Multiapplication Smart Cards

Since the early to mid-90s, much of the evolution of smart card technology has been in the direction of defining and adding on-card code later and later in the development and deployment phases of smart card applications. This “late binding” of application definition to smart card infrastructure has culminated in a variety of systems which allow application software to be loaded onto a card even after it is in the hands of a cardholder. In this chapter, we'll examine several of these multiapplication card systems. Each has a variety of advantages and detractions, and for the most part all are still being pushed in the marketplace of ideas.

In terms of deployment of cards in real-world systems, the Java Card technology would appear to be in a leading role. This is due in no small part to its acceptance as a Subscriber Identity Module (SIM) used in GSM cellular telephone systems. Overall, the number of multiapplication cards in use, relative to single-application smart cards, is still in the minority; however, the numbers are increasing at a rapid pace. Let's examine, then, some of the aspects of multiapplication smart cards.

Why Multiapplication Smart Cards

There are a number of reasons to want to add commands and applications to cards after they have been issued. For example:

  • Faster Transaction TimesIn reaching for general utility, the commands on off-the-shelf cards are necessarily low level and least common denominator. This means you can accomplish almost anything you like with them but it also means that, like grains of sand, you might need many of them to build your application. If transaction time is of the essence, which it usually is in building smart card applications—and recalling that communication between the terminal and the card is the most time-consuming—the application designer is led to building application-specific application protocol data units (APDUs) that accomplish in one go the combined effect of multiple general-purpose commands.

  • Application-Specific ProcessingDue to the domain in which they function, applications might have unique cryptographic algorithms or regional requirements for data privacy. By allowing for the construction of special-purpose APDUs and on-card applications, these programmable cards can be used in situations where their fixed-command, off-the-shelf brethren cannot.

  • Rapid Application DeploymentIncreasingly, smart cards have to compete with other trust-bearing application platforms such as PDAs, pagers, set-top boxes, cell phones, and personal multimedia players, not to mention the various programmable identity tokens that are in the R&D pipeline. Regardless of the level of security offered by the smart card, if the turnaround time to roll out a new application is years rather than days or weeks as it is with these competitors, the smart card will lose.

  • Chip IndependenceTechnologies that permit post-issuance loading of applications onto large card populations will have to solve the problem of running the application on different chip hardware. A side benefit of this will be that card issuers and their applications become independent of the underlying chip and, more importantly, its supplier.

In a sense, programmable smart cards are a return to the early days of smart cards when the entire card was application specific. The difference is that now, the application runs out of electrically erasable and programmable read-only memory (EEPROM), and the application can be deleted and replaced with another application anytime the card is used. The strategy of building an application's needs into the smart card's ROM-based operating system worked well when the number of cards needed for a particular application was large, when the application didn't do much, and was very stable over time—Carte Bancaire's Carte Blue, for example. As cards started to be used for smaller and more quickly evolving applications, however, the economic advantage of building the application's needs into ROM diminished. The turnaround time for a new version of the card was too long, the cost of development was too high, and the lifetime of the card was too short.

Another development that energized the quest for programmable cards was the empirically and painfully derived realization that smart card programs—whose business models had to stand on their own two feet and not be propped up by governmental mandates—had to offer more than one function. Because it was clearly impossible for all practicable functions to be ground into the card and activated on an as-needed basis, and because it was clear that the suite of functions of interest to one cardholder would differ from that of another, the notion of a multiapplication card—where applications could be loaded, used, and then deleted at the whim of the cardholder, the issuer, the application provider or, in all likelihood, all three—was quickly reached.

Finally, of course, application programmers and system architects, both those inside the established development organizations and those espousing new ideas and methods, needed smart cards for experimentation, testing and debugging, pilot projects, and special event business opportunities. Neither the skills demands, nor the tools requirements, nor the security protocols, nor the development cycle of assembly-language, ROM-based, single-application smart cards could begin to meet the new, emerging demands of the smart card marketplace. The stage was set for a new approach to on-card programming.

A Brief History of On-Card Interpreters and Virtual Machines

Adding executable code to cards after their manufacture was in and of itself not new. Card manufacturers used it from the day the first bug in ROM code was discovered to patch bugs or meet late-breaking customer requirements. The technique, familiar to all programmers as illustrated in Figure 5.1, was to plant some jump table–driven hooks at strategic places in the ROM code and to transfer out as needed to executable code in EEPROM to fix up a broken computation or to put an extra wrinkle on a stock ROM-based command. In fact, each of the card manufacturers semicommercialized this feature of their cards and would offer it to large, trusted customers as a way to differentiate their cards from their competitors.

Jump tables used to patch ROM code.

Figure 5.1. Jump tables used to patch ROM code.

While very useful in special situations, linking executable native code into the operating system clearly wouldn't work as a general on-card programming paradigm. It didn't solve the skill set problem—you still had to program in 8051 assembler—and because code linked in like this could theoretically read ROM and write EEPROM freely and undetected by the access protections of the operating system, there were a number of less than totally compelling security implications of this technique. What was needed was a way of running a program on the card in way that guaranteed that it didn't misbehave.

The use of source code interpreters as a way to execute programs on constrained computing resources achieved widespread popularity with the version of Beginner's All-purpose Symbolic Instruction Code (BASIC) created by Bill Gates and Paul Allen for the MITS Altair in 1975. The use of interpreters to ensure safe and controlled execution of programs can be traced to IBM's Series/1 data communications computer introduced in 1977. The issues addressed by the Series/1, whose entire operating system was interpreted, was making sure that one malfunctioning application program couldn't bring down an ultra-reliable computing platform used for 24×7 online transaction processing.

Thus, when the need to run application programs on a smart card under tight control began to arise, one approach, at least, had some historical standing. The available resources were, however, yet another order of magnitude more meager than those enjoyed by Messrs. Gates and Allen.

As often happens when an idea is in the air, work on smart card interpreters sprang up independently in more than one location. In 1990, at the RD2P (Research & Development on Portable Files) research laboratory in France (run jointly by Gemplus, Lille University, Pierre Paradinas, and others), the Card Virtual Machine (CAVIMA) was developed, which focused on the use of an on-card interpreter for data retrieval as part of a medical smart card application. This work led to Gemplus's CQL card and, subsequently, the ISO 7816-7 standard. Concurrently, Jelte van der Hoek and Jurjen Bos working at DigiCash in the Netherlands built the J-Code engine for use on the electronic purse smart card that was part of a toll-road project. The J-Code engine went on to become part of the famous DigiCash “Blue” mask, which can still be licensed today from DigiCash's phoenix, eCash Technologies.

The (apparently) first patent for an interpreter on a smart card was French patent FR 2 667 171 B1 issued to Edouard Gordons, Georges Grimonprez, and Pierre Paradinas on March 27, 1992. The title of the patent is “Support Portable A Microcircuit Facilement Programmable et Procede de Programmation de ce Microcircuit.”

The mid-1990s saw the creation of a number of smart card interpreters and on-card virtual machines. The SCIL interpreter by Eduard de Jong went on to become Integrity Art's Clasp interpreter for the TOSCA language. Tony Guilfoyle, one of the programmers of the GeldKarte, created ZeitControl's Basic interpreter. Keycorp introduced the OSSCA operating system that sported a Forth interpreter and Europay also flirted with a Forth card called the Open Card Architecture (OCA) built by Forth, Inc. Oberthur announced the HOST smart card operating system that included an on-card interpreter.

Portability of applications among cards with different chips was the primary driving force during this era. Ease of programming, including the use of standard high-level languages, was less of an issue. It was generally thought that there would be few applications, that they would be small, that they would have to be carefully written, and that as the cost of creating the application was such a small part of creating a new smart card, that efficiencies provided by software tools such as the use of high-level languages simply weren't worth the effort.

The Nat West (National Westminster) Development Team led by David Peacham and David Everett created the first e-purse, Mondex. In May 1995, NWDT set out to design a multiapplication smart card that was to contain a virtual machine with exactly these criteria in mind. Strict separation of applications and ITSEC Level 6 certification were the two design goals. NWDT started with the public domain Pascal virtual machine and byte codes in the book Programming Language Processors by David A. Watt. These byte codes were modified primarily by making them variable length to achieve higher density code at a slight expense of runtime efficiency. This card, completed in the summer of 1996, met both of its design desiderata and is now the Multos card.

Still in the mid-1990s, none of these interpreters or multiapplication cards garnered much more than tire-kicking attention from heavyweight issuers and scheme sponsors that were looking for a multiapplication, programmable smart card platform. It may have been the language, the organization behind the product, the experimental patina of the offerings, or simply that the time was not quite right.

This situation changed abruptly in late 1996 when Schlumberger announced the creation of the first Java Card smart card. Supporting a subset of the Java language subsequently labeled as Java Card and a subset of the Java byte codes executed by a 4-Kb on-card virtual machine built at Schlumberger's Austin product development center, Schlumberger's Java Card smart card was quickly embraced by the other major smart card manufacturers, Visa International and, eventually, the GSM mobile telephone community. While probably Java buzz, as much as technical prowess, fueled the success of Java Card, it did have the effect of changing the perception of programmable cards with on-card virtual machines from technical curiosity to commercial opportunity.

Java Card smart cards can, practically speaking, only be programmed in Java. In 1998, Microsoft introduced a smart card with a virtual machine called the Runtime Environment (RTE) that was programming language–independent. It was a Harvard architecture virtual machine that (for those with long memories) could easily have been mistaken for software Intel 8048. Microsoft initially provided a compiler for a subset of the Visual Basic (VB) language for the RTE.

In early 2000, Rowley and Associates broke—for once and for all—the connection between the on-card virtual machine and the source language used to create on-card applications by introducing a suite of software tools that enabled programs written in C, Java, Basic, or Modula-2 to be compiled for and run on both the Multos and Microsoft virtual machines. These tools have since been acquired by Aspects Software.

As is often the case with travels to unknown places, you don't know what's wrong with them until you get there. There are moats around the El Dorado that on-card interpreters sought: Actually installing and deleting lots of programs on the smart card generated large administration requirements and the running programs were pigs. As it usually the case, bridges can be built over moats; both of these shortcomings of installed interpreted applications are being addressed.

In 1998, engineers in a Swedish company, then called Across Wireless, came up with an elegant solution to the administrative costs problem: Don't install the programs on the card. Download the byte-coded program when you need to run it, run the program, and then throw the byte codes away. Because this is just exactly what your World Wide Web browser does when it downloads a page from the Internet, the interpreter that ran these Just-In-Time (JIT) byte codes came to be known as a “mini-browser.” However, you aren't in fact browsing in the Web sense at all. Not only is the cost of managing fire-and-forget byte codes much less than managing byte codes that are installed on the card, but issuers can also offer a much broader universe of on-card applications because they don't have to just go with the most generic—and thus least personal—applications. Of course, just as with real Web browsers, the security infrastructure involved in identifying loadable code that is “safe” is highly problematic.

Interpreted programs on an 8-bit smart card run at about 2 Dhrystones per second. The 8-bit processor itself runs at about 80 Dhrystones per second. Now the integer Dhrystone benchmark is arguably not representative of the compute profile of a typical interpreted program, but there can be no question that a stiff performance penalty is being paid every time an interpreted program is run. Originally, this was the price of the runtime checks that ensured the program didn't misbehave. As performance became an issue, however, these checks were moved from runtime to preloading program verification so that very few runtime checks were left in the on-card interpreter. All that's left (if this is done) is pure interpretation overhead. Because it is (to the first order of approximation) as easy to verify microprocessor assembly language as it is to verify arbitrary byte codes, more and more attention is being paid to downloading native code applications. Of course, as we pointed out above, this still doesn't address the “skill set” problem; curiouser and curiouser.

But today, the on-card interpreter—whether for functional languages like Basic, Java, or JIT languages like XML—is the mainstream for building on-card applications. This chapter is about building applications for these multiapplication cards.

Application Selection and AIDs

On-card application programming for a specific application is essentially nothing more than a matter of defining custom APDUs and implementing them on the card. The off-card application is aware of these custom APDUs and uses them to access the on-card functionality of the application. The off-card application sends an APDU (Table 5.1) to the on-card application:

Table 5.1. APDU Command Structure

CLA

INS

P1

P2

Data Field

and the on-card application returns a response (Table 5.2) to the off-card application:

Table 5.2. APDU Command Response Structure

Response Data

SW1

SW2

just like all the other APDUs we've discussed in previous chapters.

The on-card and off-card application programs can imbue the custom APDUs with whatever semantics they wish, but the basic APDU message format of ISO 7816-4 and master-slave between the host and the card must be maintained because these characteristics of the communication channel are ground into the physical and data-link layers of the T=0 and T=1 smart card protocol stacks.

The problem presented to off-card smart card programs by on-card programming is determining if the card that it has just shocked to life with a reset signal contains an application it can talk to and, if so, how it is to be activated so that the preceding APDU conversation can begin. This is called the application selection problem and it has been around for a surprisingly long time in smart cards.

There are some primitive but effective application selection methods built into ISO 7816-4 that go back to 1994 that we discuss later in this chapter. A patent for application selection was issued to Georges Grimonprez and Pierre Paradinas of Gemplus on October 11, 1995. The title of the patent is “Secured Method for Loading a Plurality of Applications into Microprocessor Memory Card.”

In early 1997, the United States made a proposal to the International Standards Organization (ISO) to expand the methods in ISO 7816-4. The proposal was titled “Card Structure and Enhanced Functions for Multi-application Use.” It would have become ISO 7816-11 had it been pursued, but it wasn't. The proposal (in a slightly modified form) did go on to become U.S. patent 5802519 issued on September 1, 1998, to Eduard De Jong and titled “Coherent Data Structure with Multiple Interaction Contexts for a Smart Card.”

With the commercial acceptance of multiapplication smart cards in the late 1990s and the perception that money (perhaps the “real money”) was to be made in managing the applications on card populations and not just in writing and licensing them, a number of start-ups and old-line transaction processing companies proposed proprietary application management schemes, and a number of patents for application management were applied for and issued. Principal among the latter was U.S. patent 6005942 titled “System and Method for a Multi-application Smart Card Which Can Facilitate a Post-Issuance Download of an Application onto the Smart Card” issued on December 21, 1999, to Alfred Chan, Marc Kekicheff, Joel Weise, and David Wentker, and assigned to Visa International Service Association.

The smart card application selection problem has three subproblems: naming card applications (knowing what you are looking for), finding applications on the card (knowing where to look), and activating on-card applications (knowing what to do when you find it).

Note in passing that the “microbrowser” approach to applications finesses all of these problems, if one assumes that there is to be no inter-leaving of applications on the card (a good assumption with current systems, but not necessarily for the future). The terminal doesn't have to wonder if the card can perform its application because it gives the card the application it wants performed at the time it needs it to be performed.

Application Identifiers

The application naming subproblem has a widely agreed upon solution. ISO 7816-5 establishes a standard—a universal name space for smart card applications creatively called Application Identifiers (AIDs). An AID has two parts. The first is a Registered Application Provider Identifier (RID) of 5 bytes that is unique to the application provider. Acme Smart Card Software, for example, might have an AID of 0xA0 0x00 0x00 0x00 0x88.

The second part of an AID is a variable-length field of up to 11 bytes called the Proprietary Application Identifier Extension (PIX) that an application developer uses to identify specific applications. It is up to the individual application developer to manage the PIX name space and, thus, to make sure that the RID plus the PIX uniquely identifies one and only one application. Acme could decide to use a 3-byte PIX where the first byte was the product identifier, the second byte was the major version, and the third byte was the minor version number. 0xA0 0x00 0x00 0x00 0x88 0x05 0x01 0x02 would be Version 1.2 of Acme's application number 5.

Every smart card application developer should get an RID to identify his or her applications. RIDs are assigned by the Copenhagen Telephone Company, KTAS, which is also the ISO 7816-5 Registration Authority. KTAS's address is Teglholmsgade 1, DK-1790, Copenhagen, V, Denmark, but the application has to be approved by your national ISO body. RIDs cost about 500 Euros. For those in the U.S., the American National Standards Institute, or ANSI (www.ansi.org/), will handle requests for both national and international numbers. Forms for applying for an RID can be found in ISO 7816-5 and at www.scdk.com. If you want to issue a single-application smart card, then you need an Issuer Identification Number (IIN) that is specified in ISO 7812. For U.S. residents, forms for an IIN are also available through ANSI. The cost of an IIN is $600.

ISO-7816 Application Selection

ISO 7816-4 and -5 define three methods of application identification and selection-based AIDs called implicit, direct, and DIR file.

Implicit application means that the card runs an application automatically when it is reset and includes the AID of the application in the historical bytes of the ATR or in the ATR file, 0x2F01. Initially, this was used for single-application cards where the AID in the ATR identified the application hard-wired to the card. More recently, on multiapplication cards, implicit application selection is used to launch an on-card shell program that can, in turn, run other applications. The Multos card discussed later in this chapter includes such a shell program capability.

Direct application selection uses the SELECT FILE command wherein the data field contains an AID rather than a dedicated file name. Application selection in this case is not so much a matter of launching an application program on the card as it is setting the current directory using an AID rather than a path name. After direct application selection, normal 7816-like APDU commands would be used to perform application operations on the files in the selected directory and its subdirectories. Direct application selection is typical for applications on multiapplication cards that store data but not executable code on the card.

The most elaborate application selection mechanism defined by ISO-7816 is selection by means of the DIR file. The DIR file is the file with identifier 0x2F00 in the root directory. Each constructed TLV object in the DIR file describes one application on the card. The application description must include the AID of the application and, optionally, may include the path to the directory containing the files relevant to the application and a sequence of commands that are to be executed to initiate the application. This is essentially a general-purpose shell file or BAT file capability for smart cards but the authors have never seen it used as such.

Other Application Selection Schemes

In addition to the three alternatives offered by ISO-7816, a number of smart card consortia and major issuers have come up with their own methods for doing application selection. EMV2000, for example, defines a very elaborate scheme. Visa Open Platform, the Open Card Framework, the European Telecommunications Standards Institute and the Java Card Forum, Europay and the Small Terminal Interoperability Platform consortium among others have also weighed in with their own homegrown approaches. There are also patents held by Fujitsu, Microsoft, Gemplus, Visa, Citibank, and American Express covering application selection on a smart card. Finally, each of the multiapplication cards comes with its own application selection and activation method that we will cover when we discuss the cards themselves. Most of these application selection methods are based on AIDs and all are—in the finest tradition of the smart card industry—wholly incompatible with each other.

Application selection is intimately connected on one hand to the way applications are loaded, unloaded, and generally managed on card populations and, on the other hand, to the way applications on a particular card share data and activate one another. Indeed, some of the application selection methods referred to previously are created in the midst of proposing solutions to one or the other or both of these allied problems. As a result, application selection will probably nnot stabilize on its own but will have to wait for consensus resolution of these other problems.

The SCADA Card

In this section, we will describe the on-card components of a hypothetical smart card application. After describing the application in generic terms, we will implement the application on each of four programmable, multiapplication smart cards. By considering the same application across all cards, the reader will more easily be able to compare the cards and decide which one is best for his or her own application.

There are two on-card application programs in our example: One is used when the card is in action and the other is used for card administration. The application itself is not one of the long-in-the-tooth smart card applications such as electronic cash, loyalty, stored value, or workstation logon. Rather, it is the application of a smart card to industrial control, also known by the acronym SCADA (System Control And Data Acquisition).

Imagine a smart card that is inserted into an electromechanical system of some sort. The system could, for example, be an automobile, a food processing plant, or a utility meter. While the card is inserted, it gathers performance data from the system and provides control commands back to the system. From time to time, the card is collected and brought back to an administration station where the data it has collected is retrieved and the algorithms it uses to provide control commands to the system are updated.

Imagine also that the control algorithms are like secret formulae. This is why we want to store them and the data we are gathering in a tamper-resistant capsule when they are out on the factory floor or in the field doing their work. For the automobile manufacturer, they control fuel consumption and emissions; for the food manufacturer, they control the taste and consistency of the product; and for the utility meter, they balance power consumption among the devices governed by the meter. For all three, the control algorithms are part of the card issuer's competitive edge. The process control card is a good example of a smart card that is a candidate for on-card programming.

Our hypothetical process control smart card has two applications: the online application and the administrative application. The online application is what is running while the card is inserted into the electromechanical system. The administrative application is what is used back at the office to collect the data and to update the algorithms.

SCADA Card APDUs

Each on-card application handles two APDUs. The online application has one APDU to accept performance data from the system and one APDU to provide control commands back to the system. The administrative application has one APDU to retrieve the performance data from the card and one APDU to update the control algorithms. Table 5.3 gives the particulars of each of these APDUs.

Table 5.3. APDUs of the Applications on the SCADA Card

APDU

CLA

INS

P1

P2

Data Field

Response

Online Application

      
  • Store Data

C0

10

Point

Flags

Point reading

 
  • Command

C0

20

Point

Flags

Point reading

Control command

Admin Application

      
  • Get Card ID

C0

10

   

Card identification

  • Get Data

C0

20

Point

Rec #

 

Stored data

  • Update Algorithm

C0

30

Point

Flags

Algorithm parameters

 

The details of how the performance data are accumulated and how the control algorithms are represented inside the card can be expected to vary widely from system to system.

For the sake of being explicit for our discussion on the various programmable cards, we will assume that the card keeps a running total of the data and the data squared for each control point and that each control algorithm is simply a table of control value intervals with each interval being associated with an output control command. Thus, associated with each control point, k, are two files. The file with file identifier 1000+k holds the accumulating data for control point k and the file with file identifier 2000+k holds the control table for control point k.

The data accumulation file begins with one byte that counts the number of records in the file. This count is followed by a series of 10-byte records, each having the following structure:

struct {
   WORD  n;  /* number of readings accumulated */
   DWORD v;  /* sum of all accumulated readings */
   DWORD v2; /* sum of squares of all accumulated readings */
} record;

Each record accumulates a batch of readings and the card can hold a number of batch accumulations.

The control table file similarly begins with 1 byte that counts the number of rows in the table. This count is followed by a series of 12-byte records, each having the following structure:

struct {
   WORD lb;   /* lower bound of reading */
   WORD ub;   /* upper bound of reading */
   BYTE c[8]; /* control command for readings in interval */
} row;

The interpretation of a row is that if the reading provided by the system in its request for a control command for a control point is greater than the lower bound and less than or equal to the upper bound, then the associated command is returned to the system. The meaning of the command is, of course, purely dependent on the system.

The SCADA Card Online Application

Here is a C sketch of the generic version of the online application:

Code for the Online Application

main()
{
   BYTE recs, rows;
   BYTE record[10], row[12];
   short d, n, lb, ub;
   int i, v, v2;

   if(CLA != 0xC0)
          return CLA_ERROR;

   d = MAKEWORD(APDUdata[0], APDUdata[1]);

   switch(INS) {

   /* Accumulate Data */
   case 0x10:
          SelectFile((WORD)(1000 + P1));
          ReadBinary(0, &recs, 0, 1);
          if((recs == 0) || (P2 && NEW_RECORD)) {
                  recs++;
                  WriteBinary(0, &recs, 0, 1);
          }
          recs--;
          ReadBinary((BYTE)(recs*8+1), record, 0, 10);
          n  = MAKEWORD(record[0], record[1]);
          v  = MAKEDWORD(MAKEWORD(record[2], record[3]),
                MAKEWORD(record[4], record[5]));
          v2 = MAKEDWORD(MAKEWORD(record[6], record[7]),
                MAKEWORD(record[8], record[9]));
           n++;
           v += d;
           v2 += d*d;
           memset(record, 0, sizeof(record));
           memcpy(&record[0], &n, 2);
           memcpy(&record[2], &v, 4);
           memcpy(&record[6], &v2, 4);
           WriteBinary((BYTE)(recs*8+1), record, 0, (BYTE)10);
           break;

    /* Provide Control Command */
    case 0x20:
           SelectFile((WORD)(2000 + P1));
           ReadBinary(0, &rows, 0, 1);
           for(i = 0; i < rows; i++) {
                    ReadBinary((BYTE)(i*12+1), row, 0, 12);
                    lb = MAKEWORD(row[0], row[1]);
               ub = MAKEWORD(row[2], row[3]);
               if(d> lb && d <= ub) {
                      SetResponse(row, 4, 8);
                      return SUCCESS;
               }
           }
           return TAB_ERROR;

    default:
           return INS_ERROR;
    }

    return SUCCESS;
}

The SCADA Card Administration Application

The administration application is simpler than the online application. We will assume that if the control table is to be updated during an administrative session, then it will be completely rewritten.

Here is a C sketch of the generic version of the administrative application:

Code for the Administrative Application

main()
{
   BYTE recs, rows;
   BYTE record[10];

   if(CLA != 0xC0)
          return CLA_ERROR;

   switch(INS) {

   /* Return Card Identifier */
   case 0x10:
          SelectFile((WORD)0x0002);
          ReadBinary(0, record, 0, 10);
          SetResponse(record, 0, 10);
           break;

    /* Return Stored Data Record */
    case 0x20:
           SelectFile((WORD)(1000 + P1));
           ReadBinary(0, &recs, 0, 1);
           if(recs < P2)
                   return REC_ERROR;
           ReadBinary((BYTE)((P2-1)*8+1), record, 0, 10);
           SetResponse(record, 0, 10);
           break;

    /* Update Control Table */
    case 0x30:
           SelectFile((WORD)(2000 + P1));
           ReadBinary(0, &rows, 0, 1);
           if(P2 && TAB_RESET) {
                   rows = 0;
                   WriteBinary(0, &rows, 0, 1);
           }
           WriteBinary((BYTE)(rows*12+1), APDUdata, 0, 12);
           rows++;
           WriteBinary(0, &rows, 0, 2);
           break;

    default:
           return INS_ERROR;
    }

    return SUCCESS;
}

Some of the API functions we used to access the card from the off-card application, such as SelectFile, ReadBinary, and WriteBinary, also show up in the on-card application. This makes sense because all we have really done is move functionality from the off-card application to the on-card application and, in effect, eliminated the communication overhead. The basic services provided by the card operating system are the same whether you are accessing them locally or remotely.

The Multos Card

The Multos card is the most mature and arguably the most secure, programmable multiapplication card on the market today. Multos card applications were originally conceived of as being written in byte code assembly language. This language, called the Multos Executable Language (MEL), is based on Pascal P-codes and the virtual machine described in David A. Watt's book Programming Language Processors. These byte codes underwent some modification to increase their density and the result was the MEL assembly language. While it was not a design constraint at the time, these modifications did not destroy the possibility of compiling high-level languages to the byte codes and today, MEL byte code compilers exist for both C and Java.

The Multos Virtual Machine

The core Multos virtual machine consists of the 31-byte code instructions given in Table 5.4.

Table 5.4. Byte Codes of the Multos Virtual Machine

Mnemonic

Description

ADDB

Add literal to byte

ADDN

Add n-byte blocks

ADDW

Add literal to word

ANDN

Bitwise AND of n-byte blocks

BRANCH

Branch to relative address

CALL

Call a function

CLEARN

Zeroize n-byte block

CMPB

Compare literal to byte

CMPN

Compare n-byte blocks

CMPW

Compare literal to word

DECN

Decrement n-byte block

INCN

Increment n-byte block

INDEX

Index an array

JUMP

Jump to code address

LOAD

Load data to stack

LOADA

Load address

LOADI

Load indirect

NOTN

Bitwise NOT of n-byte blocks

ORN

Bitwise OR of n-byte blocks

PRIMRET

Call primitive or return

SETB

Set byte to literal

SETW

Set word to literal

STACK

Push or pop the stack

STORE

Store data from the stack

SOTREI

Store indirect

SUBB

Subtract literal from byte

SUBN

Subtract n-byte blocks

SUBW

Subtract literal from word

SYSTEM

Various system functions

TESTN

Test n-byte block against 0

XORN

Bitwise XOR of n-byte blocks

Every implementation of the Multos card must support these byte codes and a mandatory set of operating system services that include bit manipulation, division, multiplication, and low-level memory operations. The mandatory set of operating services can be extended with services that support advanced services such as cryptographic algorithms and modular arithmetic. Implementers of the Multos card are not free to add their own extensions, so if an optional service is present on a Multos card, it is the same as that service on all other Multos cards regardless of card manufacturer.

Besides the byte codes in Table 5.4, every Multos card supports 24 operating system service calls called primitives. These include various byte array copy and compare operations, bit manipulation operations, integer multiply and divide, and card-oriented operations such as set ATR that ask the host for more time.

An advantage of a modest byte code and primitive operation set with a simple execution context is that it is feasible to write assembly language subroutines that can be called by high-level language applications and even to write inline byte codes in high-level language programs. This is a unique feature of the Multos card. We will see some examples of this later in this chapter.

There are a number of assemblers available for MEL. For small, time-critical, relatively stable applications, one of these may be the appropriate software development tool to use. For the purpose of comparing programming of a Multos card to programming of other cards, we will confine our attention to Multos's standard high-level programming language, C. There are also compilers of Java, Basic, and Modula-2 for the Multos virtual machine. Compilers for all these languages on the Multos card are provided by Rowley Associates Limited and Aspects Software in the U.K.

The Multos Programming Model

Multos does not support a file system for an application's nonvolatile data but rather simply provides a static block of EEPROM memory to the application that the application can structure how it pleases. This static data segment is protected against access by all other applications. An application in execution can also access two volatile data segments. The dynamic data segment is private to the application and contains the stack and other session data. The public data segment contains the communication buffers that handle traffic to and from the terminal and a common global area used to pass data between applications.

Virtually no structure is imposed on an application by the Multos programming model. In the spirit of Unix, an application consists of a main function that can define and call other functions as well as functions provided by the operating system.

Once a Multos application has been activated, each arriving APDU causes the main function to be called. The four header fields of the APDU (CLA, INS, P1, and P2) are preloaded into global variables by the Multos operating system. Subsequent calling of the CheckCase system service within the application causes the APDU's data field to be loaded into the application's public data segment and the Lc and Le global variables to be set. The argument to CheckCase is the ISO 7816-4 case of the APDU that the application expects, and CheckCase returns a Boolean flag indicating whether or not the APDU received from the host matches the application's expectations. For Case 2 and 4 APDUs for which the card returns data in addition to the status word to the host, the application places the data to be returned in the public data segment before exiting with a status code.

The C library for Multos applications includes many of the standard library functions known and loved by C programmers everywhere, including the ctype functions, the heap management functions, the string functions, setjmp/longjmp, and even good old printf. There is also a good collection of both high- and low-level cryptographic functions.

A unique feature of the Multos programming model is the ability to include inline byte codes and to write byte-coded subroutines. The ability to mix assembly code in with high-level language statements is standard fare in the world of microcontroller programming and is entirely missing in the other programmable cards. Notice that there is no downside security implication of this feature because execution is still controlled by the Multos virtual machine.

Some of the library functions are implemented using inline code. For example, the library function COPYN, which copies n bytes from a source pointer to a destination pointer is defined by:

#define COPYN(N, DEST, SRC)
do {
   __ push(__typechk(unsigned char *, DEST)); 
   __ push(__typechk(unsigned char *, SRC)); 
   __code(PRIM, 0x0e, N);
} while(0);

where 0x0e is the opcode of the Multos operating system primitive to copy n bytes from one location to another.

The SCADA Application on Multos

Here is the online SCADA application rendered for the Multos card using the Rowley C compiler.

Code for SCADA Application on Multos Card

#include <string.h>
#include <multoscomms.h>

#define BYTE unsigned char

#define CONTROL_POINTS 10
#define DATA_RECORDS 10

#define SUCCESS 0x9000
#define CLA_ERROR 0x6999
#define CSE_ERROR 0x6999
#define TAB_ERROR 0x6999
#define INS_ERROR 0x6999

#define NEW_RECORD 0x01

#define CONTROL_INTERVALS 10

#pragma melpublic

union
{
  BYTE as_bytes[8];
  int as_int[4];
} apdu_data;

#pragma melstatic

typedef struct
{
  short m_n;
  long m_v;
  long m_v2;
} record_t;

typedef struct
{
  short m_lb;
  short m_ub;
  BYTE m_data[8];
} row_t;

static BYTE records[CONTROL_POINTS];
static record_t record[CONTROL_POINTS][DATA_RECORDS];
static BYTE rows[CONTROL_POINTS];
static row_t row[CONTROL_POINTS][CONTROL_INTERVALS];

void main(int argc, char *argv[], char *envp[])
{
 BYTE r, i;
 short d;
 row_t *rowp;
 record_t *recp;

 if(CLA != 0xC0)
  ExitSW(CSE_ERROR);

 switch(INS) {

 /* Accumulate Data */
 case 0x10:

  if(!CheckCase(2))
   ExitSW(CLA_ERROR);

  d = apdu_data.as_int[0];
  r = records[P1];
  if ((r == 0) || (P2 && NEW_RECORD))
    records[P1] = ++r;
  r--;

  recp = record[P1] + r;
  recp->m_n++;
  recp->m_v += d;
  recp->m_v2 += d*d;
  break;

 /* Provide Control Command */
 case 0x20:
  r = rows[P1];
  for (rowp = row[P1]; rowp < row[P1]+r; ++rowp)
    if (d > rowp->m_lb && d <= rowp->m_ub) {
      memcpy(apdu_data.as_bytes, rowp->m_data, 8);
      ExitLa(8);
  }
  ExitSW(TAB_ERROR);

 default:
  ExitSW(INS_ERROR);
 }

 ExitSW(SUCCESS);
}

The Multos C version of the SCADA online application compiles to 459 MEL byte codes using Version 1.0 of the Rowley C compiler.

The three Multos data segments are identified in the C code through the use of the pragma statements, #pragma melstatic, #pragma melpublic, and #pragma melsession. In the preceding program, the array apdu_data is the incoming and outgoing communication buffer and is placed at the beginning of the public data segment. The data accumulation records and the control tables are nonvolatile data and, therefore, like the code itself, are placed in the static data segment.

Pointers and bit shifting operations are very handy to have when building resource-constrained applications such as those for a smart card. The fact that the Multos card has received the E6 High ITSEC security certification—the highest certification possible—which included the separation of applications, says that there is no connection between the use of a programming language with pointers and card security.

The Multos Application Development Cycle

Any text editor or program development environment can be used to create the Multos C source code. The code is compiled to a MEL byte code file by the Rowley DOS command-line compiler. This file can be loaded into a byte code simulator for single-step debugging or downloaded to the application directory on the card. Once on the card, the application can be selected using its AID or its name (as determined by the name of the first file in the C compilation). After the selection APDU, all subsequent APDUs are routed to the main entry point of the application for processing.

Multos has perhaps the most elaborate security scheme of all the programmable cards for loading and deleting applications. This is because the Multos scheme serves security and business purposes, with the business purposes keeping track of each load and unload operation in a nonreputable way. Fortunately, all of this machinery can be turned off during application development so that very quick edit/test/debug cycles are possible.

The Java Card

The first Java Card virtual machine was created in the spring of 1996 at Schlumberger's Austin product development center. The Schlumberger Java Card team worked top down, first prioritizing Java features versus their utility in the current smart card arena, and then discarding less useful features of Java until the Java Card virtual machine fit in 4 Kb of 6805 code.

The first implementation of the Java Card virtual machine implemented 74 Java byte codes (www.slb.com/et/). It ran on the SC49 chip, which has 11.2 Kb of ROM, 4 Kb of EEPROM, and 512 bytes of RAM (www.mot.com). The interpreter and its runtime support took all of the ROM and 1 Kb of the EEPROM, leaving 3 Kb for user programs and data. The runtime library for the card supported on-card file system operations, identity and security features such as PIN handling and file access control, and T=0 host communication functions.

This work received a U.S. patent, “US6308317: Using a High Level Programming Language with a Microcontroller” on October 23, 2001.

Following its initial development, Schlumberger transferred the specification of Java Card 1.0 to Sun Microsystems and, in the same time frame, established with Gemplus and other members of the “smart card community” the Java Card Forum. The Java Card Forum offers a venue for Java Card licensees to review, discuss, and offer suggestions to Sun Microsystems for the evolution of the Java Card specifications. As of this writing, the latest released version is Java Card 2.2 with Java Card 3.0 requirements assessment well underway.

Almost all of the Java Card smart cards on the market consist of an interpreter for the Java Card subset of Java byte codes running on top of a single-application smart card operating system. Some of the cards hide this fact and present a pure Java programming model exactly as described in the Java Card specification. Other cards, principally the Schlumberger Cyberflex Access™ series of cards, let the capabilities of the underlying operating system come through to the programming interface presented to the application.

Because the unadulterated Java Card API provides only a modest set of services outside cryptography, this latter approach holds some benefits for the application developer who is concerned with getting the application built. There is an ongoing tension between programming (application) efficiency and maintaining the integrity (purity) of the Java language, although this is not too unlike similar tensions that we've always seen between language and operating system implementations.

The Java Card Virtual Machine

As of Java Card Version 2.1.2 of May 2001, the 108 Java card byte codes were as shown in Table 5.5.

Table 5.5. Java Card 2.1.2 Byte Codes

Mnemonic

Description

aaload

Load from array reference

aastore

Store to array reference

aconst_null

Push a null

aload

Load a local variable

aload_<n>

Load reference from local variable

anewarray

Create a new array

areturn

Return from a method

arraylength

Get length of array

astore

Store into local variable

astore_<n>

Store to local variable

athrow

Throw an exception

baload

Load byte or Boolean from array

bastore

Store into byte or Boolean array

bipush

Push a byte

bspush

Push a short

checkcast

Check type of an object

dup

Duplicate top of stack

dup_x

Duplicate top of stack and insert below

dup_2

Duplicate top two operands on stack

getfield_<t>

Fetch field from object

getfield_<t>_this

Fetch field from current object

getfield_<t>_w

Fetch field from object using wide index

getstatic_<t>

Get static field from class

goto

Branch always

goto_w

Branch always with wide index

i2b

Convert integer to byte

i2s

Convert integer to short

iadd

Add integer

iaload

Load integer from array

iand

Boolean AND integer

iastore

Store into integer array

icmp

Compare integers

iconst_<i>

Push constant integer onto stack

idiv

Divide integers

if_acmp<cond>

Branch if comparison succeeds

if_acmp<cond>_w

Branch if comparison succeeds (wide index)

if_scmp<cond>

Branch if short comparison succeeds

if_scmp<cond>_w

Branch if short comparison succeeds (wide index)

if<cond>

Branch if short comparison with zero succeeds

if<cond>_w

Branch if short comparison with zero succeeds (wide index)

ifnonnull

Branch if reference is not null

ifnonnull_W

Branch if reference is not null (wide index)

ifnull

Branch if reference is null

ifnull_w

Branch if reference is null (wide index)

iinc

Increment local integer variable by a constant

iinc_w

Increment local integer variable by a constant (wide index)

iipush

Push integer

iload

Load integer from local variable

iload_<n>

Load integer from local variable

ilookupswitch

Access jump table by key match and jump

imul

Multiply integers

ineg

Negate an integer

instanceof

Determine if object is of a given type

invokeinterface

Invoke interface method

invokespecial

Invoke instance method with special handling

invokestatic

Invoke a class method

invokevirtual

Invoke instance method based on class

ior

Boolean OR of integers

irem

Remainder of integer division

ireturn

Return integer from a method

ishl

Shift integer left

ishr

Shift integer right

istore

Store integer into local variable

istore_<n>

Store integer into local variable

isub

Subtract integers

itableswitch

Access table by integer index and jump

iushr

Logical shift right of an integer

ixor

Boolean XOR of integers

jsr

Jump to a subroutine

new

Create a new object

newarray

Create a new array

nop

Do nothing

pop

Pop top operand on stack

pop2

Pop top two operands on stack

putfield_<t>

Set value of field in an object

putfield_<t>_this

Set value of field in current object

putfield_<t>_w

Set value of field in object (wide index)

putstatic_<t>

Set value of field in static class

ret

Return from subroutine

return

Return void from method

s2b

Convert short to byte

s2i

Convert short to integer

sadd

Add shorts

saload

Load short from array

sand

Boolean AND of shorts

sastore

Store short into an array

sconst_<s>

Push short constant

sdiv

Divide shorts

sinc

Increment short by constant

sinc_w

Increment short by constant (wide index)

sipush

Push short

sload

Load short from local variable

sload_<n>

Load short from local variable

slookupswitch

Access jump table by short key match and jump

smul

Multiply shorts

sneg

Negate short

sor

Boolean OR of shorts

srem

Remainder of short division

sreturn

Return short from method

sshl

Shift left of short

sshr

Shift right of short

sspush

Push a short

sstore

Store short into local variable

sstore_<n>

Store short into local variable

ssub

Subtract shorts

stableswitch

Access jump table by short index and jump

sushr

Local shift right of short

swap_x

Swap top two operand stack words

sxor

Boolean XOR of shorts

Due to the complex state of the Java Card virtual machine, it is virtually impossible to write assembly language subroutines using Java Card byte codes, let alone inline Java Card byte codes in Java Card application programs. It is also forbidden by the Java Card specification.

The Java Card Programming Model

The Java Card smart card has the most complex application programming model of the commercially available programmable smart cards. This is because Java Card removes the notion of an underlying operating system and uses the Java Card programming language to serve the dual—and, at times, contradictory—roles of computational process description and runtime context administration. The result is that a Java Card program is a mixture of application logic and job control logic.

A Java Card application provides four routines that allow it and its data to be controlled by the Java Card framework. Three of these routines—install, select, and deselect—concern only job control logic, including memory management and data sharing. The fourth—process—is called each time an APDU arrives for the application and is analogous to the main entry point of a Multos card application.

A Java Card application's install entry point is called once by the Java Card framework when the application is loaded onto the card. The install routine allocates all the nonvolatile data space that the application might ever need. Data space can be allocated as needed by the process routine, but this approach is not recommended by the Java Card specification because if the space should turn out to be unavailable, the application aborts. The install routine must also call the framework's register routine to make the framework aware of the application's AID. Even though it is only used once, the install routine code stays on the card and the space it occupies is lost.

Because Java Card's language features are used to provide what would normally be operating system services, a Java Card application's data and code are closely bound together. On the one hand, this makes it difficult to update the application's code to a new version without disturbing the data associated with the application. Conversely, it minimizes discrepancies between data definitions and data processing code, which can occur when the two are allowed to evolve independently. On specialized Java Cards that support file operations, files can be used to hold the data associated with an application, thus providing a more “classic” smart card software architecture. On more orthodox Java Cards, you can create a data repository application that just holds the application's data and shares read and write methods with the application itself. Essentially, each application has to provide its own file system code. There has been some successful prototyping of a relational database data store on a Java Card smart card that allows various applications to access information in a common data store. As the memory available on smart card chips increases, this approach may see increasing merit.

The Java Card 2.1.2 API consists of 119 entry points that include APDU reception and transmission services, volatile memory management, array manipulation services, transaction services, a large number of cryptographic services, and runtime exceptions. Like the Multos card, the Java card specification does not support a file system of any sort. However, rather than simply making a block of memory available that can be used in a manner that is natural for the application, Java card binds nonvolatile memory management, including the data security constructs to the Java programming language. Thus, nonvolatile data objects are created within the language and controlled by the Java card runtime environment. Once created, they cannot be freed nor, because of the strict typing of the Java language, can the EEPROM space they occupy be used for other purposes by the application. Upcoming releases of the Java card specification will support the reclamation of unused data space (garbage collection) but it will be a while before these cards are in the field.

The SCADA Application on a Java Card

Code for Online SCADA Application for Java Card

/*
** online.java - On-Line Application for the SCADA Card
*/
import java.lang.reflect.Array;
import javacard.framework.*;
import javacardx.framework.*;
import javacardx.crypto.*;

public class online extends javacard.framework.Applet {

    /*  SCADA card on-Line application parameters and sizing values */
    final static byte SCADA_CLA = (byte)0xC0;

    final static byte DATA_ACQUISITION_INS = (byte)0x10;
    final static byte SYSTEM_CONTROL_INS   = (byte)0x20;

    final static byte NEW_RECORD = (byte)0x01;

    final static byte POINTS  = 4;
    final static byte RECORDS = 8;
    final static byte ROWS    = 8;

    /* The input/output buffer */
    byte apdu_data[];

    /* The data acquisition records and system control tables */
    static byte records[];
    static byte record[];
    static byte rows[];
    static byte row[];

    private online() {

           records = new byte[POINTS];
           record  = new byte[POINTS*RECORDS*10];
           rows    = new byte[POINTS];
           row     = new byte[POINTS*ROWS*12];

           register();
}

/* Called when the applet is instantiated. */
public static void install(APDU apdu) {
        new online();
}

/*  Called when the applet is selected. */
public boolean select() {
        return true;
}

/* Called when an APDU is received. */
public void process(APDU apdu) throws ISOException {
       short d;
       byte p;

       apdu.setIncomingAndReceive();

       apdu_data = apdu.getBuffer();

       if ((apdu_data[ISO.OFFSET_CLA] == ISO.CLA_ISO) &&
                (apdu_data[ISO.OFFSET_INS] == ISO.INS_SELECT)){
                ISOException.throwIt(ISO.SW_NO_ERROR);
       }

       if (apdu_data[ISO.OFFSET_CLA] != SCADA_CLA)
                       ISOException.throwIt(ISO.SW_CLA_NOT_SUPPORTED);

       p = apdu_data[ISO.OFFSET_P1];

       d = Array.getShort(apdu_data, 0);

       switch (apdu_data[ISO.OFFSET_INS]) {

       case DATA_ACQUISITION_INS:
                AccumulateData(p, d, apdu_data[ISO.OFFSET_P2]);
                break;
       case SYSTEM_CONTROL_INS:
                ProvideControl(p, d);
                apdu.setOutgoingAndSend((short)0, (short)8);
                break;
       default:
                ISOException.throwIt(ISO.SW_INS_NOT_SUPPORTED);
       }

       ISOException.throwIt(ISO.SW_NO_ERROR);
}

/*
** Accumulate a Data Value from a Control Point
*/
private void AccumulateData(byte p, short d, byte flags) {
       short r, n, v, v2;

       r = records[p];

       if((r == 0) || ((flags & NEW_RECORD) != 0)) {
               r++;
               records[p] = (byte)r;
       }
       r--;

       n  = Array.getShort(record, p*r*10+0);
       v  = Array.getShort(record, p*r*10+2);
       v2 = Array.getShort(record, p*r*10+6);

       n  += 1;
       v  += d;
       v2 += d*d;

       Array.setShort(record, p*r*10+0, n);
       Array.setShort(record, p*r*10+2, v);
            Array.setShort(record, p*r*10+6, v2);
    }

    /*
    ** Provide a Control Command to a Control Point
    */
    private void ProvideControl(byte p, short d) {
           short r, i, lb, ub;

           r = rows[p];

           for(i = 0; i < r; i++) {

                   lb = Array.getShort(row, p*r*12+0);
                   ub = Array.getShort(row, p*r*12+2);

                   if(d > lb && d <= ub) {
                          Util.arrayCopy(row, (short)(p*r*12+4),
                                             apdu_data, (short)0, (short)8);
                          return;
                   }
            }
            ISOException.throwIt(ISO.SW_RECORD_NOT_FOUND);
    }
}

The Java card version of the SCADA online application compiles to 680 Java byte codes using Schlumberger's mksolo32 byte code converter.

The need to preallocate the data acquisition and command tables to their maximum possible size means that a lot of EEPROM space is wasted. Files could be used to store this data, but files are not part of the Java Card specification; those Java cards that extend the specification by including file objects require preallocation if the file is to maximum size.

The lack of multidimensional arrays in Java Card Java is only a slight irritation as is having to constantly cast everything to a short. You should, however, abandon the “write once, run everywhere” notion when it comes to Java Card versus “pure” Java. Java Card is a special-purpose offshoot of Java that, because of the smart card architectural and processing environment, has abandoned some elements of consistency with its parent. This is particularly true in the area of data access control and data sharing, which we discuss later.

The Java Card Application Development Cycle

The process of creating an executable Java card application consists of the following steps:

  1. Edit and compile the application's Java card source code.

  2. Convert the resulting class files to a Java card byte code file (CAP file).

  3. Verify the CAP file (optional).

  4. Translate the CAP file to a vendor-specific application image file.

  5. Download the application image file to the vendor's Java card.

  6. Install the application into the Java card framework.

At this point, the application can be selected and run. The translate step and the download step are combined in some Java Card implementations.

While this process is straightforward, the eight Java card software development kits currently on the market differ markedly in how they present this process to the application developer. Work is underway to standardize this process among a particular subset of the eight cards.

Each Java card SDK takes as its starting point the collection of application class files created by any one of the commercially available Java compilers from the application's Java source code. Because none of these full Java compilers recognize the Java Card subset or extensions, it falls to the task of the converter, the verifier, and the translator to check for compliance with the Java Card specification. Unfortunately, because the source code has been left behind, it can be a challenging task to tie the error messages generated by these programs back to the Java source code line that is causing the problem. Furthermore, because Java Cards differ in their loading mechanisms from one vendor to another, an application that successfully passes through the convert/verify/translate process from one vendor might fail the same process of another vendor.

Many of the Java card SDKs leave in place the security machinery that is used in production to ensure that only authorized applets get onto the card. While this is helpful if you are doing end-to-end testing, it can get in the way if you are at the initial stages of developing, testing, and debugging a Java card application. One of the kits, the one from Giesecke & Devrient, includes a very nice Java card simulator that can be very useful in initial debugging of a Java card application.

The Java Card specification mandates the step of installing an application into the on-card framework. Because Java Card implements classic operating system features such as data security, access control, and interapplication communication using programming language constructs, there must be a “first among equals” application that knows and manages all the other applications. This overseer application is essentially the Java card framework, and installing a new application into the framework connects the language features and name space of the new application with the language features and name space of the framework. The result is that a Java card is essentially one giant application—the framework—that contains all the applications loaded onto the card.

The “firewall” between Java card applications is provided by the rules of variable name visibility defined for the Java Card language. All applications are part of the framework's name space and all execute in the same sandbox—the framework's. As we will see later, the unified name space provided by the Java card framework is the language feature also used to implement data sharing between applications.

Java cards have perhaps the most involved application development cycle of all the cards discussed in this chapter. This is due both to the innate complexity of the process and the lack of integration of the steps. The inability of standard compilers to handle the distinct specifications of Java Card Java means that simple programming errors are caught farther downstream than is desirable. The use of language features to perform operating system services begets the installation step.

The Windows-Powered Smart Card

Microsoft's Windows for Smart Cards (WfSC) operating system was developed in the summer of 1998 and made its debut at Cartes'98 in November of that year. Rather than designing de novo for the smart card, the Microsoft development team, like Multos's Nat West Development Team before it, started with battle-hardened designs from “big iron” and adapted them to the resources available on the smart card. The philosophy was to embed smart card computing in the skill sets and programming models of existing application programmers rather than require that these application programmers learn new skills and programming models in order to use smart cards. Of course, handling the limited resources environment of the smart card will probably always constitute a re-learning process for typical PC-level application programmers.

The file system design of the Windows card is the tried and true File Access Table (FAT) file system of DOS and Windows. Because smart cards are used internationally, file names are represented in Unicode rather than ASCII. To support the fine-grain, multipersonality requirements for access control and data security, the team adopted the access control list (ACL) design created by Bob Daley and Peter Neumann in 1964 for the Multics operating system and found in many Multics descendants such as George, Unix, VMS, and Windows NT. The virtual machine is a compact version of the Intel 8048 and the on-card application programming interface is a greatly scaled-down version of the Windows API.

The Windows Card Virtual Machine

The Microsoft Windows Card virtual machine (or as the documentation refers to it, the Windows Card Runtime Environment, or simply RTE) is arguably the most well-designed and most parsimonious of all the smart card virtual machines.

Like the Multos virtual machine, the Microsoft virtual machine has a Harvard architecture with a single 8-bit accumulator and an optional stack. Also, like the Multos virtual machine, it is defined in terms of a small core byte code set to which application-specific extensions can be added. The 27 core byte codes are shown in Table 5.6.

Table 5.6. Byte Codes for Windows Card Virtual Machine

Mnemonic

Description

ADD

Add literal to the ACC

SUB

Subtract literal from the ACC

AND

AND literal with the ACC

OR

OR literal with the ACC

XOR

XOR literal with the ACC

LDA#

Load ACC with a literal

LDA

Load ACC from an address

LDAI

Load ACC from address and increment address

STAI

Store ACC to address and increment address

LDAD

Decrement address and load address to ACC

STAD

Decrement address and store ACC to address

LDAC

Load the ACC with contents of PC+A+offset+2

JMP

Jump to a location

JZ

Jump if Z flag is set

JNZ

Jump if Z flag is not set

JC

Jump if C flag is set

JNC

Jump if C flag is not set

CALL

Call subroutine

RET

Return from a subroutine

CLR

Clear an address to zero

DEC

Decrement contents of an address

INC

Increment contents of an address

NOP

Do nothing

END

Terminate execution

STOP

Break-point in debug mode

ESC

Transfer control to extension

SYS

Call an operating system service

The Windows Card Programming Model

The Windows card programming model is very much like the Multos programming model. There is no over-arching framework as there is on the Java card. After being selected, the application has complete control of the card and calls upon the WfSC operating system for services such as communication, file access, and cryptography—classic platform computing.

Selection of an application is accomplished by associating a unique APDU with the application and then sending that APDU to the card. In other words, it is not by way of AIDs. In this regard, WfSC is like the Basic card (see later in this chapter) except that an APDU is associated with an entire application, not entry points in the application. Once activated, the application receives all APDUs transmitted to the card until it terminates. Associating an APDU with an application can be a bit awkward because it requires editing and overwriting the APDU dispatch table on the card. The dispatch table itself is a very powerful construct and, as its full utility gets integrated into the development environment, the process of associating an APDU with an application should become painless.

A compiled WfSC program consists of two files: a byte code file (.RTE) and a data space file (.DAT). This separation of code and data, at one time a basic tenet of good programming practice, together with the existence of a full-featured file system, means that code that implements a WfSC application on a card can be updated without destroying the data that has become associated with the application. It is, in fact, possible for two code files to share the same data space file but this is not typically done. Rather, the file system is used to share data between applications.

The SCADA Program on a Windows-Powered Smart Card

Code for SCADA Program on a Windows Smart Card

Const CLA = &HC0
Const INS = &H20
Const P1 = &H0
Const P2 = &H0

Const NEW_RECORD = &H1

Const SUCCESS = &H9000
Const CLA_ERROR = &H6D00
Const INS_ERROR = &H6E00
Const TAB_ERROR = &H6F00

Const SHIFT8 As Integer = &H100
Const SHIFT16 As Long = &H10000
Const SHIFT24 As Long = &H1000000

Function MAKEWORD(ByVal a As Byte, ByVal b As Byte) As Long
    MAKEWORD = a * SHIFT8 + b
End Function

Function MAKEDWORD(ByVal a As Long, ByVal b As Long) As Long
    MAKEDWORD = a * SHIFT16 + b
End Function

Sub Main(ByVal CLA As Byte, _
         ByVal INS As Byte, _
         ByVal P1 As Byte, _
         ByVal P2 As Byte, _
         ByVal lc As Byte)

    Dim APDUdata(0 To 10)
    Dim recs, rows As Byte
    Dim record(0 To 9) As Byte, row(0 To 11) As Byte
    Dim d, n, lb, ub As Integer
    Dim v, v2 As Long
    Dim hFile As Byte
    Dim i, Status, ActualBytes As Byte
    Dim fileName(0 To 3) As Byte

    If (CLA <> &HC0) Then
        ScwSendCommInteger CLA_ERROR
        Exit Sub
    End If

    d = MAKEWORD(APDUdata(0), APDUdata(1))

    Select Case INS

    ' Accumulate Data
    Case &H10:
        fileName(0) = &H10
        fileName(1) = P1
        fileName(2) = 0
        fileName(3) = 0
        Status = ScwCreateFile(fileName, "", hFile)
        Status = ScwReadFile(hFile, recs, 1, ActualBytes)
        If recs = 0 Or P2 = NEW_RECORD Then
            recs = recs + 1
            Status = ScwSetFilePointer(hFile, 0, FILE_BEGIN)
            Status = ScwWriteFile(hFile, recs, 1, ActualBytes)
        End If
        recs = recs - 1
        Status = ScwSetFilePointer(hFile, recs * 8 + 1, FILE_BEGIN)
        Status = ScwReadFile(hFile, record, 10, ActualBytes)
        n = MAKEWORD(record(0), record(1))
        v = MAKEDWORD(MAKEWORD(record(2), record(3)), MAKEWORD(record(4), record(5)))
        v2 = MAKEDWORD(MAKEWORD(record(6), record(7)), MAKEWORD(record(8), record(9)))

        n = n + 1
        v = v + d
        v2 = v2 + d * d

        record(0) = n  SHIFT8
        record(1) = n - record(0) * SHIFT8

        record(2) = v  SHIFT24
        record(3) = v  SHIFT16 - record(2) * SHIFT8
        record(4) = v  SHIFT8 - (record(2) * SHIFT16 + record(3) * SHIFT8)
        record(5) = v - (record(2) * SHIFT24 + record(3) * SHIFT16 + record(4) * SHIFT8)

        record(6) = v2  SHIFT24
        record(7) = v2  SHIFT16 - record(6) * SHIFT8
        record(8) = v2  SHIFT8 - (record(6) * SHIFT16 + record(7) * SHIFT8)
        record(9) = v2 - (record(6) * SHIFT24 + record(7) * SHIFT16 + record(8) * SHIFT8)

        Status = ScwSetFilePointer(hFile, recs * 10 + 1, FILE_BEGIN)
        Status = ScwWriteFile(hFile, record, 10, ActualBytes)

    ' Provide Control Command
    Case &H20:
        fileName(0) = &H20
        fileName(1) = P1
        fileName(2) = 0
        fileName(3) = 0
        Status = ScwCreateFile(fileName, "", hFile)
        Status = ScwReadFile(hFile, rows, 1, ActualBytes)
        For i = 0 To rows
            Status = ScwSetFilePointer(hFile, i * 12 + 1, FILE_BEGIN)
            Status = ScwReadFile(hFile, row, 12, ActualBytes)
            lb = MAKEWORD(row(0), row(1))
            ub = MAKEWORD(row(2), row(3))
            If d > lb And d <= ub Then
                ScwSendCommBytes row, 4, 8
                ScwSendCommInteger SUCCESS
                Exit Sub
            End If
        Next
        ScwSendCommInteger SUCCESS
        Exit Sub
    End Select

End Sub

The SCADA application compiles to 1753 bytes of executable byte codes for the Version 1.0 Microsoft Runtime Environment (RTE).

The fact that FAT files can grow and shrink as needed means that there is no wasted space on the Microsoft card for storing either the acquired data or the process control rules. The lack of bit operations in Visual Basic does, however, mean that unnatural computation acts to efficiently store multibyte values in the files have to be performed.

The Windows Card Application Development Cycle

Microsoft has integrated application development for Windows for Smart Cards completely into Visual Studio and its popular and widely used Visual Basic IDE. In fact, Windows for Smart Cards is just another type of Visual Basic project. When you compile a Windows for Smart Cards Visual Basic application, all of the constraints on Visual Basic to enable it to be compiled for the WfSC virtual machine are taken into account and violations of those constraints are flagged at the source code level and immediately available for editing and fixing. At the time of this writing, Microsoft has discontinued their support for Windows for Smart Cards. The product may well be supported by others; however, its continued support in Visual Studio and other Microsoft toolkits may become an issue.

The Visual Basic IDE also includes a Windows for Smart Cards simulator into which a successfully compiled application can be loaded. The simulated card can be connected to an off-card VB application and the two run in tandem, but the off-card application is running in a separate VB IDE. You can single-step from off-card to on-card and back to off-card code, but it is much more awkward than the “double debugger” environment offered by the ZeitControl Basic card (see later in this chapter).

After the on-card application has been run in the simulator, it can be downloaded to the card from within the VB IDE. Like some of the other programmable cards, the security mechanisms surrounding code downloading in the field can be turned off to speed debug turnaround time. After the code has been downloaded, the off-card application can be pointed at the card rather than the simulator and debugging with the card itself commenced.

Besides writing and downloading VB applications, the free-for-the-download Microsoft SmartCard Toolkit provides a number of additional capabilities that enable the smart card architect to design a complete smart card including the file system, access control policies, and cryptography. This multifaceted smart card design capability tends to lead to a complex development context within which it is easy to lose your simple VB application. Nevertheless, the integration of Source Safe and continued work on the integration of smart cards within the VB IDE will smooth over these bumps and make the creation of custom smart cards a task that any application programmer can tackle without having to learn arcane facts about microcontrollers, ROM masks, and chip production.

The ZeitControl Basic Card

The ZeitControl Basic card was and still is the first programmable smart card to offer an integrated application development environment that spans both the off-card and the on-card application simultaneously. You bring up the off-card application in one window, the on-card in an adjacent window, and single-step through the off-card, over to the on-card, and then back to the off-card. At the time they were introduced in 1996, the card and its IDE were light-years ahead of the competition. In a number of ways, they still are. The IDE is free and can be downloaded from www.zeitcontrol.de.

ZeitControl Basic (ZC-Basic) contains most of the usual Basic language constructs including strings and string functions, arrays, and user-defined data types. Like the Microsoft card, the Basic card sports a DOS-like FAT file system with the familiar Basic programming interface.

The ZeitControl Basic Card Virtual Machine

The Compact version of the ZeitControl Basic card virtual machine supports 1-, 2-, and 4-byte signed integer and string data types. The Extended version also supports floats. It is the only virtual machine that supports floats. The 116 byte codes in the Compact ZeitControl virtual machine are shown in Table 5.7.

Table 5.7. Byte Codes for Basic Card Virtual Machine

Mnemonic

Description

ABSL

Pop slX ; push Abs(slX)

ABSW

Pop swX ; push Abs(swX)

ADD$

Pop X$ ; pop Z$ ; pop Y$ ; X$ = Y$ + Z$

ADDL

Pop slY ; pop slX ; push slX + slY

ADDSP

SP += scDelta (if scDelta > 0, 'pushed' bytes are initialized to zero)

ADDW

Pop swY ; pop swX ; push swX + swY

ALLOCA

Pop A ; pop bounds word uwBr for each dimension r, in reverse order; allocate data area of A and initialize all elements to 0

ANDL

Pop ulY ; pop ulX ; push ulX And ulY

ANDW

Pop uwY ; pop uwX ; push uwX And uwY

ARRAY

Pop A ; pop subscript swIr for each dimension r, in reverse order ; push address of array element A (swI1, swI2, . . . , swIn)

ASC$

Pop X$ ; push Asc(X$) as CHAR

BOUNDA

Pop swHi ; pop swLo ; push 400*swLo + (swHi – swLo) as WORD

CALL

Procedure call or GoSub: push PC+3 as WORD ; PC = uwAddr

CHKDIM

Pop A ; push A ; if Dim(A) <> ucNdims then execute ERROR 0C

COMP$

Pop Y$ ; pop X$ ; compare ; push for WORD comparison

COMPL

Pop slY ; pop slX ; compare ; push for WORD comparison

COPY$

Pop X$ ; pop Y$ ; X$ = Y$

CVTCW

Pop ucX ; swY = ucX ; push swY

CVTLW

Pop slX ; swY = slX ; push swY

CVTWC

Pop swX ; ucY = swX ; push ucY

CVTWL

Pop swX ; slY = swX ; push slY

DIVL

Pop slY ; pop slX ; push slX / slY

DIVW

Pop swY ; pop swX ; push swX / swY

DUP

Push the top ucLen stack bytes

ENTER

Push FP ; push SP + ucFrmSiz + F ; FP = SP ; SP = SP + ucFrmSiz

ERROR

Generate a P-Code error condition

EXIT

Exit the Virtual Machine

FDATA

Copy data (ucLen bytes) to address FP + scAddr

FREE$

Pop 2-byte handle to variable-length string X$ ; X$ = empty string

FREEA

Pop A ; if Dynamic then deallocate A, else set all elements of A to 0

FREEA$

Pop string array A ; free all strings in A ; if Dynamic then deallocate A

HEX$

Pop X$ ; pop slX ; X$ = Hex$(slX)

INCL

Pop slX ; push slX + 1

INCW

Pop swX ; push swX + 1

JEQWB

Pop swY ; pop swX ; if swX = swY then PC = PC + scDisp + 2

JGEWB

Pop swY ; pop swX ; if swX >= swY then PC = PC + scDisp + 2

JGTWB

Pop swY ; pop swX ; if swX > swY then PC = PC + scDisp + 2

JLEWB

Pop swY ; pop swX ; if swX <= swY then PC = PC + scDisp + 2

JLTWB

Pop swY ; pop swX ; if swX < swY then PC = PC + scDisp + 2

JNEWB

Pop swY ; pop swX ; if swX <> swY then PC = PC + scDisp + 2

JNZWB

Pop swX ; if swX <> 0 then PC = PC + scDisp + 2

JUMPB

PC = PC + scDisp + 2

JUMPW

PC = uwAddr

JZRWB

Pop swX ; if swX = 0 then PC = PC + scDisp + 2

LBOUND

Pop A ; pop ucDim ; push lower bound of subscript ucDim as WORD

LCASE$

Pop X$ ; pop Y$ ; X$ = LCase$(Y$)

LEAVE

Return from procedure: SP = FP – F ; pop FP ; pop PC

LEFT$

Pop swLen ; pop X$ ; push Left$(X$, swLen)

LEN$

Pop X$ ; push Len(X$) as CHAR

LOOP

Pop swX ; if swX >= 0 then execute JLEWB else execute JGEWB

LTRIM$

Pop X$ ; push LTrim$(X$)

MID$

Pop swLen ; pop swStart ; pop X$ ; push Mid$(X$, swStart, swLen)

MODL

Pop slY ; pop slX ; push slX Mod slY

MODW

Pop swY ; pop swX ; push swX Mod swY

MULL

Pop slY ; pop slX ; push slX * slY

MULW

Pop swY ; pop swX ; push swX * swY

NEGL

Pop slX ; push –slX

NEGW

Pop swX ; push –swX

NOP

No operation

NOTL

Pop ulX ; push Not(ulX)

NOTW

Pop uwX ; push Not(uwX)

ORL

Pop ulY ; pop ulX ; push ulX Or ulY

ORW

Pop uwY ; pop uwX ; push uwX Or uwY

POECW

Pop CHAR at address uwAddr

POELW

Pop LONG at address uwAddr

POEWW

Pop WORD at address uwAddr

POFCB

Pop CHAR at address FP + scAddr

POFLB

Pop LONG at address FP + scAddr

POFWB

Pop WORD at address FP + scAddr

POINC

Pop uwAddr ; pop CHAR at address uwAddr

POINL

Pop uwAddr ; pop LONG at address uwAddr

POINW

Pop uwAddr ; pop WORD at address uwAddr

PORCB

Pop CHAR at address ucAddr

PORLB

Pop LONG at address ucAddr

PORWB

Pop WORD at address ucAddr

PUCCB

Push constant CHAR ucConst

PUCWB

Push constant scConst sign-extended to WORD

PUCWC

Push constant ucConst zero-extended to WORD

PUCWW

Push constant WORD swConst

PUECW

Push CHAR at address uwAddr

PUELW

Push LONG at address uwAddr

PUESW

Push STRING at address uwAddr

PUEWW

Push WORD at address uwAddr

PUFAB

Push FP + scAddr as WORD

PUFCB

Push CHAR at address FP + scAddr

PUFLB

Push LONG at address FP + scAddr

PUFSB

Push STRING at address FP + scAddr

PUFWB

Push WORD at address FP + scAddr

PUINC

Pop uwAddr ; push CHAR at address uwAddr

PUINL

Pop uwAddr ; push LONG at address uwAddr

PUINW

Pop uwAddr ; push WORD at address uwAddr

PUPSB

Push 3-byte STRING parameter at address FP + scAddr

PURCB

Push CHAR at address ucAddr

PURLB

Push LONG at address ucAddr

PURSB

Push STRING at address ucAddr

PURWB

Push WORD at address ucAddr

PUSAB

Push SP – ucAddr as WORD

RAND

Push a LONG random number

RDATA

Copy data (ucLen bytes) to address ucAddr

RETURN

Return from GoSub: pop PC

RIGHT$

Pop swLen ; pop X$ ; push Right$(X$, swLen)

RTRIM$

Pop X$ ; push RTrim$(X$)

STRING$

Pop X$ ; pop ucChar ; pop swLen ; X$ = String$(swLen, ucChar)

STRL$

Pop X$ ; pop slX ; X$ = Str$(slX)

SUBL

Pop slY ; pop slX ; push slX – slY

SUBW

Pop swY ; pop swX ; push swX – swY

SYSTEM

Operating system call

UBOUND

Pop A ; pop ucDim ; push upper bound of subscript ucDim as WORD

UCASE$

Pop X$ ; pop Y$ ; X$ = UCase$(Y$)

VALHL$

Pop X$ ; slVal = ValH(X$, ucLen) ; push slVal ; push ucLen

VALL$

Pop X$ ; slVal = Val&(X$, ucLen) ; push slVal ; push ucLen

WTX

Send a Waiting Time Extension request

XORL

Pop ulY ; pop ulX ; push ulX Xor ulY

XORW

Pop uwY ; pop uwX ; push uwX Xor uwY

The ZeitControl Programming Model

ZeitControl Basic extends the Subroutine and Function procedure types of regular Basic with a new type called Command. You create Command procedures on the card and then simply call them as functions from the off-card application. All the smart card communication and APDU handling is taken care of by the ZeitControl runtime system. Data is passed into the card from the host and back to the host from the card in the arguments to the Command procedure.

For example, in the on-card application, you might include the code

Command &HC0 &H10 MyAPDU(in As Long, out As String)

     if in <> 0 then
          out = "Not Zero"
     else
          out = "Zero"
End Command

You would call this Command from the off-card application by writing

Declare Command &HC0 &H10 MyAPDU(in As Long, out As String)
Dim S As String
...
Call MyApdu(0, S)
...

The P1 and P2 parameters of the APDU can be used but they are optional.

The ZeitControl development environment encourages tight integration of the off-card and on-card application. The tools, language features, and runtime support provided for Basic card applications are most effective when both sides of the application are written in ZC Basic. But this is not a necessity. A Basic card running a ZC Basic application will field ISO 7816-4 APDUs coming from any off-card program and will return ISO 7816-4–compliant responses. The details of the APDU formats used to communicate with a Basic card are given in the Basic Card User's Guide.

The SCADA Online Application for the ZeitControl Card

Code for Online SCADA Application for Basic Card

Const NEWRECORD = &H1

Const TABERROR = &H6F00

Eeprom recs, rows As Byte

Command &HC0 &H10 AccumulateData(d as Long)

    Dim n As Integer
    Dim v, v2 As Long

    If recs = 0 Or P2 = NEWRECORD Then
        recs = recs + 1
    End If

    Open "data" For Binary Access Read Write As #1

    Seek #1, (recs-1)*10

    Get #1, , n
    Get #1, , v
    Get #1, , v2

    n = n + 1
    v = v + d
    v2 = v2 + d * d

    Seek #1, (recs-1)*10

    Put #1, , n
    Put #1, , v
    Put #1, , v2

    Close #1

End Command

Command &HC0 &H20 ProvideCommand(d as Long, c1 as Long, c2 as Long)
    Dim i as Byte
    Dim lb, ub as Integer
    Dim row(0 to 11) as Byte

    Open Chr$(P1) For Binary Access Read As #1

    For i = 0 To rows
           Get #1, , lb
           Get #1, , ub
           Get #1, , c1
           Get #1, , c2

        If d > lb And d <= ub Then
            Exit Command
        End If
    Next

    SW1SW2 = TABERROR

End Command

The SCADA online application compiles into a mere 260 bytes of executable byte codes for the ZeitControl Basic card.

Direct reading and writing of variables from files is a big win for ZC –Basic, as is treating nonvolatile memory as both a variable store and a file system. APDU handling, which introduces so much unnecessary complexity into Java card and WfSC programs, is totally absent from ZC Basic programs. The simple command-as-subroutine metaphor turns terminal communication into a simple remote procedure call.

The Basic Card Application Development Cycle

The Basic card has by far and away the most tightly integrated, most efficient, and easiest to use application development cycle. The ZeitControl “Double Debugger” is identical to the Microsoft Visual Basic environment but the integration of the card and the off-card application is much tighter and more seamless than in the Visual Basic IDE.

Within single running instance of the Double Debugger, you create and edit both sides of the application. Each side can be compiled by itself or the two sides can be compiled simultaneously. After successful compilation, the source code for each side can be loaded into side-by-side windows and you can single-step through the off-card application, follow an APDU to the on-card application, single-step through the on-card code, follow a response back to the off-card application, and continue single-stepping through the host code. All communication between the off-card and the on-card application is visible as are current variable values on both sides. The usual debugging features, such as breakpoints and watch points in each window, are available.

Next, the on-card application can be downloaded to a Basic card. Single-stepping through the off-card application proceeds as previously. Communication between the host and the card is visible but response from the card is immediate.

Data Access Control

You may have six applications on your smart card but you only have one home address. Clearly, you want the six applications and any new ones that might be loaded onto your card to share this information but you may want only one, the personal information management application, for example, to be able to change it. The video store application and the pizza parlor application on your card may want to share a loyalty points purse but they don't want the ice cream store to figure out how much time you're spending at the other end of Main Street by reading the number of video-pizza loyalty points you have accumulated.

There can be 5, 10, or even 20 different entities that have one or more rights to access various pieces of data on a multiapplication smart card. The cardholder is an obvious example of one of these entities. The issuer of the electronic purse on the card is another example. The capacity to enforce data access control policies—ensuring that each entity can do what it is allowed to do and not do what it is not allowed to do—is in fact the defining characteristic of a smart card.

Data access control is more comprehensive than data security. Data security typically means making sure that unauthorized entities can't access a piece of data. It is focused primarily on locking people out, not on selectively letting some people do some things and other people do other things. Data access control certainly includes data security in this sense but goes on to ensure that, for example, entities that are only allowed to read the data can't change it or entities that are only allowed to add data to a file can't delete data from it.

The four programmable cards as described previously are functionally identical—write an application in a high-level language, compile it to byte codes, load the byte codes onto the card, place them in execution, and talk to the running application with APDUs. The approach taken by one is preferred by some and the approach taken by another preferred by others. But they are basically the same with respect to the broad outlines of creating, loading, and running an on-card application.

Given then that data access control is the defining property of smart cards, it is perhaps surprising where these four cards differ as much as they do in this aspect of their operation. You might have thought that the users and the makers of smart cards would long ago have come to a consensus on the right way to do data access control and that all the cards would simply implement this given wisdom. Actually, it can be argued that they did; however, the resulting mechanisms don't fit well into a multiapplication environment where applications want to share data.

The problem of on-card data sharing and access control in its full generality is actually relatively new to smart cards. In the pre-multiapplication card era, there were only a few entities on a card (the cardholder, the issuer, the generic point of use), the number of data items was static, and the access rights of each entity were frozen when the card was created. It didn't take much in the way of on-card software to meet these modest data access control requirements. It wasn't until the advent of serious commercial interest in the multiapplication card in the late 1990s that the realization dawned that existing smart card data access control machinery was not up to the challenges of these new kinds of cards. The number of entities a card had to keep track of multiplied many times over. The entities could come and go with the applications. The complexity of the trust relationships between the entities and the data on the card multiplied.

Application-Centric versus Data-Centric Access Control

There are two general approaches to data access control. One way—the application-centric approach—associates the data with an application and lets the application control access to the data. The other way—the data-centric approach—associates access control policies with the data and lets the operating system mediate between the data and its accessors using these policies. As we will see, the Java card and the Multos card implement the application-centric approach and the Microsoft card and the ZeitControl card implement the data-centric approach. Each approach has its supporters and detractors; each can find preferred utility in certain classes of problems.

The application-centric approach has the advantage that more fine-grain data access control policies can be implemented because the application knows the semantics of the data. The disadvantage is that these fine-grain policies are embedded in application code so that the code has to be changed if the policies are changed. There is the additional disadvantage that if the application goes away, so does the access control to the data it is responsible for.

The data-centric approach has the advantage that data access control policies are externalized and have a common representation across all data. Applications can concentrate on processing data, not administering outside access to it. Furthermore, because applications and access control have been separated, each can come and go independently of the other. Obviously, this is also a disadvantage if the two evolve independently without significant regard for the other. Another disadvantage is that the access control policy language, by definition, has to be very general and of a one-size-fits-all nature and thus typically can't key off of data semantics or even data values.

Recently in updating the standard smart card command set of standards, ISO 7816, the worldwide smart card standards community, also put in place a very general standard for data access control on smart cards. It is a data-centric (and file system-oriented) approach called Security Attributes and it is included in ISO 7816-9 that was ratified as an ISO standard on May 9, 2000.

ISO 7816-9 Data Access Control

ISO 7816-9 lets you associate one or more security attributes with any operation on any file. A security attribute is simply an assertion about the current security status of the card. For example, you might associate the security attribute “Cardholder has been authenticated” with the UPDATE operation on the PIN file. This means that the operating system will allow an UPDATE operation on the PIN file to proceed only if the PIN contained the file that had already been presented to the card. In everyday language, you have to know the PIN in order to change the PIN.

How the security status of the card is described is covered in ISO 7816-8. These descriptions can become quite complex and so security attributes themselves can become quite complex. Furthermore, if more than one security attribute is associated with a particular operation on a particular file, they can be ANDed together or ORed together. In the first case, they all have to be true if the operation is to proceed. In the latter case, at least one has to be true if the operation is to proceed. The ISO 7816-9 Security Attributes Task Force has tried and largely succeeded in preserving the advantages of data-centric access control while reaching for some of the fine-grain capabilities of application-centric data access control.

Of the four cards discussed in this chapter, the Microsoft card comes the closest to the ISO 7816-9 Security Attributes standard. As we will see, it allows arbitrary Boolean expressions in card authentications to be associated with each possible operation on a file. Card authentications are one type of security status and Boolean expressions generalize the simple ANDing and ORing defined by ISO 7816-9.

Application-Centric Access Control Using Data Ownership and Interapplication Communication

The Multos card and the Java card take basically the same approach to data access control. They both begin by positing that each piece of data on the card is owned by the application that created it. To access data owned by an application, you send the owning application a message asking for the data and, if the owning application wishes, it returns what you asked for. The challenge, of course, is for the called application to figure out if it wishes or not. This usually turns on identifying the requesting application somehow. Both the Java card and the Multos card leave this as an exercise for the card issuer and application providers and only provide the basic interapplication communication services. The basic problem is the extension of “identity” from the off-card to the on-card environment and the ability to simultaneously treat multiple identities within the smart card itself.

Interapplication communication can obviously be used for purposes above and beyond simply sharing data between applications. Request-receiving applications can be created to provide a wide range of general-purpose utility services to other on-card applications. We will confine our attention in this section to the use of this general-purpose capability to the task of data access control and data sharing.

For small, relatively fixed populations of applications, the notion of data ownership and the use of interapplication communication to share data among applications works well. When applications can come and go, however, the notion of ownership and application-based access control can quickly become problematic. All too often, we want to get rid of the application but not the data that it has created. This means we have to either leave behind a shadow of the application simply to administer the access to the data or pass ownership of the data and the administration of access to another application. Neither of these alternatives is particularly attractive.

Data Sharing on a Java Card

All on-card Java card applications share a common namespace; hence, the framework can use the namespace to move data between requesting applications and owning applications. Owning applications export function names to the framework that provide access to the data they are willing to share. Requesting applications ask the framework for access to shared data by calling out the owning application's AID. The framework then passes back to the requesting applications the access functions registered by the owning application. It is still up to the owning application to determine if it wants to provide its data to the requesting application.

The downside of this approach is that an application has to know the AIDs of all the applications it wants to acquire data from and what data is associated with each AID. This can work fine in small, stable, predefined sets of applications, but it doesn't seem to scale well. As the number of applications grows and as applications are loaded onto and deleted from individual cards, the task of managing the AID-based connection between pairs of applications on each card gets exponentially harder.

Data Sharing on the Multos Card

Like the Java card, each Multos application owns the data it creates and shares this data with other applications according to is own preferences. Unlike the Java card, there is no capo de capo framework with root privileges on the Multos card that mediates interapplication communication. There is no registry of the data applications willing to share data nor a central directory of shared data. Instead, Multos applications communicate with one another by sending each other APDUs. This unifies interapplication and host communication and allows the smart card designer to migrate functionality between the terminal and the card without rewriting all the applications on the card. Making the APDU the de facto intra-on-card messaging format, does involve a fairly heavy-weight mechanism in the process.

Interapplication communication on the Multos card is called delegation. The sender of the APDU is the delegator and the receiver of the APDU is the delegate. The delegator addresses the delegate using the delegate's AID and the delegate program is responsible for determining if the delegator is who it says it is and if it should be served.

Data-Centric Access Control Using File Attributes and Access Control Lists

The Windows card and the Basic card take a wholly different approach to data access control and sharing. It is the approach found in almost all big iron operating systems and it is the approach underpinning the smart card standard for data access control, ISO 7816-9. Rather than associating data with an application and then forcing that application to administer access to it, the approach used is to associate access privilege descriptions directly with the data and let the operating system administer access for all applications using these descriptions. In this scheme, access controls exist for the lifetime of the data rather than for the lifetime of the application that created the data. Furthermore, data access can be represented and administered uniformly across all data in a way that access policies are visible rather than embedded down inside application code. The flip side of this, of course, is that access policies have to be defined and implemented across an entire application structure (off-card and on-card), which can raise a number of coordination issues in its own right.

Data Sharing on the Basic Card

The ZeitControl Compact Basic card does not support any file access conditions. All applications on the card can open, read, write, and update all the files on the card as long as they know the name of the file. The Enhanced Basic card supports the association of a read lock, a write lock, and a read-and-write lock with any file or directory, but this is a lock from the point of view of the off-card application, not a lock between applications on the card.

Data Sharing on the Microsoft Card

The access control subsystem of the Microsoft card is the most comprehensive and the most general of the four cards discussed in this chapter; that is, of any mechanisms specified as part of the basic system for the various cards. It is based on the access control list concepts invented for the Multics operating system and is compatible with and extends the security attribute recommendations of ISO 7816-9.

The WfSC scheme associates an access control list with every file and every directory. The access control list consists of a sequence of pairs, (Op, Bool), where Op is an operation that can be performed on the file or directory such as read, write, or create and Bool is a Boolean expression over authentication status of the entities that might want to perform the Op operation on the file or directory. An authentication status is TRUE if the entity has been authenticated by the card during the current session and the authentication status is FALSE if the entity has not been authenticated by the card in the current session.

The Boolean expression is evaluated any time any application attempts to perform the Op operation on the file or directory. If the Boolean expression evaluates to TRUE, then the operation is allowed to proceed. If the Boolean expression evaluates to FALSE, the operation is not allowed to proceed.

Access control lists are themselves stored in files and, therefore, in turn have access control lists guarding them. Clearly, the access control list describing access to an access control list will, in all likelihood, be quite different than the access control list it guards.

Summary of the Four Programmable Smart Cards

In this chapter, we have discussed on-card programming and compared and contrasted the four major multiapplication, programmable smart cards on the market. Each card, together with its application development environment, has its strengths and weaknesses. They are certainly all different and there are undoubtedly practical smart card applications where any one of them would outshine all of the others.

The Multos card and the Windows card are minimalist RISC type cards that provide maximum freedom to the application programmer. Java card and Basic card are CISC type cards with richer programming models but more application programmer creature comforts once you learn how to navigate them.

Our discussions of the four cards can be summarized in the following five property tables (Tables 5.8 through 5.12):

Table 5.8. Virtual Machine Type

RISC

CISC

Multos, Microsoft

Java, ZeitControl

Table 5.9. On-Card API Complexity

Simple

Complex

Multos, Microsoft

Java, ZeitControl

Table 5.10. Program Development Environment Complexity

Simple

Complex

Multos, ZeitControl

Java, Microsoft

Table 5.11. Access Control Style

Data-Centric

Application-Centric

Microsoft, ZeitControl

Java, Multos

Table 5.12. Terminal Communication Complexity

Simple

Complicated

Multos, ZeitControl

Java, Microsoft

Finally, Table 5.13 gives some descriptive information about each card as of the writing of this book.

Table 5.13. Characteristics of the Major Programmable Smart Cards

 

Multos Card 4.0

Java Card 2.1.2

Windows Card 1.0

Basic Card 3.1

Implementations

2

6

1

1

Suppliers

2

5

7

1

Programming Languages

C, Java, MEL

Java Card

Visual Basic, C

ZC Basic

Virtual Machine Byte Codes

  • Core

31

108

27

116

  • Extended

23

61

On-Card API Functions

  • Core

24

119

45

42

  • Extended

1151

472

29

Application Selection

AID, Name

AID

Application APDU

APDU Procedure Call

Data Access Control

Delegated Commands

Exported Methods

Access Control Lists

File Locks

Byte Code Image Size in Bytes

  • SCADA Online Example

4591

6802

1753

260

  • Dhrystones Benchmark

18781

23522

4461

977

Performance in Dhrystones/Second

1.27

1.37

  

Summary

While it may be hard to conclude from the preceding discussion, things are actually getting better for the smart card application developer. Most, if not all of the Java cards are being brought into cross-compatibility. The ETSI SCP series of smart card standards yield interoperable cards—not just standards-compliance marketing claims. And smart cards with multitasking operating systems on 32-bit chips have been announced. Whether or not card issuers turn to the third-party application development community for applications is solely a function of how compelling and innovative the applications created by that community are. This is progress.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.204.102