Sunteți pe pagina 1din 65

Guidelines for Developing Java Card

Applications on GlobalPlatform Cards


Version 1.0
December 2002

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

Trademarks
Java Card is a registered trademark of Sun Microsystems, Inc.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

Table of Contents

1.

OVERVIEW..............................................................................................................................................5
1.1.
1.2.

2.

PURPOSE OF THIS DOCUMENT ..............................................................................................................5


ADVANTAGES OF USING GLOBALPLATFORM FUNCTIONALITY ............................................................5

USING GLOBALPLATFORM SECURE CHANNELS.......................................................................6


2.1. GLOBALPLATFORM SECURE CHANNELS ..............................................................................................6
2.2. USING A GLOBALPLATFORM SECURE CHANNEL ..................................................................................7
2.2.1.
Retrieving a Security Channel Handle........................................................................................7
2.2.2.
Initiating a Secure Channel ........................................................................................................7
2.2.3.
Terminating a Secure Channel ...................................................................................................9
2.2.4.
Unwrapping Commands ...........................................................................................................10
2.2.5.
Wrapping responses..................................................................................................................11
2.2.6.
Decrypting and Verifying Keys .................................................................................................11
2.2.7.
Decrypting Secret Data.............................................................................................................13

3.

USING AND MANAGING A PIN ........................................................................................................14


3.1. GLOBALPLATFORM CVM..................................................................................................................14
3.2. USING GLOBALPLATFORM CVM.......................................................................................................14
3.2.1.
Verifying the CVM Management Privilege ...............................................................................14
3.2.2.
Managing the CVM State..........................................................................................................15
3.2.3.
Verifying the PIN value being presented ..................................................................................15
3.2.4.
Changing the PIN value............................................................................................................16

4.

USING CARD AND APPLICATION LIFE CYCLE STATES .........................................................18


4.1. GLOBALPLATFORM APPLICATION LIFE CYCLE STATES .....................................................................18
4.2. EXAMPLES OF APPLICATION SPECIFIC LIFE CYCLE STATES ................................................................19
4.2.1.
PERSONALIZED state..............................................................................................................19
4.2.2.
BLOCKED state........................................................................................................................19
4.3. SETTING APPLICATION LIFE CYCLE STATES ON JAVA CARD .............................................................19
4.4. RETRIEVING CARD LIFE CYCLE STATES ............................................................................................20
4.5. SETTING CARD LIFE CYCLE STATES ..................................................................................................21

5.

APPLICATION RISK MANAGEMENT USING CARD AND APPLICATION LIFE CYCLE...22


5.1. OVERVIEW .........................................................................................................................................22
5.2. INTRODUCTION TO RISK MANAGEMENT ............................................................................................22
5.3. SAMPLE APPLICATION .......................................................................................................................23
5.4. CARD LIFE CYCLE STATES.................................................................................................................23
5.5. APPLICATION LIFE CYCLE STATES.....................................................................................................24
5.6. USING APPLICATION LIFE CYCLE STATES FOR APPLICATION RISK MANAGEMENT............................24
5.6.1.
SELECTABLE Life Cycle State.................................................................................................24
5.6.2.
PERSONALIZED Life Cycle State ............................................................................................26
5.6.3.
BLOCKED Life Cycle State ......................................................................................................27
5.7. USING CARD LIFE CYCLE STATES FOR APPLICATION RISK MANAGEMENT........................................28
5.7.1.
The OP_READY and INITIALIZED Life Cycle States..............................................................28
5.7.2.
SECURED Life Cycle State.......................................................................................................29
5.7.3.
Loyalty Application Coding ......................................................................................................29

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

6.

JAVA CARD 2.1 USAGE REQUIREMENTS.....................................................................................32


6.1. INSTALL() METHOD ............................................................................................................................32
6.2. SELECT() METHOD .............................................................................................................................34
6.3. DESELECT() METHOD .........................................................................................................................35
6.4. PROCESS() METHOD ...........................................................................................................................35
6.4.1.
SELECT command processing..................................................................................................35
6.4.2.
Case 2 APDU commands on T=0 cards ...................................................................................37

7.

JAVA CARD RESOURCE CONSIDERATIONS...............................................................................38


7.1.
7.2.

8.

COMMIT BUFFER................................................................................................................................38
TRANSIENT MEMORY.........................................................................................................................39

GLOBALPLATFORM APIS ................................................................................................................40

APPENDIX A.1 SAMPLE APPLICATION (USING THE 2.1 API)......................................................43


APPENDIX A.2 SAMPLE APPLICATION (USING THE DEPRECATED API) ...............................50
APPENDIX B.1 LOYALTY APPLICATION (USING THE 2.1 API) ...................................................57
APPENDIX B.2 LOYALTY APPLICATION (USING THE DEPRECATED API).............................61

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

1.
1.1.

Overview
Purpose of this Document
The purpose of this document is to offer guidelines for developers who are
writing applications for Java Cards compliant to the GlobalPlatform Card
Specification Version 2.1.
The advantage of using GlobalPlatform functionality is explained, as are some
special requirements and restrictions that are specific to GlobalPlatform Java
Card based implementations. Information in this document focuses on smart
cards that implement Java Card 2.1.1 specifications and GlobalPlatform
Card Specification version 2.1 which supports both the 2.0.1 (Deprecated)
and 2.1 API.
The sample code and examples provided in this document are shown using
both the New and Deprecated API. The next version of this document will also
include examples that are leveraging the functionality provided only by the 2.1
API.

1.2.

Advantages of Using GlobalPlatform Functionality


Although applications need not use the underlying GlobalPlatform
functionality in order to be fully functional on a GlobalPlatform card, there are
many significant advantages to be achieved when an application does use this
functionality.

Using a GlobalPlatform Secure Channel (e.g. during personalization)


allows an application to minimize its own code size by leveraging the
cards platform security mechanisms and minimizes the impact on
systems using the standardized secure communication protocols.

Using the GlobalPlatform Life Cycle State management gives an


application the advantage of making its Life Cycle State available to
off-card management systems in a standardized manner through
Issuer Security Domain commands. It also provides useful functionality
for supporting application specific risk management policies and
implementing associated enforcement mechanisms.

Using the GlobalPlatform CVM (Global PIN in the deprecated API) in


applications that employ a user PIN can simplify the application itself,
and can increase card usability by having a common PIN for multiple
applications.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

2.
2.1.

Using GlobalPlatform Secure Channels


GlobalPlatform Secure Channels
GlobalPlatform Secure Channels may be used by an Application whenever
secure communication is required. Although applications are free to
implement their own secure communication mechanism, there is a significant
advantage for an application to use a GlobalPlatform Secure Channel during
its process, especially during personalization.
In order to minimize their impact to personalization systems, it is
recommended that applications leverage the GlobalPlatform Secure Channel
interface defined in GlobalPlatform Card Specifications. This is because the
personalization system that installed the application will already itself have
implemented the mechanism to employ one of the GlobalPlatform Secure
Channel Protocols.
Note that the advantage of using a GlobalPlatform Secure Channel for
personalization also minimizes the code size of an application in that code
would not be required for implementing specific security mechanism.
Applications can realize further advantages for themselves by using
GlobalPlatform Secure Channels in other cases requiring secure
communication. Using GlobalPlatform Secure Channels for all secure
communication allows even more compact applications to be developed. Such
applications can be relieved of having to implement their own cryptographic
functions: the Security Domain will manage all cryptographic functionality,
the checking of the sequence of events, and responding with the relevant
errors. Furthermore, using GlobalPlatform Secure Channels will assure that a
standard and acceptable level of security has been attained by the application.
The advantages of GlobalPlatform Secure Channels for purposes other than
personalization must be measured against the impact it may have on key
management. Note that GlobalPlatform Secure Channels can only be used
with the keys of a Security Domain. The Application Provider security policy
may request to use other keys for secure communication to the application
during its operational phase.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

2.2.

Using a GlobalPlatform Secure Channel


2.2.1.

Retrieving a Security Channel Handle


In order to use the Secure Channel, the application must first obtain a handle
to its associated Security Domain. As it is possible for an Application to be
extradited from one Security Domain to another, the handle to the Security
Domain should be retrieved each time the Application is selected.
The Sample Application extract below shows the getSecureChannel() method
(getSecurityDomain() method in the deprecated API) being invoked during the
selection process of the application.

2.1 API:
private SecureChannel MySecureChannel;
...
public boolean select() {
MySecureChannel = GPSystem.getSecureChannel();
...
Deprecated API:
private ProviderSecurityDomain SecurityDomain;
...
public boolean select() {
SecurityDomain = OPSystem.getSecurityDomain();
...
2.2.2.

Initiating a Secure Channel


In order to actually use a Secure Channel, it has to be opened and the external
entity must be authenticated. Following these steps, the Secure Channel is
initiated and can be used by the application until either:

A new Secure Channel is opened,

The application is de-selected,

The card is reset or powered off,

The application explicitly closes the Secure Channel; or

An erroneous cryptographic protection occurs on a message.

In the explicit initiation mode of a Secure Channel, the P1 byte of the


EXTERNAL AUTHENTICATE command establishes the Security Level of the
Secure Channel Session being initiated. It is the responsibility of the
Application to verify that the Security Level has been set
appropriately. For example, an application may want to require that the
Security Level be set to C-MAC, in other words requiring that a MAC be
present for all commands received within a Secure Channel Session. It is
Copyright 2002 GlobalPlatform Inc. All Rights Reserved.
The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

important that the Application performs this check as the Security Domain will
not perform any checks over and above its own security policy as defined by its
owner (the Issuer or Application Provider). If the Security Domain security
policy does not require the presence of a C-MAC, when the Security Level
defined in the EXTERNAL AUTHENTICATE command indicates no Secure
Messaging (i.e. P1 parameter set to zero), there will be no secure messaging
checking by the Security Domain on subsequent commands, even if the Class
byte on a subsequent command has its bit 3 set to 1 (e.g. Class byte = 0x04 or
0x84).
Implicit Initiation mode: to be completed.
If an application wants to ensure that a command contains secure messaging
and that the command cryptographic protection is actually verified by the
Security Domain, the application must check the Security Level of the current
Secure Channel Session using the getSecurityLevel() method (no equivalent
method in the deprecated API beyond the application checking the value of P1
of the EXTERNAL AUTHENTICATE command). In other words, verifying that
the Class byte of a command has its bit 3 set to 1 is not sufficient by itself.
The Sample Application extract below shows the invocation of the
processSecurity() method (openSecureChannel() and
verifyExternalAuthenticate() methods in the deprecated API) for processing
the Secure Channel Protocol commands, regardless of the Secure Channel
Protocol supported by the Security Domain (SCP 01 or SCP 02). Please note
that in the deprecated API, the two Secure Channel Protocol commands:
INITIALIZE UPDATE and EXTERNAL AUTHENTICATE, must be recognized
by the application before being processed by the appropriate method.
2.1 API:
public void process( APDU apdu ) {
...
switch ( buffer[ISO7816.OFFSET_INS] ) {
// other commands recognized by the applet...
default: SCPcommands( apdu );
break;
}
return;
...
void SCPcommands ( APDU apdu ) {
responseLength = MySecureChannel.processSecurity( apdu );
if (responseLength != 0)
apdu.setOutgoingAndSend((short) ISO7816.OFFSET_CDATA, responseLength);
}

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

Deprecated API:
final static byte INS_INITIALIZE_UPDATE = (byte) 0x50;
...
public void process( APDU apdu ) {
...
switch ( buffer[ISO7816.OFFSET_INS] ) {
// other commands recognized by the applet...
case (byte) INS_INITIALIZE_UPDATE: initializeUpdate( apdu );
break;
case (byte) ISO7816.INS_EXTERNAL_AUTHENTICATE:
externalAuthenticate( apdu );
break;
default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
break;
}
return;
...
void initializeUpdate ( APDU apdu ) {
apdu.setIncomingAndReceive();
byte[] buffer = apdu.getBuffer();
channel = SecurityDomain.openSecureChannel( apdu );
short responseLength = buffer[ISO7816.OFFSET_LC];
apdu.setOutgoingAndSend((short) ISO7816.OFFSET_CDATA, responseLength);
}
...
void externalAuthenticate ( APDU apdu ) {
apdu.setIncomingAndReceive();
byte[] buffer = apdu.getBuffer();
SecurityDomain.verifyExternalAuthenticate( channel, apdu );
}
2.2.3.

Terminating a Secure Channel


If an application uses a GlobalPlatform Secure Channel, it should also
implement a deselect() method that will cause the Secure Channel Session to
close when a new SELECT command is received, as shown in the Sample
Application extract below..

2.1 API:
public void deselect() {
MySecureChannel.resetSecurity();
}
Deprecated API:
public void deselect() {
SecurityDomain.closeSecureChannel(channel);
}

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

10

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

2.2.4.

Unwrapping Commands
The application and the off-card entity must be synchronized as to which
commands contain secure messaging and which do not. Once a Secure Channel
Session has been initiated with a Security Level that indicates Secure
Messaging, the application can assume that any cryptographically protected
command received will be correctly unwrapped, its cryptographic protection
verified or, if not, the appropriate error response will be returned. If the
correct level of Secure Messaging has been applied to the command by the offcard entity, the unwrap() method will strip the command of its Secure
Messaging information, and present it back to the application for processing.
The following Sample Application extract demonstrates the use of unwrap()
method during personalization of the application .

2.1 API:
final static byte CLA_Proprietary_Secured = (byte) 0x84;
...
void personalize( APDU apdu ) {
...
byte[] buffer = apdu.getBuffer();
if( buffer[ ISO7816.OFFSET_CLA ] != CLA_Proprietary_Secured )
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
wrappedLength = apdu.setIncomingAndReceive();
MySecureChannel.unwrap(buffer, (short) ISO7816.OFFSET_CLA,
(short) (wrappedLength+5));
...
Deprecated API:
final static byte CLA_Proprietary_Secured = (byte) 0x84;
...
void personalize( APDU apdu ) {
...
byte[] buffer = apdu.getBuffer();
if( buffer[ ISO7816.OFFSET_CLA ] != CLA_Proprietary_Secured )
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
apdu.setIncomingAndReceive();
SecurityDomain.unwrap(channel, apdu);
...
The above extract shows the case where the unwrapping of commands is
required during personalization. The Sample Application extract below shows
the unwrapping of the Change PIN command, when secure messaging is
indicated in the Class byte of the command header (i.e. bit 3 set to 1).

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

11

2.1 API:
void changePIN( APDU apdu ) {
...
byte[] buffer = apdu.getBuffer();
wrappedLength = apdu.setIncomingAndReceive();
if( buffer[ ISO7816.OFFSET_CLA ] == CLA_Proprietary_Secured ) {
MySecureChannel.unwrap(buffer, (short) ISO7816.OFFSET_CLA,
(short) (wrappedLength+5));
MyPIN.update(buffer, (short) ISO7816.OFFSET_CDATA,
buffer[ISO7816.OFFSET_LC], CVM.FORMAT_HEX);
...
Deprecated API:
void changePIN( APDU apdu ) {
...
byte[] buffer = apdu.getBuffer();
apdu.setIncomingAndReceive();
if( buffer[ ISO7816.OFFSET_CLA ] == CLA_Proprietary_Secured )
SecurityDomain.unwrap(channel, apdu);
OPSystem.setPin( apdu, ISO7816.OFFSET_CDATA );
...
2.2.5.

Wrapping responses
To be completed

2.2.6.

Decrypting and Verifying Keys


The application can also choose to load encrypted application specific keys
through the Secure Channel. The decryptData() method (decryptVerifyKey()
method in the deprecated API) is available to decrypt the content of a key
block. The decryption performed by this method is over and above any
encryption that may have been removed by unwrapping the command
message.
In the deprecated API only, depending on the key algorithm (e.g. 0x81)
indicated in the command (see for instance GlobalPlatform PUT KEY
command), the decryptVerifyKey() method will attempt to verify a supplied key
check value. However, the decryptVerifyKey() method will return the
decrypted data (i.e. the data block resulting from the decryption operation)
even if the verification of the supplied key check value fails. Application
developers should be aware that velocity checking may have been implemented
on the card, and multiple key check value verification failures may cause the
underlying key encryption key (KEK) and key set to be locked.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

12

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

The Sample Application extract below shows an application specific key block
being decrypted during the application personalization process. In this
example, the application specific key is presented to the card with the
GlobalPlatform PUT KEY command and a key check value, where the key
check value is formed of the 3 high order bytes resulting from encrypting a
block of 8 bytes of zeroes.
2.1 API:
private static DESKey verifKey;
private static Cipher DESInstance;
...
verifKey = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES_TRANSIENT_DESELECT,
KeyBuilder.LENGTH_DES, false);
DESInstance = Cipher.getInstance(Cipher.ALG_DES_ECB_NOPAD, false);
...
boolean verifyKeyCheckValue (byte[] buffer, short keyOffset,
short checkValueOffset) {
byte[] checkValue = new byte[8];
Util.arrayFillNonAtomic(checkValue, (short) 0, (short) 8, (byte) 0 );
verifKey.setKey(buffer, keyOffset);
DESInstance.init(verifKey, Cipher.MODE_ENCRYPT);
DESInstance.doFinal(checkValue, (short) 0, (short) 8, checkValue,
(short) 0);
return (Util.arrayCompare(checkValue, (short) 0, buffer,
checkValueOffset, (short) 3) == (byte) 0);
}
...
void personalize( APDU apdu ) {
...
wrappedLength = apdu.setIncomingAndReceive();
MySecureChannel.unwrap(buffer, (short) ISO7816.OFFSET_CLA,
(short) (wrappedLength+5));
MySecureChannel.decryptData(buffer, (short) (ISO7816.OFFSET_CDATA+3),
(short) (buffer[ISO7816.OFFSET_CDATA+2]) );
if (verifyKeyCheckValue(buffer, (short) (ISO7816.OFFSET_CDATA+3),
(short)(ISO7816.OFFSET_CDATA+4 + buffer[ISO7816.OFFSET_CDATA+2]) )
appletKey.setKey(buffer, (short) (ISO7816.OFFSET_CDATA+3));
...
Deprecated API:
void personalize( APDU apdu ) {
...
apdu.setIncomingAndReceive();
SecurityDomain.unwrap(channel, apdu);
if (SecurityDomain.decryptVerifyKey(channel,apdu,
(short)(ISO7816.OFFSET_CDATA+1))))
appletKey.setKey(buffer, (short)(ISO7816.OFFSET_CDATA+3));
...

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

2.2.7.

13

Decrypting Secret Data


The application can also request that its associated Security Domain decrypt
secret data if a Secure Channel Session exists. This data does not necessarily
have to be keys but can be any data that requires confidentiality. An example
is the PIN value. The decryptData() method is intended for such usage.
In the deprecated API, the decryptVerifyKey() method may also be used, with
the restriction indicated above regarding to key check values and eventual
velocity checking.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

14

3.

Using and Managing a PIN

3.1.

GlobalPlatform CVM
The GlobalPlatform CVM (or Global PIN in the deprecated API) functionality
is available on GlobalPlatform compliant cards as an option. GlobalPlatform
CVM provides a simple interface to a CVM data structure, and the controls
surrounding the CVM. Using this GlobalPlatform interface minimizes the
applications code by relieving the application from implementing PIN
management functions within its own code. It also improves the overall card
usability, since a common PIN may be used by multiple applications. Currently
the only supported CVM is a PIN.
An application may require the ability not only to verify that the CVM (PIN)
has been correctly presented, but may also require the ability to alter the value
of the CVM (PIN) block. If this is the case, the application must be installed
with the relevant CVM Management privilege, and the application should
contain code to verify that it is being installed with the required privilege. As
an enhancement to GlobalPlatform 2.0.1, GlobalPlatform 2.1 provides
additional CVM functionality that allows an application to set the maximum
retry limit as well as allowing an application to check if the PIN has been
previously presented within the current Card Session.

3.2.

Using GlobalPlatform CVM


3.2.1.

Verifying the CVM Management Privilege


The Sample Application extract below shows the checking of the Application
Privileges during installation to ensure that the application is being installed
with the required privilege.

2.1 API:
final static byte CVM_Management_Privilege = (byte) 0x02;
private CVM MyPIN;
...
public static void install(byte[] buffer, short offset, byte length) {
byte instanceLength = (byte) buffer[offset];
short instanceOffset = (short)(offset + 1);
byte appletPrivileges = (byte) buffer[
(short) (offset+1+instanceLength+1)];
if( appletPrivileges != CVM_Management_Privilege )
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
MyPIN = GPSystem.getCVM(GPSystem.CVM_GLOBAL_PIN);
if ( MyPIN == null )
ISOException.throwIt(Util.makeShort((byte) 0x6A, (byte) 0x88));
...
Copyright 2002 GlobalPlatform Inc. All Rights Reserved.
The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

15

Deprecated API:
final static byte PIN_Change_Privilege = (byte) 0x02;
...
public static void install(byte[] buffer, short offset, byte length) {
byte instanceLength = (byte) buffer[offset];
short instanceOffset = (short)(offset + 1);
byte appletPrivileges = (byte) buffer[
(short) (offset+1+instanceLength+1)];
if( appletPrivileges != PIN_Change_Privilege ) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
...
See section 6.1 - Install() method for more information on the parameters of the
install() method.

3.2.2.

Managing the CVM State


The Sample Application extract below shows the invocation of the resetState()
method (no equivalent method in the deprecated API). In this example, the
application requires that the CVM be systematically (re)presented to the
application and the CVM State is reset on application selection, regardless if
the CVM has been previously presented (and successfully verified or not)
during the current card session.

2.1 API:
public boolean select() {
...
MyPIN.resetState();
...
Deprecated API:
public boolean select() {
...
PINPresented = false;
...

3.2.3.

Verifying the PIN value being presented


The Sample Application extract below shows the invocation of the verify()
method (verifyPin() method in the deprecated API) for verifying the PIN being
presented. As defined in ISO7816-4, this method also details how:

an application would return the number of retries remaining to the


interface device in the event that the PIN verification failed.

a totally different response is returned, prior to attempting to perform the


verification, if no retries remain for the PIN.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

16

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

2.1 API:
void presentPIN( APDU apdu ) {
...
if ( MyPIN.isBlocked() )
ISOException.throwIt(Util.makeShort( (byte) 0x69, (byte) 0x83));
byte[] buffer = apdu.getBuffer();
wrappedLength = apdu.setIncomingAndReceive();
...
MyPIN.verify(buffer, (short) ISO7816.OFFSET_CDATA,
buffer[ISO7816.OFFSET_LC], CVM.FORMAT_HEX);
if ( !MyPIN.isVerified() ) {
byte triesRemaining = (byte) (MyPIN.getTriesRemaining() |
(byte) 0xc0);
ISOException.throwIt(Util.makeShort( (byte) 0x63, triesRemaining));
...

Deprecated API:
void presentPIN( APDU apdu ) {
...
if( OPSystem.getTriesRemaining() == 0 )
ISOException.throwIt(Util.makeShort( (byte) 0x69, (byte) 0x83));
byte[] buffer = apdu.getBuffer();
apdu.setIncomingAndReceive();
...
if( OPSystem.verifyPin( apdu, ISO7816.OFFSET_CDATA )){
PINPresented = true;
} else {
PINPresented = false;
byte triesRemaining = (byte) (OPSystem.getTriesRemaining() |
(byte) 0xc0);
ISOException.throwIt(Util.makeShort( (byte) 0x63, triesRemaining));
...

3.2.4.

Changing the PIN value


The Sample Application extract below shows the invocation of the update()
method (setPin() method in the deprecated API) for changing the value of the
PIN. Note that this example demonstrates an extra and application specific
requirement that the correct value of the previous PIN has been previously
presented and successfully verified.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

17

2.1 API:
void changePIN( APDU apdu ) {
if ( !MyPIN.isVerified() )
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
byte[] buffer = apdu.getBuffer();
wrappedLength = apdu.setIncomingAndReceive();
...
MyPIN.update(buffer, (short) ISO7816.OFFSET_CDATA,
buffer[ISO7816.OFFSET_LC], CVM.FORMAT_HEX);
...
Deprecated API:
void changePIN( APDU apdu ) {
if ( PINPresented != true )
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
byte[] buffer = apdu.getBuffer();
apdu.setIncomingAndReceive();
...
OPSystem.setPin( apdu, ISO7816.OFFSET_CDATA );
...

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

18

4.
4.1.

Using Card and Application Life Cycle States


GlobalPlatform Application Life Cycle States
Upon reception of an INSTALL [for make selectable] or [for install and make
selectable] command, the OPEN sets the Application Life Cycle State to
SELECTABLE. Thereafter, an application has the ability to manage its own
Life Cycle State. Typically an Application would transition its own Life Cycle
State once it has received all application specific data (e.g. PERSONALIZED as
defined in the deprecated API) and may later, depending on circumstances,
limit its functionality by transitioning to another Life Cycle State (e.g.
BLOCKED as defined in the deprecated API). While the deprecated API
defines the only possible Life Cycle States for an Application beyond
SELECTABLE, i.e.: PERSONALIZED and BLOCKED, the 2.1 API allows an
application to define its own Life Cycle States beyond SELECTABLE as long
as these do not interfere with the Life Cycle States defined in the specification
(i.e. INSTALLED, SELECTABLE, and LOCKED). Note that the OPEN does
not in any way limit the functionality of the application once it has been
selected immaterial of its Application Life Cycle State. It is the responsibility
of the application itself to limit or increase its own functionality as necessary.
Note that in order to prevent an application from being selected, it is the Issuer
Security Domain that must set the application state to LOCKED. This can be
done as a result of a SET STATUS command sent to the Issuer Security
Domain, and this state may be reversed only with another SET STATUS
command sent to the Issuer Security Domain.
Although the changing of the Application Life Cycle State by an application
does not alter the behavior of the OPEN in any way, using this GlobalPlatform
functionality does have the advantage of making the Application Life Cycle
State available through existing Issuer Security Domain commands (GET
STATUS), and can allow off-card management systems to access the
Application Life Cycle State in a standardized manner.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

4.2.

19

Examples of application specific Life Cycle States


Note the following examples of application specific Life Cycle State mirror the
deprecated API definition of Application Life Cycle States.
4.2.1.

PERSONALIZED state
The application must set its own state to PERSONALIZED from the
state SELECTABLE. This action has to be initiated by an APDU destined for
the application, and should be completed prior to the application being used in
its intended environment. Typically, the application sets its Life Cycle State to
PERSONALIZED after it has received sufficient personalization information
(e.g. application specific keys and data).

4.2.2.

BLOCKED state
An application can transition its Life Cycle State to BLOCKED in the case
where it might want to limit some of its functionality. This could be either
before or after the application had reached the PERSONALIZED state.
It is the application itself that has the responsibility to limit its own
functionality when in the BLOCKED state.
Once in the state BLOCKED, the application may contain functionality that
allows it to return to its Life Cycle State prior to being set to the BLOCKED
state.

4.3.

Setting Application Life Cycle States on Java Card


The application can set its own Life Cycle State at any time following its
installation (i.e. subsequent to the successful completion of the install()
method) and once it is made selectable (i.e. its Life Cycle State is set to
SELECTABLE).
The Sample Application extract below shows the invocation of the
setCardContentState() method during the personalization of the application,
limited in this example to the personalization of application specific keys.
Obviously the personalization procedure would typically contain additional
code populating application specific data fields or initializing application
specific key information.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

20

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

2.1 API:
final static byte APPLET_PERSONALIZED = (byte) 0x0F;
...
void personalize( APDU apdu ) {
...
MySecureChannel.decryptData(buffer, (short) (ISO7816.OFFSET_CDATA+3),
(short) (buffer[ISO7816.OFFSET_CDATA+2]) );
if (verifyKeyCheckValue(buffer, (short) (ISO7816.OFFSET_CDATA+3),
(short)(ISO7816.OFFSET_CDATA+4 + buffer[ISO7816.OFFSET_CDATA+2])){
appletKey.setKey(buffer, (short) (ISO7816.OFFSET_CDATA+3));
GPSystem.setCardContentState( APPLET_PERSONALIZED );
} else {
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
}
...
Deprecated API:
void personalize( APDU apdu ) {
...
if( SecurityDomain.decryptVerifyKey(channel,apdu,ISO7816.OFFSET_CDATA) ){
appletKey.setKey(buffer, (short)(ISO7816.OFFSET_CDATA+3));
OPSystem.setCardContentState( OPSystem.APPLET_PERSONALIZED );
} else {
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
}
...

4.4.

Retrieving Card Life Cycle States


Card Life Cycle States are managed by the OPEN. Applications always have
access to the current Card Life Cycle State. Chapter 5 illustrates how an
application may use the Card Life Cycle for its own risk management. The
Sample Application extract below shows the invocation of the getCardState()
method (getCardManagerState() method in the deprecated API) implementing
some enforcement mechanism after card issuance.

2.1 API:
if ((GPSystem.getCardState()) == GPSystem.CARD_SECURED ) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
...
Deprecated API:
if ((OPSystem.getCardManagerState()) == OPSystem.CARD_SECURED ) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
...

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

4.5.

21

Setting Card Life Cycle States


Privileged applications have the ability to change the Life Cycle State of the
card. This could be used in the event the application identifies what it deems to
be a security breach of the card and, as a result, decides to lock or terminate
the card.

Locking the card disables all applications on the card and allows only the
Issuer Security Domain to process commands. This state is reversible from
within the Issuer Security Domain.

Terminating the card disables the card to the extent that only the GET
DATA command is processed and this state is not reversible.

For applications with the required privileges, an API is available to set the Life
Cycle State of the card to CARD_LOCKED and another API is available to
terminate the card. If an application needs to exercise this functionality, it
should contain code to verify that it is being installed with the appropriate
privilege during its installation.
The Sample Application demonstrates a similar processing of Application
Privileges as it applies to the verification of the CVM Management privilege
(see section 3.2.1 - Verifying the CVM Management Privilege).

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

22

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

5.

Application Risk Management using Card and


Application Life Cycle

5.1.

Overview
This chapter describes how GlobalPlatform Life Cycle States may be applied to
implement application specific policies and risk management. The focus of this
chapter is on how Application Providers may implement risk management for
their specific application.

5.2.

Introduction to Risk Management


When an application is loaded onto a smart card, it goes through a sequence of
steps until it is finally ready to be used by the cardholder. In many cases these
steps are performed in a controlled environment, e.g. at a card manufacturers
site. Once the card is issued, it is beyond the control of the Card Issuer of what
the card and its applications are exposed to. At all times it is in the interest of
the Application Provider (assumed to be the application operator) to guard the
assets represented on the card. It can be assumed that the regular application
operation does not require specific actions or precautions. However incorrect
use of the card, fraud or cryptographic attacks are examples of situations
where the Application Provider / operator and / or Card Issuer may want to
implement special functionality to provide protection for their assets. On-card
as well as off-card enforcement mechanisms are required. Card Issuers and
Application Providers can make sure that operational policies are adhered to
and fraud is prevented. GlobalPlatform uses Card and Application Life Cycle to
support the implementation of this risk management. However it is the
responsibility of the individual Application Provider to implement the required
functionality. Applications may use Card Life Cycle States as well as
Application Life Cycle States to implement their risk management.
Card Life Cycle States defined by GlobalPlatform are:
OP_READY, INITIALIZED, SECURED, CARD_LOCKED (CM_LOCKED in
the deprecated API), TERMINATED.
Application Life Cycle States defined by GlobalPlatform are:
INSTALLED, SELECTABLE, LOCKED, and in the deprecated API only:
PERSONALIZED and BLOCKED.
See chapter 4 for using PERSONALIZED and BLOCKED states with the
deprecated API.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

5.3.

23

Sample Application
In order to illustrate the use of Life Cycle States for risk management an
example application is provided: a Loyalty Application. The Loyalty
Application will allow the cardholder to collect and redeem points stored on the
card. Collecting and redeeming points is achieved using commands that add or
subtract the requested value from the on-card value. For the purpose of this
document it is assumed that the card reader implements this application logic.
This focus of this document is to describe the on-card implementation.
The Loyalty Application implements:

5.4.

Loyalty points collection and redemption using two specific operational


commands: COLLECT and REDEEM. Card and Application Life Cycle
State information are used to determine the correct usage of these
commands and to enforce the corresponding risk management and
security policies.

Cardholder identification (verification of a Password) using the


VERIFY commandVelocity checking is used for risk management and
an Application Life Cycle State change is triggered when required.

Personalization using the STORE_DATA command. Card and


application Life Cycle State information is used to determine the
correct usage of this command and to enforce corresponding security
policies

Changing Application Life Cycle State of the application using the


SET_STATUS command.

Card Life Cycle States


Applications have access to the current Card Life Cycle State through the
GlobalPlatform API, see chapter 4 - Using Card and Application Life Cycle
States. The Card Life Cycle State may be used by the application for its risk
management, such as:

Execute and respond to a specific set of commands: Depending on the Card


Life Cycle State a specific sub-set of the application commands is executed:
e.g. personalization commands, operational commands.

Adapting authentication schemes: Depending on the Card Life Cycle State,


the same command may be sent to the card in the clear or protected with
secure messaging (e.g. with command data encrypted and/or protected with
a MAC).

It is not recommended that the application stores the Card Life Cycle State. As
the Card Life Cycle Sate may change at some point in time unknown to the
application, the Card Life Cycle State should be requested each time directly
from the GlobalPlatform API when needed.
Copyright 2002 GlobalPlatform Inc. All Rights Reserved.
The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

24

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

5.5.

Application Life Cycle States


The Application Life Cycle States INSTALLED, SELECTABLE and LOCKED
serve to implement card content management of applications. The Application
Life Cycle States SELECTABLE and application specific Life Cycle States
PERSONALIZED and BLOCKED enable the application to implement
application risk management according to the application specific
requirements.
The responsibilities for managing Application Life Cycle States INSTALLED
and LOCKED are beyond the responsibility of and not accessible to the
Application. The following discussion describes the application taking
responsibility for application specific Life Cycle States and also using Card Life
Cycle States for risk management.

5.6.

Using Application Life Cycle States for Application Risk


Management
The Loyalty Application being a loyalty application, regular operations will
consist of identifying the cardholder, collecting and redeeming loyalty points.
The Loyalty Application uses the Application Life Cycle States to implement
risk management policies and enforcement mechanisms as follows:

5.6.1.

SELECTABLE: In this Life Cycle State the application has been first
instantiated and made selectable.

PERSONALIZED: In this Life Cycle State the application is fully


operational. It executes and responds to all operational commands.

BLOCKED: In this Life Cycle State the application executes and


responds to a very limited set of commands only.

SELECTABLE Life Cycle State


The application does not yet have cryptographic material, which must be
populated during this Life Cycle State. The application personalization data
must also be populated. Both tasks require the application to request
cryptographic support from its corresponding Security Domain.
For the purpose of risk management the application implements the
enforcement mechanism to only execute and respond to commands used during
personalization. The personalization command this application uses is:
STORE_DATA. For Application Life Cycle State transitions the command
SET_STATUS is implemented, the only Life Cycle State transition allowed is
to PERSONALIZED.
The application does not determine by itself when personalization is complete,
rather it receives a SET_STATUS command to transition it to the next Life
Cycle State (PERSONALIZED) whenall personalization is completed.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

25

The following enforcement mechanisms are implemented in this


SELECTABLE state:

STORE_DATA checks if the application is in Life Cycle State


PERSONALIZED. Being an application personalization command, it is
only executed if the application has not been personalized yet. Further
personalization during the application life shall not be allowed.

SET_STATUS only allows a transition to PERSONALIZED.

The following Loyalty Application extract illustrates the enforcement


mechanism for the STORE_DATA command:
2.1 API:
if ((GPSystem.getCardContentState()) == GPSystem.APPLICATION_SELECTABLE){
// applet personalization code goes here...
} else {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
...
Deprecated API:
if ((OPSystem.getCardContentState()) == OPSystem.APPLET_SELECTABLE) {
// applet personalization code goes here...
} else {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
...
The following Loyalty Application extract illustrates the enforcement
mechanism for the SET_STATUS command:
2.1 API:
final static byte APPLET_PERSONALIZED = (byte) 0x0F;
...
byte bAppletLifeCycle = GPSystem.getCardContentState();
byte bNewAppletLifeCycle = buffer[ISO7816.OFFSET_P2];
if (bAppletLifeCycle == GPSystem.APPLICATION_SELECTABLE) {
if (bNewAppletLifeCycle != APPLET_PERSONALIZED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
}
...
Deprecated API:
byte bAppletLifeCycle = OPSystem.getCardContentState();
byte bNewAppletLifeCycle = buffer[ISO7816.OFFSET_P2];
if (bAppletLifeCycle == OPSystem.APPLET_SELECTABLE) {
if (bNewAppletLifeCycle != OPSystem.APPLET_PERSONALIZED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
}
...
Copyright 2002 GlobalPlatform Inc. All Rights Reserved.
The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

26

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

5.6.2.

PERSONALIZED Life Cycle State


In this Life Cycle State, the application is fully operational. It executes and
responds to all operational commands. The operational commands implement
the application specific security requirements and risk management. For the
purpose of risk management the application implements the enforcement
mechanism to only execute and respond to commands used for regular
operation: VERIFY enables cardholder identification, COLLECT adds loyalty
points and REDEEM subtracts loyalty points. As in the SELECTABLE state,
the command SET_STATUS is implemented for Life Cycle transitions. The
use of the STORE_DATA is prohibited.
Risk management may determine that a transition to the BLOCKED state is
appropriate.
This Loyalty Application implements the following rules:

The VERIFY command may present an incorrect Password too often. Once
the retry counter expires, the Application transitions its own Life Cycle
State to BLOCKED.

The COLLECT, REDEEM and VERIFY commands may only be used in the
PERSONALIZED Life Cycle State.

The transition from PERSONALIZED to BLOCKED may either be


performed implicitly as part of the application implementation or explicitly
by a command sent to the application on the card. In this Loyalty
Application, the Application Life Cycle State is transitioned from
PERSONALIZED to BLOCKED by the application itself as part of the
execution of the VERIFY command.

The following Loyalty Application extract illustrates the enforcement


mechanism for the VERIFY command:
2.1 API:
final static byte APPLET_BLOCKED = (byte) 0x7F;
...
check_CARD_SECURED();
if ((AppletPW.check(buffer, ISO7816.OFFSET_CDATA,
(byte)buffer[ISO7816.OFFSET_LC])) == false) {
if ((AppletPW.getTriesRemaining()) == (byte) 1) {
GPSystem.setCardContentState(APPLET_BLOCKED);
}
...
private void check_CARD_SECURED () {
if ((GPSystem.getCardState()) != GPSystem.CARD_SECURED ) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
}
...

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

27

Deprecated API:
check_CARD_SECURED();
if ((AppletPW.check(buffer, ISO7816.OFFSET_CDATA,
(byte)buffer[ISO7816.OFFSET_LC])) == false) {
if ((AppletPW.getTriesRemaining()) == (byte) 1) {
OPSystem.setCardContentState(OPSystem.APPLET_BLOCKED);
}
}
...
private void check_CARD_SECURED () {
if ((OPSystem.getCardManagerState()) != OPSystem.CARD_SECURED ) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
}
...
5.6.3.

BLOCKED Life Cycle State


In this Life Cycle State, the application executes and responds to a very limited
set of commands only. The application has been exposed to a situation (see
above) where risk management has determined that the regular operation of
the application must be discontinued. The situation should be resolved before
the Application Life Cycle State is transitioned back to PERSONALIZED.
The Application Life Cycle State will transition back to the Life Cycle State
PERSONALIZED when a SET STATUS command is received with proper
authentication.
The following Loyalty Application extract illustrates the enforcement
mechanism for the Application Life Cycle State transition:

2.1 API:
final static byte APPLET_PERSONALIZED = (byte) 0x0F;
final static byte APPLET_BLOCKED = (byte) 0x7F;
...
if (bAppletLifeCycle == APPLET_BLOCKED) {
if (bNewAppletLifeCycle != APPLET_PERSONALIZED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
}
GPSystem.setCardContentState(bNewAppletLifeCycle);
...
Deprecated API:
if (bAppletLifeCycle == OPSystem.APPLET_BLOCKED) {
if (bNewAppletLifeCycle != OPSystem.APPLET_PERSONALIZED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
}
OPSystem.setCardContentState(bNewAppletLifeCycle);
...

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

28

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

5.7.

Using Card Life Cycle States for Application Risk Management


An application may use the Card Life Cycle States to implement Card Life
Cycle dependant application specific risk management. For example:

5.7.1.

In OP_READY and INITIALIZED states, the application may consider


the card to be in a secured environment, e.g. a Card Issuer
personalization machine these are pre-issuance Card Life Cycle
States. The following conclusions may be drawn:
o

Only personalization commands need to be executed and


responded to,

Operational commands need to be rejected,

Cryptographic operations may be kept to a minimum e.g. only


used for sensitive data loading such as application specific keys.

In the SECURED Card Life Cycle State, the card has been issued to
the cardholder: it is a post-issuance Card Life Cycle State. The
following conclusions may be drawn:
o

If the application has not yet been personalized and


personalization commands are received, the data path is not
necessarily known it may be personalized over the Internet
and a GlobalPlatform Secure Channel should be used. Note
that this case is not shown in the Loyalty Application code
provided in Appendix B.

If the application has been personalized then only operational


command need to be executed and responded to.

In the CARD_LOCKED (CM_LOCKED in the deprecated API)


and TERMINATED Life Cycle States, the application will not
be selected and there is no need to reject commands.

The OP_READY and INITIALIZED Life Cycle States


The Card Life Cycle States OP_READY and INITIALIZED are pre-issuance
Life Cycle States. During these Life Cycle States, Load Files are loaded (unless
they are already pre-loaded, e.g. masked in ROM), applications are installed
and personalized. One can assume:

The card operates within a secure environment.

Only application specific installation and personalization functionality


is required.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

29

It should not be concluded from this that the application does not need any
security when processing commands during these Card Life Cycle States.
Rather, the application may assume commands received have been or are
generated by a known entity. Identifying and authenticating this entity once at
the beginning of the session e.g. of the personalization sequence can be
considered sufficient for the whole operation.
5.7.2.

SECURED Life Cycle State


The Card Life Cycle States SECURED, CARD_LOCKED (CM_LOCKED in the
deprecated API) and TERMINATED are post-issuance Life Cycle States.
Risk management in the SECURED Life Cycle State needs to take into account
that the card and the applications on the card may be exposed to commands of
unknown origin and with the possible intention of compromising the card or
any one of the applications. A conservative application implementation might
go as far as to consider each incoming command as a potential threat. It would
execute and respond to it only if proper security requirements are met. These
"proper security requirements" are application specific and are dependant on
the security policies of the Application Owner, Application Provider or
operator. Not every application on a given card has to implement the same
security requirements, which depend on the functionality the application
implements.
Once the application is loaded, installed and personalized and the card is
issued (i.e. in the SECURED Life Cycle State), the application responds to
operational commands. If an application is loaded post-issuance, then it needs
to respond to personalization commands in addition to the operational
commands. The implementation of the application security requirements would
typically be different and more stringent.

5.7.3.

Loyalty Application Coding


In this Loyalty Application, the risk management policies to be enforced are:

The application shall only be personalized pre-issuance.

It shall only be possible to redeem and collect loyalty points postissuance.

The personalization of this Loyalty Application consists of setting the


cardholder Password. After personalization is complete, the application is set
to the application specific Life Cycle State PERSONALIZED. The application
personalization sequence is as follows:

Set the application private Password for cardholder verification.

Transition the Application Life Cycle State from SELECTABLE to


PERSONALIZED.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

30

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

The Life Cycle related risk management policies are applied to the command
processing as follows:

If the Card Life Cycle State is SECURED, then COLLECT, REDEEM


and VERIFY commands can be executed.

If the Card Life Cycle State is not SECURED, the application only
executes pre-issuance personalization commands.
o

STORE_DATA is executed for the purpose of personalizing the


Password value;

Collecting and redeeming loyalty points are rejected.

In addition to the Card Life Cycle dependant risk management, the application
implements functional risk management policies. They are applied to the
command execution as follows:

COLLECT and REDEEM are executed only if the Password


presentation was successful.

Application Life Cycle State transition from BLOCKED to


PERSONALIZED is executed only if the Password presentation was
successful.

The following table gives an overview of all the Loyalty Application risk
management policies.
APDU
STORE_DATA
COLLECT

Function
Application
personalization
(set Password)
Add loyalty points

REDEEM

Use loyalty points

VERIFY

Perform cardholder
verification using
application Password

Risk Management
Card state: pre-issuance
Application state: selectable
Other: none
Card state: post-issuance
Application state: personalized
Other: Password verified
Card state: post-issuance
Application state: personalized
Other: Password verified
Card state: post-issuance
Application state: personalized
Other: Password verified

The following Loyalty Application extract illustrates the risk management


implementation for the COLLECT command.
private void cmd_COLLECT (APDU apdu) {
byte[] buffer = apdu.getBuffer();
byte bReadbytes = (byte)(apdu.setIncomingAndReceive());
check_CARD_SECURED();
check_PERSONALIZED();
check_PWVALIDATED();
sLoyaltyPoints = (short) (sLoyaltyPoints +
buffer[ISO7816.OFFSET_CDATA]);
}
Copyright 2002 GlobalPlatform Inc. All Rights Reserved.
The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

private void check_PWVALIDATED () {


if (AppletPW.isValidated() == false) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
}
2.1 API:
private void check_PERSONALIZED () {
if (GPSystem.getCardContentState() != APPLET_PERSONALIZED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
}
private void check_CARD_SECURED () {
if (GPSystem.getCardState() != GPSystem.CARD_SECURED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
}
Deprecated API:
private void check_PERSONALIZED () {
if (OPSystem.getCardContentState() != OPSystem.APPLET_PERSONALIZED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
}
private void check_CARD_SECURED () {
if (OPSystem.getCardManagerState() != OPSystem.CARD_SECURED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
}

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

31

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

32

6.

Java Card 2.1 Usage Requirements


A Java Card application extends the applet class and is expected to register
itself and receive APDU commands. It must therefore implement its own
install() and process() methods. Optionally, it may also implement its own
select() and deselect() methods.
There are certain additional requirements and restrictions that apply
specifically to Java Card applications written for a GlobalPlatform card. These
are requirements and restrictions that go beyond those specified in the Java
Card 2.1.1 specification. Application developers need to follow the
requirements below when implementing these methods.

6.1.

Install() method
The install method is responsible for instantiating the application, assigning
data space (if required) and registering the application. The parameters passed
to this method by a GlobalPlatform compliant runtime environment have the
following format:

Byte array
A buffer of unknown length and format containing at least the
following consecutive data:
Field
Length of instance AID
Instance AID
Length of application privileges
Application privileges
Length of application specific parameters
Application specific parameters

Length
1
5-16
1
1
1
variable

Offset
An offset within the buffer pointing to the length of the instance AID.

Length
A length indicating the length of all the above defined consecutive data
at least encompassing the application specific parameters.

The instance AID must be used by the application to register itself in the Open
Platform Registry. This is done by invoking the register( byte[] bArray, short
bOffset, byte bLength ) method and should be the last function performed prior
to the install() method returning control to the JCRE.
Copyright 2002 GlobalPlatform Inc. All Rights Reserved.
The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

33

The Applet class in the javacard.framework also contains a form of the


register() method which takes no parameters. Applications on GlobalPlatform
cards should not use that form of the register() method.
The constructor method of the Sample Application extract below demonstrates
how the AIDs position and length within the install parameters are
determined and registers the application with the instance AID.
protected Sample(byte[] buffer, short offset, byte length) {
byte instanceLength = (byte) buffer[offset];
...
register(buffer, (short)(offset + 1), instanceLength);

The install() method of the Sample Application extract below shows the
constructor method being called.
public static void install(byte[] buffer, short offset, byte length) {
new Sample(buffer, offset, length);

The handling of GlobalPlatform Application Privileges and application specific


Install Parameters depend on the functionality of the application, but if an
application requires that it be installed with particular privileges, the
Application Privileges byte should be checked in this method. See section 3.2.1
- Verifying the CVM Management Privilege for such an example.
GlobalPlatform methods that require access to the Open Platform Registry
may cause unpredictable behavior if invoked from within the install() method,
and for this reason must be avoided. All of the SecureChannel interface
methods (providerSecurityDomain interface methods in the deprecated API)
also need to be avoided. While these methods do not themselves require access
to the Open Platform Registry, they must be preceded by the
getSecureChannel() method (getSecurityDomain() method in the deprecated
API) which does. This recommendation goes hand in hand with the
requirement that the Java Card register() method be the last function
performed by the install() method.
On the other hand, the following list of GlobalPlatform methods can safely be
invoked from within the install() method:
2.1 API:
GPSystem.getCVM(), and
GPSystem.getCardState().
Deprecated API:
OPSystem.getTriesRemaining();
OPSystem.getCardManagerState(); and,
OPSystem.verifyPIN();

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

34

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

6.2.

Select() method
The application becomes the current context following the successful invocation
of the select() method of the application by the JCRE. This could occur either
through the receipt of a SELECT command or due to the application being the
default selectable application. The default select() method implementation
provided by the applet class returns true. If the application implements its
own select() method, proper care must be taken to ensure that the select()
method does not fail for any reason whatsoever (i.e. does not throw an
exception), and that this method also always returns true.
Throwing an exception in the select() method, or returning false from the
select() method, will prevent the JCRE from proceeding with the application
selection. The errors returned to the terminal by the JCRE in these cases are
Java Card specific (not defined by ISO 7816-4).
If it is desired to prevent an application instance from being selected, a SET
STATUS command should be sent to the Issuer Security Domain to change the
Life Cycle State for that application instance to LOCKED.
The select() method of the Sample Application extract below has no conditions
which would cause this method to return false.

2.1 API:
public boolean select() {
MySecureChannel = GPSystem.getSecureChannel();
MyPIN.resetState();
return true;
}
...
Deprecated API:
public boolean select() {
SecurityDomain = OPSystem.getSecurityDomain();
PINPresented = false;
return true;
}
...

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

6.3.

35

Deselect() method
If a application has established a GlobalPlatform Secure Channel Session, it
must invoke the resetSecurity() method (closeSecureChannel() method in the
deprecated API) in its deselect() method. This is to ensure that the Secure
Channel Session will not be available to a different application that might be
selected.

2.1 API:
public void deselect() {
MySecureChannel.resetSecurity();
}
Deprecated API:
public void deselect() {
closeSecureChannel(channel);
}

6.4.

Process() method
When the application is the current context (i.e. selected), all APDU commands
are directed by the JCRE to the process() method of the application.
6.4.1.

SELECT command processing


Exactly how the application handles its own APDU commands is application
specific, but there are specific requirements for handling SELECT commands.
In addition, an application, whether explicitly or implicitly selected, is
responsible for correctly managing spurious SELECT commands.
Spurious SELECT commands are SELECT type commands that could not be
successfully processed by the runtime environment, i.e. unexpected P1 and/or
P2 or the AID is not present in the Open Platform Registry. The runtime
environment would direct these spurious SELECT commands to the currently
selected application on the assumption that the application may expect and
know how to manage this command.
Even though the application may have no use for these spurious SELECT
commands, the application is responsible for handling them appropriately. The
first thing the application must do is to determine if the SELECT command
was actually destined for the application directly following the application
becoming the current context. This is simple to do by invoking the
selectingApplet() method.
If this method returns true, application specific processing can continue.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

36

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

If this method returns false, the application must first determine if it has
knowledge on how to handle the particular SELECT command (also
application specific) else it must return one of the following errors: 67 00 invalid length, 6A 86 - invalid P1/P2, 6A 81- function not supported or 6A 82
- application/file not found.
The Sample Application extract shown below provides a simple example of
spurious SELECT command management.
An EMV compliant application responding to a successful SELECT command
with an FCI containing the DF name (AID) of the application, must ensure
that the full AID is being returned. An application developer has 2 options:

Construct the FCI during the installation process using the instance AID
as the DF name; or,

Invoke the getAID() method while processing the SELECT command and
use this object for the DF name.

The developer must not use the AID of the data field of the command message
as the received SELECT command may have the partial select option set. In
this case the full AID may not be present in the data field.
The Sample Application extract below shows the coding of the second option
above.
void processSelect( APDU apdu ) {
if( !selectingApplet() ) {
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
}
apdu.setIncomingAndReceive();
byte[] buffer = apdu.getBuffer();
short offset = ISO7816.OFFSET_CDATA;
short AIDLength =
JCSystem.getAID().getBytes(buffer, (short)(offset+4));
buffer[offset] = (byte) FCI_Template;
buffer[offset+1] = (byte)(4+AIDLength);
buffer[offset+2] = (byte) AID_Tag;
buffer[offset+3] = (byte) AIDLength;
buffer[offset+4+AIDLength] = (byte) Proprietary_Data_Template;
apdu.setOutgoingAndSend( (short) ISO7816.OFFSET_CDATA,
(short) (6+AIDLength) );
}

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

6.4.2.

37

Case 2 APDU commands on T=0 cards


There is a special requirement for the process() method that is specific to case 2
APDU commands with Le=0 on some T=0 cards. This requirement applies to
those commands that might yield unexpected results if they were to be
executed multiple times. It solves a problem that is caused by the way some
JCRE implementations handle these APDU commands.
On a T=0 card, if an application receives and successfully executes a case 2
command where Le=0 and then returns data as a result, the JCRE will
currently return a result code of 6CXX to the terminal, where XX is the byte
length of the data that the application had returned to the JCRE. The
terminal, following IS0-7816 specifications, will then re-issue the command
with Le=XX. Unfortunately, this new APDU will then be passed by some
JCRE implementations to the application process() method again. This will
cause the command to execute for a second time, unless the application has
taken special precautions.
The best solution to this problem is for Java Card applications to do the
following: Check that if the protocol is T=0, and if the command is a case 2
APDU, and if Le =0, then return a 6CXX error without executing the
command. The terminal will re-issue the command with the correct Le, and
the application can then execute it and return the data without risk of having
the command executed multiple times.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

38

7.

Java Card Resource Considerations


In all smart card programming, developers must be careful how they allocate
or use limited memory resources. On Java Card, there are two resources that
require particular care in using: the commit buffer, and transient memory.

7.1.

Commit Buffer
Transactions on a Java Card are usually bracketed by application calls to
JCSystem.beginTransaction() and JCSystem.commitTransaction(). The JCRE
maintains an atomic transaction commit buffer. During a transaction, the
JCRE journal changes to persistent memory in this buffer so that it can
guarantee the atomicity of the transaction. The commit buffer is contained in
persistent memory, but is usually limited to a few hundred bytes. The amount
of overhead required to journal any particular change to persistent memory is
implementation specific, so it is difficult to determine how much of the commit
buffer a given transaction will use.
The following are several techniques that may help to reduce usage of the
commit buffer.

arrayCopy() is very expensive inside a transaction. When arrayCopy()


is used inside a transaction, the JCRE must log each element of the
array separately. This requires 4 or more bytes of header information
to be logged for each element that is changed. Try using
arrayCopyNonAtomic() instead, but be aware that
arrayCopyNonAtomic () executes completely outside of the transaction
subsytem and that changes to persistent memory by
arrayCopyNonAtomic() may not be rolled-back even if the transaction
aborts.

Be sure to put new calls inside transaction brackets, instead of before


them. That way, updates to newly created objects will not need to be
logged.

For commands that update an extensive amount of data, consider


having the application manage the transaction state itself.

Be aware that many JCRE implementations also use the commit buffer to
journal changes made during the install() method. Developers need to be
particularly careful not to cause the commit buffer to overflow during the
install() method, since this will make it impossible to install the application.
Some implementations may require more than 8 bytes of the commit buffer to
journal each new operation. Therefore, designing an application with
extremely complex objects that need to be instantiated may prevent the
application from being installed on some cards.
Copyright 2002 GlobalPlatform Inc. All Rights Reserved.
The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

7.2.

39

Transient Memory.
Transient Objects, although normally allocated in RAM, are guaranteed to
continue to exist so long as they can be referenced. The description transient
more accurately refers to the data contents of the object, which may be cleared,
rather than the object itself. The area of RAM allocated in a given application
for a Transient Object may not be available for use by other applications on the
card.

Since most Java Card implementations do not implement dynamic runtime


garbage collection, it is possible for an application to leak RAM. This is
because a Transient Object may continue to exist and occupy scarce RAM even
after it can no longer be referenced. On some cards the only way to recover the
area of RAM allocated to a Transient Object is to delete the entire application
itself. Therefore, Transient Objects should be allocated with the same
considerations that apply to allocating other persistent objects.

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

40

8.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

GlobalPlatform APIs
This chapter describes the mapping of GlobalPlatform Deprecated API onto
GlobalPlatform 2.1 API.
The export and related files for the 2.1 API can be obtained from
GlobalPlatform website (http://www.globalplatform.org) within the Supporting
Documentation section or within the Card-Related Chip Technology section.
The export and related files for the Deprecated API can be obtained from the
GlobalPlatform website within the Previous GlobalPlatform Versions section.
Deprecated API

2.1 API

Description

visa.openplatform

org.globalplatform

Package name

A0 00 00 00 03 00 00

A0 00 00 01 51 00 00

Package AID

Class OPSystem

Class GPSystem

Basic API functionality

byte getCardContentState ()

byte getCardContentState () Obtain the current


Application Life Cycle State
(see sections 4.4 & 5.6)
boolean
Set the Application Life
Cycle State (see sections 4.3
setCardContentState
& 5.6)
(byte bState)

boolean
setCardContentState
(byte bState)
byte getCardManagerState
()

byte getCardState ()

boolean lockCardManager ()

boolean lockCard ()

boolean
terminateCardManager ()

boolean terminateCard ()

boolean setATRHistBytes
(byte[] buffer, short sOffset,
byte bLength)

boolean setATRHistBytes
(byte[] baBuffer, short sOffset,
byte bLength)

ProviderSecurityDomain
getSecurityDomain ()

SecureChannel
getSecureChannel ()

N/A

CVM getCVM
(byte[] baCVMIdentifier)

Obtain the current Card


Life Cycle State (see section
5.7)
Set the Card Life Cycle
State to CARD_LOCKED
(see section 4.5)
Set the Card Life Cycle
State to TERMINATED (see
section 4.5)
Set the historical bytes of
the Answer-To-Reset
Provides the handle to the
Secure Channel Interface
(see section 2.2.1)
Provides the handle to the
CVM Interface for the 2.1
API (see section 3.2)

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

Deprecated API

2.1 API

41

Description

Class OPSystem

Interface CVM

CVM services (see section 3)

byte getTriesRemaining ()

byte getTriesRemaining ()

boolean verifyPIN
(APDU apdu, short pOffset)

short verify
(byte[] baBuffer, short sOffset,
byte bLength, byte bFormat)

Obtain the number of


remaining tries available
(see section 3.2.3)
Verify the CVM value being
presented (see section 3.2.3)

boolean setPIN
(APDU apdu, short pOffset)

boolean update
(byte[] baBuffer, short sOffset,
byte bLength, byte bFormat)

Set or update the CVM


value (see section 3.2.4)

N/A

short setTryLimit
(byte[] bTryLimit)

Set or update the CVM


maximum number of tries

N/A

boolean blockState ()

Set the CVM state to


BLOCKED

N/A

boolean resetState ()

Reset the CVM state to


ACTIVE (see section 3.2.2)

N/A

boolean
resetAndUnblockState ()

Reset the CVM state from


BLOCKED to ACTIVE

N/A

boolean isActive ()

Indicate if the CVM is


present and activated

N/A

boolean isBlocked ()

Indicate if the CVM is


blocked (see section 3.2.3)

N/A

boolean isSubmitted ()

Indicate if the CVM has


been presented to the card

N/A

boolean isVerified ()

Indicate if the CVM has


been successfully verified
(see section 3.2.3)

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

42

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

Deprecated API

2.1 API

Description

Interface
ProviderSecurityDomain

Interface SecureChannel

Secure Channel services


(see section 2)

byte openSecureChannel
(APDU apdu)

short processSecurity
(APDU apdu)

Initiate a Secure Channel


Session (see section 2.2.2)

void
short processSecurity
verifyExternalAuthenticate (APDU apdu)
(byte channel, APDU apdu)

Initiate a Secure Channel


Session in the Explicit
Initiation Mode (see section
2.2.2)
Terminate a Secure
Channel Session (see section
0)
Decrypt secret data such as
a secret key (see section 0)

void closeSecureChannel
(byte channel)

void resetSecurity ()

boolean decryptVerifyKey
(byte channel, APDU apdu,
short offset)

short decryptData
(byte[] baBuffer, short sOffset,
short sLength)

void unwrap
(byte channel, APDU apdu)

short unwrap
(byte[] baBuffer, short sOffset,
short sLength)

Unwrap an APDU command


message (see section 2.2.4)

N/A

short wrap
(byte[] baBuffer, short sOffset,
short sLength)

Wrap an APDU response


message (see section 2.2.5)

N/A

short encryptData(byte[]
baBuffer, short sOffset, short
sLength)

Encrypt secret data

N/A

byte getSecurityLevel ()

Obtain the current Security


Level of a Secure Channel
Session

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

43

Appendix A.1 Sample Application


(using the 2.1 API)
/**
Copyright (c) 2002 by GlobalPlatform Inc., all rights reserved. This software is the
property of GlobalPlatform Inc.and is protected under the copyright, trade secret and
confidentiality laws of the United States and other countries, including each of the
countries in which it is licensed.
This Java code is basically a template of a compliant GlobalPlatform 2.1 application. It
has no intended function and is only made available to guide developers in what is required
of an application destined for a GlobalPlatform 2.1 compliant card. This source shows the
intended use of most basic GlobalPlatform 2.1 features. Please note that this code details
what is required but does not mandate the how or where. Java Card compliant code contained
in this source must of course also be adhered to but these requirements are not indicated
within this code.
**/
/* disclaimer: this sample application is being developped for educational purposes.
Therefore it is not intended to be optimized with respect to execution speed or memory size
requirements. */
/*
// $Workfile: Sample.java $
// $Date: 10/23/02 $
// */
import
import
import
import
import
import
import
import
import

javacard.framework.ISO7816;
javacard.framework.ISOException;
javacard.framework.Util;
javacard.framework.Applet;
javacard.framework.APDU;
javacard.framework.JCSystem;
javacard.security.DESKey;
javacardx.crypto.Cipher;
javacard.security.KeyBuilder;

import org.globalplatform.*;
public class Sample extends Applet {
// Commands the applet implements
final static byte CLA_Proprietary = (byte) 0x80;
final static byte CLA_Proprietary_Secured = (byte) 0x84;
final static byte CLA_ISO7816_Secured = (byte) 0x04;
final static byte INS_VERIFY = (byte) 0x20;
final static byte INS_CHANGE_PIN = (byte) 0x24;
final static byte INS_PUT_KEY = (byte) 0xD8;
final static byte INS_GET_STATUS = (byte) 0xF2;
// Mask the secure messaging bit 3 of the Class byte
final static byte SM_MASK = (byte) 0xFB;
// Constants for the applets Select response string
final static byte FCI_Template = (byte) 0x6F;
final static byte AID_Tag = (byte) 0x84;
final static byte Proprietary_Data_Template = (byte) 0xA5;
// Application specific Life Cycle State of the applet
final static byte APPLET_PERSONALIZED = (byte) 0x0F;
// This application example makes use of the Global PIN provided by the GlobalPlatform
// CVM Interface. The CVM State keeps track of whether the PIN has been presented
// correctly from one APDU to the next. For this example it is explicitly reset
// each time the application is selected, regardless if it was previously presented
// (correctly or not) during the current card session.
final static byte CVM_Management_Privilege = (byte) 0x02;
private CVM MyPIN;
// The next statements are only required if Security Domain features are being used by
Copyright 2002 GlobalPlatform Inc. All Rights Reserved.
The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

44

// the application. The MySecureChannel is a handle to this application's associated


// Security Domain.
private SecureChannel MySecureChannel;
private short responseLength;
private short wrappedLength;
// Application specific key and temporary key for key check value verification.
private static DESKey appletKey;
private static DESKey verifKey;
// Instance of the DES cipher object.
private static Cipher DESInstance;

/* Applet constructor
*
The constructor for the applet would typically be where objects to be
*
used by the applet would be instantiated but not necessarily populated.
*
For the purpose of this example code, the only function of the constructor
*
is to register itself with the instance AID defined by the off-card
*
entity.
*
@ Parameters
*
buffer :- buffer containing at least the instance AID and application
*
privileges.
*
offset :- offset within the buffer pointing to the beginning of the
*
instance AID length.
*
length :- length of the install parameters within the buffer.
**/
protected Sample(byte[] buffer, short offset, byte length) {
// Determine the length of the instance AID.
byte instanceLength = (byte) buffer[offset];
// Locate the install privileges.
byte appletPrivileges = (byte) buffer[
(short) (offset+1+instanceLength+1)];
// Ensure that the applet has CVM Management permission.
if ( appletPrivileges != CVM_Management_Privilege )
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
// Ensure that the card implements the CVM Interface
MyPIN = GPSystem.getCVM(GPSystem.CVM_GLOBAL_PIN);
if ( MyPIN == (CVM) null )
ISOException.throwIt(Util.makeShort((byte) 0x6A, (byte) 0x88));
appletKey

= (DESKey) KeyBuilder.buildKey( KeyBuilder.TYPE_DES,


KeyBuilder.LENGTH_DES, false);
verifKey = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES_TRANSIENT_DESELECT,
KeyBuilder.LENGTH_DES, false);
DESInstance = Cipher.getInstance(Cipher.ALG_DES_ECB_NOPAD,false);
}

register(buffer, (short)(offset + 1), instanceLength);

/* Install method
*
As defined in the Java Card specifications and invoked by the JCRE on receipt
*
of an INSTALL [for instal]l command as defined in GlobalPlatform specifications
*
Parameters
*
buffer :- buffer containing at least the length and values of the
*
following: instance AID, application privileges and
*
application specific parameters
*
offset :- offset within the buffer pointing to the beginning of the
*
install parameters i.e. instance AID length.
*
length :- length of the install parameters within the buffer.
*
Note that this example applet does not utilize application specific parameters.
**/
public static void install(byte[] buffer, short offset, byte length) {

}
/*

// Applet constructor
new Sample(buffer, offset, length);
Select method

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

45

*
As defined in the Java Card specifications and invoked by the JCRE on receipt
*
of a SELECT command indicating this applet's instance.
*
Please note that it is advised that, for Global Platform, minimal code, if any,
*
be contained in this method and that for no reason should this method ever fail
*
or return false rather than true.
**/
public boolean select() {
// Retrieve the handle of the Security Domain associated with this applet.
MySecureChannel = GPSystem.getSecureChannel();

// Reset the CVM State of the Global PIN, regardless if the PIN has been previously
// presented (correctly or not) during the current card session. This example
// requires that the PIN be systematically (re)presented to the application.
MyPIN.resetState();
return true;

/* Deselect method
* calling resetSecurity() will ensure that if a Secure Channel Session
* has been established, it will not be available to another application.
* If a Secure Channel Session has not been established, this call will have no
* effect
*/
public void deselect() {
MySecureChannel.resetSecurity();
}
/* Process method
*
As defined in the Java Card specifications and invoked by the JCRE on
*
receipt of a command intended for the applet. The applet is responsible
*
for processing or dispatching each command.
*
Parameters
*
apdu :- the apdu buffer.
**/
public void process( APDU apdu ) {
// Generally commands are dispatched within an application according to
// their class and instruction bytes. Secure messaging is checked by
// individual methods.
byte[] buffer = apdu.getBuffer();
byte cla = (byte) (buffer[ ISO7816.OFFSET_CLA ] & (byte) SM_MASK);
byte ins = buffer[ ISO7816.OFFSET_INS ];
// ISO class
if( cla == ISO7816.CLA_ISO7816 ){
switch ( buffer[ISO7816.OFFSET_INS] ) {
// SELECT Command
case (byte) ISO7816.INS_SELECT: processSelect( apdu );
break;
// PRESENT PIN command
case (byte) INS_VERIFY: presentPIN( apdu );
break;
default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
break;
} /* end switch */
return;
}
// Proprietary class commands
if( cla == CLA_Proprietary ){
switch ( buffer[ISO7816.OFFSET_INS] ) {
// PUT KEY command
case (byte) INS_PUT_KEY: personalize( apdu );
break;
// CHANGE PIN command
case (byte) INS_CHANGE_PIN: changePIN( apdu );
break;
// GET STATUS command
case (byte) INS_GET_STATUS: getStatus( apdu );
break;
// Command not directly supported by the applet: it might be a Secure Channel
Copyright 2002 GlobalPlatform Inc. All Rights Reserved.
The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

46

// Protocol command
default: SCPcommands( apdu );
break;
} /* end switch */
return;

}
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);

/*

processSelect method
*
Method to handle the SELECT command.
*
Parameters
*
apdu :- the apdu buffer.
**/
void processSelect( APDU apdu ) {
// As the JCRE dispatches SELECT commands which cannot be accessed through the
// registry to the currently selected applet, the applet must insure it is being
// selected prior to responding.
if( !selectingApplet() ) {
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
}
// Even though the command message has already been received by the JCRE, for
// consistency a pseudo receive is performed.
apdu.setIncomingAndReceive();
byte[] buffer = apdu.getBuffer();
// Retrieve the complete AID of the selected applet and build the Select
// response string.
short offset = ISO7816.OFFSET_CDATA;
short AIDLength =
JCSystem.getAID().getBytes(buffer, (short)(offset+4));
buffer[offset] = (byte) FCI_Template ;
buffer[offset+1] = (byte)(4+AIDLength);
buffer[offset+2] = (byte) AID_Tag;
buffer[offset+3] = (byte) AIDLength;
buffer[offset+4+AIDLength] = (byte) Proprietary_Data_Template;
buffer[offset+4+AIDLength+1] = (byte) 0x00;
apdu.setOutgoingAndSend( (short) ISO7816.OFFSET_CDATA, (short) (6+AIDLength) );

/* SCPcommands method
*
Method to handle the Secure Channel Protocol commands defined in the
*
GlobalPlatform specifications, such as: INITIALIZE UPDATE and EXTERNAL
*
AUTHENTICATE commands.
*
The processing for these commands is performed by the Security Domain
*
associated with the application.
*
Errors are managed and output by the Security Domain.
*
Parameters
*
apdu :- the apdu buffer.
**/
void SCPcommands ( APDU apdu ) {

// The processSecurity() method proceeds to receive the APDU and expect it as


// defined in the GlobalPlatform specifications. The method will throw an error if
// the command is not recognized.
// The prepared response message is placed in the APDU buffer by the Security
// Domain in position 5. The length to be output is returned by the processSecurity
// method.
responseLength = MySecureChannel.processSecurity( apdu );
if (responseLength != 0 )
apdu.setOutgoingAndSend( (short) ISO7816.OFFSET_CDATA, responseLength );

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

47

/* personalize method
*
Method to handle the personalization (PUT KEY) command.
*
The personalization command requires secure messaging and contains
*
one single length key data object formatted according to the
*
GlobalPlatform specifications.
*
Parameters
*
apdu :- the apdu buffer.
**/
void personalize( APDU apdu ) {
// The applet checks its own state to insure it is not already personalized.
if( GPSystem.getCardContentState() != GPSystem.APPLICATION_SELECTABLE )
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
// The applet expects some kind of secure messaging i.e. MAC or MAC and encryption.
byte[] buffer = apdu.getBuffer();
if( buffer[ ISO7816.OFFSET_CLA ] != CLA_Proprietary_Secured )
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
// The personalization data is retrieved and the command is unwrapped by the
// Security Domain.
// Errors in the unwrapping process are managed and output by the Security Domain.
wrappedLength = apdu.setIncomingAndReceive();
MySecureChannel.unwrap(buffer, (short) ISO7816.OFFSET_CLA,
(short) (wrappedLength+5));
// The command is now in an unwrapped state and the key can now be decrypted
// by the Security Domain. The applet is responsible for verifying the key check
// value of the key and for determining the action taken if the key cannot be
// verified.
MySecureChannel.decryptData(buffer, (short) (ISO7816.OFFSET_CDATA+3),
(short) (buffer[ISO7816.OFFSET_CDATA+2]) );
//
//
//
//
if
{

The applet is responsible for verifying the key check value of the key and
for determining the action taken if the key check value does not match.
This example sets the key as the applet key if the verification is correct and
throws an error if not.
(verifyKeyCheckValue(buffer, (short) (ISO7816.OFFSET_CDATA+3),
(short)(ISO7816.OFFSET_CDATA+4 + buffer[ISO7816.OFFSET_CDATA+2]) ))
appletKey.setKey(buffer, (short) (ISO7816.OFFSET_CDATA+3));

// As the application now contains personalization data, it's Life Cycle


// State transitions to its own specific state Personalized.
GPSystem.setCardContentState( APPLET_PERSONALIZED );
} else {
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
}

/* getStatus method
*
Method to handle the Get Status command.
*
The Get Status command may or may not include secure messaging and returns
*
the status of the application to the off-card entity.
*
Parameters
*
apdu :- the apdu buffer.
**/
void getStatus( APDU apdu ) {
byte[] buffer = apdu.getBuffer();
// Only if the command includes secure messaging will it contain a command
// message i.e. a MAC. In which case the command message must be retrieved
// and the command unwrapped.
// Errors in the unwrapping process are managed and output by the Security
// Domain.
if( buffer[ ISO7816.OFFSET_CLA ] == CLA_Proprietary_Secured ){
wrappedLength = apdu.setIncomingAndReceive();
MySecureChannel.unwrap(buffer, (short) ISO7816.OFFSET_CLA,
(short) (wrappedLength+5));
}

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

48

// The application Life Cycle State is retrieved and output to the external entity.
buffer[ISO7816.OFFSET_CDATA] = GPSystem.getCardContentState();
apdu.setOutgoingAndSend( (short) ISO7816.OFFSET_CDATA, (short) 1 );

/* presentPIN method
*
Method to handle the present PIN command.
*
The present PIN command checks that the PIN presented by the external entity
*
to the card is valid. As this is the global PIN, the applet assumes that
*
the PIN has been previously populated.
*
Parameters
*
apdu :- the apdu buffer.
**/
void presentPIN( APDU apdu ) {
// PIN presentation can only occur when the application is in its own state
// Personalized.
if( GPSystem.getCardContentState() != APPLET_PERSONALIZED )
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
// If the CVM State of the PIN is blocked, i.e. its retry limit has been reached,
// an appropriate error is thrown.
if( MyPIN.isBlocked() )
ISOException.throwIt(Util.makeShort( (byte) 0x69, (byte) 0x83));
// Retrieve the PIN data and unwrap the command if secure messaging is present.
byte[] buffer = apdu.getBuffer();
wrappedLength = apdu.setIncomingAndReceive();
if( buffer[ ISO7816.OFFSET_CLA ] == CLA_ISO7816_Secured )
MySecureChannel.unwrap(buffer, (short) ISO7816.OFFSET_CLA,
(short) (wrappedLength+5));
// The applet assumes that the PIN formatting required by the verify() method has
// been applied by the off-card entity and uses the transparent HEX format.
MyPIN.verify(buffer, (short) ISO7816.OFFSET_CDATA, buffer[ISO7816.OFFSET_LC],
CVM.FORMAT_HEX);
// If PIN verification failed, an appropriate error indicating how many
// opportunities remain to present the correct PIN will be thrown.
if ( !MyPIN.isVerified() ) {
byte triesRemaining = (byte) (MyPIN.getTriesRemaining () | (byte) 0xc0 );

ISOException.throwIt(Util.makeShort( (byte) 0x63, triesRemaining ));

/* changePIN method
*
Method to handle the change PIN command.
*
The change PIN command allows the Global PIN to be changed if the correct
*
PIN has been previously presented.
*
Parameters
*
apdu :- the apdu buffer.
**/
void changePIN( APDU apdu ) {
// The PIN must have been previously presented.
if ( !MyPIN.isVerified() )
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
// Retrieve the command data
byte[] buffer = apdu.getBuffer();
wrappedLength = apdu.setIncomingAndReceive();
// unwrap if secure messaging is present
if( buffer[ ISO7816.OFFSET_CLA ] == CLA_Proprietary_Secured )
MySecureChannel.unwrap(buffer, (short) ISO7816.OFFSET_CLA,
(short) (wrappedLength+5));

// The applet assumes that the correct PIN formatting has been applied by the
// off-card entity and uses the transparent HEX format.
MyPIN.update(buffer, (short) ISO7816.OFFSET_CDATA, buffer[ISO7816.OFFSET_LC],
CVM.FORMAT_HEX);

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

49

/* Key Check Value verification method


*
Application specific key check value verification method.
*
The verification algorithm is defined by the application specification, and
*
not GlobalPlatform specification.
*
Parameters
*
buffer :- buffer containing the key and its key check value
*
keyOffset :- offset of the key to verify
*
checkValueOffset: - offset of the key check value.
**/
boolean verifyKeyCheckValue (byte[] buffer, short keyOffset, short checkValueOffset) {
byte[] checkValue = new byte[8];
Util.arrayFillNonAtomic(checkValue, (short) 0, (short) 8, (byte) 0 );
verifKey.setKey(buffer, keyOffset);
DESInstance.init(verifKey, Cipher.MODE_ENCRYPT);
DESInstance.doFinal(checkValue, (short) 0, (short) 8, checkValue, (short) 0);
return (Util.arrayCompare(checkValue, (short) 0, buffer, checkValueOffset,
(short) 3) == (byte) 0);
}
} // end applet

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

50

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

Appendix A.2 Sample Application


(using the Deprecated API)
/**
Copyright (c) 2002 by GlobalPlatform Inc., all rights reserved. This software is the
property of GlobalPlatform Inc.and is protected under the copyright, trade secret and
confidentiality laws of the United States and other countries, including each of the
countries in which it is licensed.
This Java code is basically a template of a compliant GlobalPlatform 2.1 application using
the Deprecated API. It has no intended function and is only made available to guide
developers in what is required of an application destined for a GlobalPlatform 2.1
compliant card. This source shows the intended use of most basic GlobalPlatform 2.1
features. Please note that this code details what is required but does not mandate the how
or where. Java Card compliant code contained in this source must of course also be adhered
to but these requirements are not indicated within this code.
**/
/* disclaimer: this sample application is being developped for educational purposes.
Therefore it is not intended to be optimized with respect to execution speed or memory size
requirements. */
/*
//
//
//
//

$Workfile: Sample.java $
$Date: 04/13/00 $
$Revised: 10/21/02 $
*/

import
import
import
import
import
import
import
import
import

javacard.framework.ISO7816;
javacard.framework.ISOException;
javacard.framework.Util;
javacard.framework.Applet;
javacard.framework.APDU;
javacard.framework.JCSystem;
javacard.security.DESKey;
javacardx.crypto.Cipher;
javacard.security.KeyBuilder;

import visa.openplatform.*;
public class Sample extends Applet {
// Commands the applet implements
final static byte CLA_Proprietary = (byte) 0x80;
final static byte CLA_Proprietary_Secured = (byte) 0x84;
final static byte CLA_ISO7816_Secured = (byte) 0x04;
final static byte INS_INITIALIZE_UPDATE = (byte) 0x50;
final static byte INS_VERIFY = (byte) 0x20;
final static byte INS_CHANGE_PIN = (byte) 0x24;
final static byte INS_PUT_KEY = (byte) 0xD8;
final static byte INS_GET_STATUS = (byte) 0xF2;
// Mask the secure messaging bit 3 of the Class byte
final static byte SM_MASK = (byte) 0xFB;
// Constants for the applets Select response string
final static byte FCI_TEMPLATE = (byte) 0x6F;
final static byte AID_Tag = (byte) 0x84;
final static byte Proprietary_Data_Template = (byte) 0xA5;
// The PINPresented flag is only required if an application makes use of the
// Global PIN. This flag keeps track of whether the PIN has been presented
// correctly from one APDU to the next. For this example it is explicitly
// set to false each time the application is selected. Alternatively, this
// could be a transient object in which case it would be automatically reset.
final static byte PIN_Change_Privilege = (byte) 0x02;
protected boolean PINPresented;
Copyright 2002 GlobalPlatform Inc. All Rights Reserved.
The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

51

// The next 2 statements are only required if Security Domain features are being
// used by the application. The channel is used to keep track of the currently
// opened Secure Channel Session and SecurityDomain is a handle to this
// application's associated Security Domain.
private byte channel;
private ProviderSecurityDomain SecurityDomain;
// Application specific key.
private static DESKey appletKey;
// Instance of the DES cipher object.
private static Cipher DESInstance;

/* Applet constructor
*
The constructor for the applet would typically be where objects to be
*
used by the applet would be instantiated but not necessarily populated.
*
For the purpose of this example code, the only function of the constructor
*
is to register itself with the instance AID defined by the off-card
*
entity.
*
@ Parameters
*
buffer :- buffer containing at least the instance AID and application
*
privileges.
*
offset :- offset within the buffer pointing to the beginning of the
*
instance AID length.
*
length :- length of the install parameters within the buffer.
**/
protected Sample(byte[] buffer, short offset, byte length) {
// Determine the length of the instance AID.
byte instanceLength = (byte) buffer[offset];
// Locate the install privileges.
byte appletPrivileges = (byte) buffer[
(short) (offset+1+instanceLength+1)];
// Ensure that the applet has PIN Change permission.
if ( appletPrivileges != PIN_Change_Privilege )
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
appletKey

= (DESKey) KeyBuilder.buildKey( KeyBuilder.TYPE_DES,


KeyBuilder.LENGTH_DES, false);

DESInstance = Cipher.getInstance(Cipher.ALG_DES_ECB_NOPAD,false);
}

register(buffer, (short)(offset + 1), instanceLength);

/* Install method
*
As defined in the Java Card specifications and invoked by the JCRE on receipt
*
of an INSTALL [for instal]l command as defined in the GlobalPlatform
*
specifications.
*
Parameters
*
buffer :- buffer containing at least the length and values of the
*
following: instance AID, application privileges and
*
application specific parameters
*
offset :- offset within the buffer pointing to the beginning of the
*
install parameters i.e. instance AID length.
*
length :- length of the install parameters within the buffer.
*
Note that this example applet does not utilize application specific parameters.
**/
public static void install(byte[] buffer, short offset, byte length) {

// Applet constructor
new Sample(buffer, offset, length);

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

52

/*

Select method
*
As defined in the Java Card specifications and invoked by the JCRE on receipt
*
of a SELECT command indicating this applet's instance.
*
Please note that it is advised that, for Global Platform, minimal code, if any,
*
be contained in this method and that for no reason should this method ever fail
*
or return false rather than true.
**/
public boolean select() {
// Retrieve the handle of the Security Domain associated with this applet.
SecurityDomain = OPSystem.getSecurityDomain();
}

// Set the PINPresented flag to false.


PINPresented = false;
return true;

/* Deselect method
* calling closeSecureChannel() will ensure that if a Secure Channel Session
* has been established, it will not be available to another application.
* If a Secure Channel Session has not been established, this call will have no
* effect
**/
public void deselect() {
SecurityDomain.closeSecureChannel(channel);
}
/* Process method
*
As defined in the Java Card specifications and invoked by the JCRE on
*
receipt of a command intended for the applet. The applet is responsible
*
for processing or dispatching each command.
*
Parameters
*
apdu :- the apdu buffer.
**/
public void process( APDU apdu ) {
// Generally commands are dispatched within an application according to
// their class and instruction bytes. Secure messaging is checked by
// individual methods.
byte[] buffer = apdu.getBuffer();
byte cla = (byte) (buffer[ ISO7816.OFFSET_CLA ] & (byte) SM_MASK);
byte ins = buffer[ ISO7816.OFFSET_INS ];
// ISO class
if( cla == ISO7816.CLA_ISO7816 ){
switch ( buffer[ISO7816.OFFSET_INS] ) {
// SELECT Command
case (byte) ISO7816.INS_SELECT: processSelect( apdu );
break;
// PRESENT PIN command
case (byte) INS_VERIFY: presentPIN( apdu );
break;
default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
break;
} /* end switch */
return;
}
// Proprietary class commands
if( cla == CLA_Proprietary ){
switch ( buffer[ISO7816.OFFSET_INS] ) {
// INITIALIZE UPDATE command
case (byte) INS_INITIALIZE_UPDATE: initializeUpdate( apdu );
break;
// EXTERNAL AUTHENTICATE command
case (byte) ISO7816.INS_EXTERNAL_AUTHENTICATE: externalAuthenticate( apdu );
break;
// PUT KEY command
case (byte) INS_PUT_KEY: personalize( apdu );
break;
Copyright 2002 GlobalPlatform Inc. All Rights Reserved.
The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0
// CHANGE PIN command
case (byte) INS_CHANGE_PIN: changePIN( apdu );
break;
// GET STATUS command
case (byte) INS_GET_STATUS: getStatus( apdu );
break;
default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
break;
} /* end switch */
return;

}
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);

/* processSelect method
*
Method to handle the SELECT command.
*
Parameters
*
apdu :- the apdu buffer.
**/
void processSelect( APDU apdu ) {
// As the JCRE dispatches SELECT commands which cannot be accessed through the
// registry to the currently selected applet, the applet must insure it is being
// selected prior to responding.
if( !selectingApplet() ) {
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
}
// Even though the command message has already been received by the JCRE, for
// consistency a pseudo receive is performed.
apdu.setIncomingAndReceive();
byte[] buffer = apdu.getBuffer();
// Retrieve the complete AID of the selected applet and build the Select
// response string.
short offset = ISO7816.OFFSET_CDATA;
short AIDLength =
JCSystem.getAID().getBytes(buffer, (short)(offset+4));
buffer[offset] = (byte) FCI_TEMPLATEemplate;
buffer[offset+1] = (byte)(4+AIDLength);
buffer[offset+2] = (byte) AID_Tag;
buffer[offset+3] = (byte) AIDLength;
buffer[offset+4+AIDLength] = (byte) Proprietary_Data_Template;
buffer[offset+4+AIDLength+1] = (byte) 0x00;
apdu.setOutgoingAndSend( (short) ISO7816.OFFSET_CDATA, (short) (6+AIDLength) );

/* initializeUpdate method
*
Method to handle the INITIALIZE UPDATE command.
*
The processing for this command is performed by the Security Domain
*
associated with the application.
*
Errors are managed and output by the Security Domain.
*
Parameters
*
apdu :- the apdu buffer.
**/
void initializeUpdate ( APDU apdu ) {
apdu.setIncomingAndReceive();
byte[] buffer = apdu.getBuffer();
// The openSecureChannel method expects to receive the APDU as defined in the
// GlobalPlatform specifications.
// The channel number returned must be used for all subsequent invocations of
// Security Domain methods.
channel = SecurityDomain.openSecureChannel( apdu );

// The prepared response message is placed back in the buffer by the Security
// Domain in position 5. The length to be output is found in position 4.
short responseLength = buffer[ISO7816.OFFSET_LC];
apdu.setOutgoingAndSend( (short) ISO7816.OFFSET_CDATA, responseLength );

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

53

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

54

/* externalAuthenticate method
*
Method to handle the EXTERNAL AUTHENTICATE command.
*
The processing for this command is performed by the Security Domain
*
associated with the application.
*
Errors are managed and output by the Security Domain.
*
Parameters
*
apdu :- the apdu buffer.
**/
void externalAuthenticate ( APDU apdu ) {
apdu.setIncomingAndReceive();
byte[] buffer = apdu.getBuffer();

// The verifyExternalAuthenticate method expects to receive the APDU as


// defined in the GlobalPlatform specifications.
SecurityDomain.verifyExternalAuthenticate( channel, apdu );

/* personalize method
*
Method to handle the personalization (PUT KEY) command.
*
The personalization command requires secure messaging and contains
*
one single length key data object formatted according to the
*
GlobalPlatform specifications.
*
Parameters
*
apdu :- the apdu buffer.
**/
void personalize( APDU apdu ) {
// The applet checks its own state to insure it is not already personalized.
if( OPSystem.getCardContentState() != OPSystem.APPLET_SELECTABLE )
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
// The applet expects some kind of secure messaging i.e. MAC or MAC and encryption.
byte[] buffer = apdu.getBuffer();
if( buffer[ ISO7816.OFFSET_CLA ] != CLA_Proprietary_Secured )
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
// The personalization data is retrieved and the command is unwrapped by the
// Security Domain.
// Errors in the unwrapping process are managed and output by the Security Domain.
apdu.setIncomingAndReceive();
SecurityDomain.unwrap(channel, apdu);
// The command is now in an unwrapped state and the key can now be decrypted
// and verified by the Security Domain. In this case the applet is responsible
// for determining the action taken if the key cannot be verified by the Security
// Domain.
// This example sets the key as the applet key if the method returns true and
// throws an error if the method returns false.
if( SecurityDomain.decryptVerifyKey(channel,apdu, (short)(ISO7816.OFFSET_CDATA+1)) )
{
appletKey.setKey(buffer, (short)(ISO7816.OFFSET_CDATA+3));

// As the application now contains personalization data, it's Life Cycle


// State transitions to personalized.
OPSystem.setCardContentState( OPSystem.APPLET_PERSONALIZED );
} else {
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
}

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

55

/* getStatus method
*
Method to handle the Get Status command.
*
The Get Status command may or may not include secure messaging and returns
*
the status of the application to the off-card entity.
*
Parameters
*
apdu :- the apdu buffer.
**/
void getStatus( APDU apdu ) {
byte[] buffer = apdu.getBuffer();
// Only if the command includes secure messaging will it contain a command
// message i.e. a MAC. In which case the command message must be retrieved
// and the command unwrapped.
// Errors in the unwrapping process are managed and output by the
// Security Domain.
if( buffer[ ISO7816.OFFSET_CLA ] == CLA_Proprietary_Secured ){
apdu.setIncomingAndReceive();
SecurityDomain.unwrap(channel, apdu);
}

// The application Life Cycle State is retrieved and output to the external entity.
buffer[ISO7816.OFFSET_CDATA] = OPSystem.getCardContentState();
apdu.setOutgoingAndSend( (short) ISO7816.OFFSET_CDATA, (short) 1 );

/* presentPIN method
*
Method to handle the present PIN command.
*
The present PIN command checks that the PIN presented by the external entity
*
to the card is valid. As this is the global PIN, the applet assumes that
*
the PIN has been previously populated.
*
Parameters
*
apdu :- the apdu buffer.
**/
void presentPIN( APDU apdu ) {
// PIN presentation can only occur when the application is in a personalized state.
if( OPSystem.getCardContentState() != OPSystem.APPLET_PERSONALIZED )
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
// If the PIN retry limit has been reached, an appropriate error, indicating that
// the PIN is blocked, is thrown.
if( OPSystem.getTriesRemaining() == 0 )
ISOException.throwIt(Util.makeShort( (byte) 0x69, (byte) 0x83));
// Retrieve the PIN data and unwrap the command if secure messaging is present.
byte[] buffer = apdu.getBuffer();
apdu.setIncomingAndReceive();
if( buffer[ ISO7816.OFFSET_CLA ] == CLA_ISO7816_Secured )
SecurityDomain.unwrap(channel, apdu);
// The applet assumes that the PIN formating required by the verifyPIN() method
// has been applied by the off-card entity.
if( OPSystem.verifyPin( apdu, ISO7816.OFFSET_CDATA )){
PINPresented = true;
// If PIN presentation failed, an appropriate error indicating how many
// opportunities remain to present the correct PIN will be thrown.
} else {
PINPresented = false;
byte triesRemaining = (byte) (OPSystem.getTriesRemaining() | (byte) 0xc0 );

ISOException.throwIt(Util.makeShort( (byte) 0x63, triesRemaining ));

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

56

/* changePIN method
*
Method to handle the change PIN command.
*
The change PIN command allows the global PIN to be changed if the correct
*
PIN has been previously presented.
*
Parameters
*
apdu :- the apdu buffer.
**/
void changePIN( APDU apdu ) {

// The PIN must have been previously presented.


if ( PINPresented != true )
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
// Retrieve the command data
byte[] buffer = apdu.getBuffer();
apdu.setIncomingAndReceive();
// unwrap if secure messaging is present
if( buffer[ ISO7816.OFFSET_CLA ] == CLA_Proprietary_Secured )
SecurityDomain.unwrap(channel, apdu);
OPSystem.setPin( apdu, ISO7816.OFFSET_CDATA );

} // end applet

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

57

Appendix B.1 Loyalty Application


(using the 2.1 API)
/**
Copyright (c) 2002 by GlobalPlatform Inc., all rights reserved. This software is the
property of GlobalPlatform Inc. and is protected under the copyright, trade secret and
confidentiality laws of the United States and other countries, including each of the
countries in which it is licensed.
/*
* Package: GPRiskMgmntPackage
* Filename: GPRiskMgmntApplet.java
* Class:
GPRiskMgmntApplet
* Date:
Nov 15, 2002
*/
/* This applet uses card life cycle and applet life cycle to implement risk management.
Additional mechanisms for risk management are not considered by this applet. */
/* disclaimer: this sample applet is being developed for educational purposes. therefore it
is not intended to be optimized with respect to execution speed or memory size
requirements. */
package GPRiskMgmntPackage;
import javacard.framework.*;
import org.globalplatform.*;
public class GPRiskMgmntApplet extends javacard.framework.Applet{
// commands the applet implements
final static byte STOREDATA = (byte) 0xE2;
final static byte SETSTATUS = (byte) 0xF0;
final static byte VERIFY = (byte) 0x20;
final static byte COLLECT = (byte) 0xC2;
final static byte REDEEM = (byte) 0xC4;
// constants for the applet Password
final static byte TRYLIMIT = (byte) 4;
final static byte PWLENGTH = (byte) 8;
// return codes
final static short SW_INVALID_PW = 0x63C0;
// application specific life cycle states:
final static byte APPLET_PERSONALIZED = (byte) 0x0F;
final static byte APPLET_BLOCKED = (byte) 0x7F;
// this applet's own stuff....
// the applet's own Password, GlobalPlatform CVM is not used
OwnerPIN AppletPW;
// the current loyalty points value
short sLoyaltyPoints;
/******************************************************************/
public static void install(byte[] bArray, short bOffset, byte bLength){
new GPRiskMgmntApplet (bArray, (short)(bOffset + 1), bArray[bOffset]);
} /* end method */
/******************************************************************/
private GPRiskMgmntApplet (byte[] bArray, short bOffset, byte bLength) {
AppletPW = new OwnerPIN(TRYLIMIT, PWLENGTH);
register(bArray, bOffset, bLength);
} /* end method */
/******************************************************************/
// deselect() and select() method are not required by this implementation
/******************************************************************/
public void process(APDU apdu){
Copyright 2002 GlobalPlatform Inc. All Rights Reserved.
The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

58

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

byte[] buffer = apdu.getBuffer();


if ( selectingApplet() ){
AppletPW.reset();
return;
} /* end if */
switch ( buffer[ISO7816.OFFSET_INS] ) {
case (byte) SETSTATUS: cmd_SETSTATUS (apdu);
break;
case (byte) STOREDATA: cmd_STOREDATA (apdu);
break;
case (byte) VERIFY: cmd_VERIFY (apdu);
break;
case (byte) COLLECT: cmd_COLLECT (apdu);
break;
case (byte) REDEEM: cmd_REDEEM (apdu);
break;
default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
break;
} /* end switch */
return;
} /* end method */
/******************************************************************/
/*
cmd_SETSTATUS
*
set the applet specific life cycle state
*
this applet implements the checking for the state transitions as follows:
*
APPLET_SELECTABLE ==> APPLET_PERSONALIZED <==> APPLET_BLOCKED
*
card life cycle state is not used for state transitions in this implementation
*
future development: use SCP when performing post issuance life cycle transitions
(see source code comments)
*/
private void cmd_SETSTATUS(APDU apdu) {
byte[] buffer = apdu.getBuffer();
byte bAppletLifeCycle = GPSystem.getCardContentState();
byte bNewAppletLifeCycle = buffer[ISO7816.OFFSET_P2];
// from APPLICATION_SELECTABLE it is only possible to go to APPLET_PERSONALIZED
if (bAppletLifeCycle == GPSystem.APPLICATION_SELECTABLE) {
if (bNewAppletLifeCycle != APPLET_PERSONALIZED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} /* end if */
} /* end if */
// from APPLET_PERSONALIZED it is only possible to go to APPLET_BLOCKED
if (bAppletLifeCycle == APPLET_PERSONALIZED) {
if (bNewAppletLifeCycle != APPLET_BLOCKED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} /* end if */
} /* end if */
// from APPLET_BLOCKED it is only possible to go to APPLET_PERSONALIZED
if (bAppletLifeCycle == APPLET_BLOCKED) {
// applet life cycle is APPLET_BLOCKED and should go to APPLET_PERSONALIZED
// conditions: card life cycle must be post-issuance, Password presentation
// successfull
check_CARD_SECURED();
check_PERSONALIZED();
check_PWVALIDATED();
AppletPW.resetAndUnblock(); // and also the Password is unblocked but reset!
} // end if
GPSystem.setCardContentState(bNewAppletLifeCycle);
return;
} /* end method */

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

59

/******************************************************************/
/*
cmd_STOREDATA
*
applet personalization code:
*
personalize the Password
*/
private void cmd_STOREDATA (APDU apdu) {
byte[] buffer = apdu.getBuffer();
byte bReadBytes = (byte)(apdu.setIncomingAndReceive());
if ((GPSystem.getCardContentState()) == GPSystem.APPLICATION_SELECTABLE) {
// the applet has not been personalized yet, perform regular personalization
// check for card life cycle
if ((GPSystem.getCardState()) == GPSystem.CARD_SECURED ) {
// it's post-issuance
// this applet does not implement support for this situation
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} else {
AppletPW.update(buffer, ISO7816.OFFSET_CDATA,
(byte)buffer[ISO7816.OFFSET_LC]);
} /* end if */
} else {
// the applet is personalized, but a perso command is received
// this applet does not implement support for this situation.
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} /* end if */
} /* end method */
/******************************************************************/
/*
cmd_VERIFY
*
verification of the applet Password for card holder verification
*/
private void cmd_VERIFY (APDU apdu) {
byte[] buffer = apdu.getBuffer();
byte bAppletLifeCycle = GPSystem.getCardContentState();
byte bReadBytes = (byte)(apdu.setIncomingAndReceive());
// short sStatusWord = SW_INVALID_PW;
// this command is only executed in CARD_SECURED,
check_CARD_SECURED();
if ((AppletPW.check(buffer, ISO7816.OFFSET_CDATA, (byte)buffer[ISO7816.OFFSET_LC]))
== false) {
// Are there any Password verification tries left?
if ((AppletPW.getTriesRemaining()) == (byte) 1) {
// if there is one try left, block application
// now there is only one more chance!
// Otherwise Password will be blocked
GPSystem.setCardContentState(APPLET_BLOCKED);
} /* end if */
ISOException.throwIt((short)(SW_INVALID_PW +
(short)(AppletPW.getTriesRemaining())));
} /* end if */
} /* end method */
/******************************************************************/
/*
cmd_COLLECT
*
collect more loyalty points
*/
private void cmd_COLLECT (APDU apdu) {
byte[] buffer = apdu.getBuffer();
byte bReadbytes = (byte)(apdu.setIncomingAndReceive());
/* loyalty collection is only done when:
*
(a) card life cycle is post-issuance
*
(b) applet is personalized,
*
(c) card holder verification was successfull */
check_CARD_SECURED();
check_PERSONALIZED();
check_PWVALIDATED();
sLoyaltyPoints = (short) (sLoyaltyPoints + buffer[ISO7816.OFFSET_CDATA]);
} // end method

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

60

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

/******************************************************************/
/*
cmd_REDEEM
*
Redeem some of the loyalty points
*/
private void cmd_REDEEM (APDU apdu) {
byte[] buffer = apdu.getBuffer();
byte bReadbytes = (byte)(apdu.setIncomingAndReceive());
byte bRedeemAmount = buffer[ISO7816.OFFSET_CDATA];
/* loyalty redeeming is only done when:
*
(a) card life cycle is post-issuance
*
(b) applet is personalized,
*
(c) card holder verification was successfull */
check_CARD_SECURED();
check_PERSONALIZED();
check_PWVALIDATED();
if ((short)bRedeemAmount > sLoyaltyPoints) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} else {
sLoyaltyPoints = (short) (sLoyaltyPoints - (short)bRedeemAmount);
} // end if
Util.setShort(buffer, (short)0, sLoyaltyPoints);
apdu.setOutgoingAndSend((short)0, (short)2);
} // end method
/******************************************************************/
private void check_PERSONALIZED () {
if (GPSystem.getCardContentState() != APPLET_PERSONALIZED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} /* end if */
} /* end method */
/******************************************************************/
private void check_PWVALIDATED () {
if (AppletPW.isValidated() == false) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} // end if
} // end method
/******************************************************************/
/*
check_CARD_SECURED */
private void check_CARD_SECURED () {
if (GPSystem.getCardState() != GPSystem.CARD_SECURED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} // end if
} // end method
} // end applet

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

61

Appendix B.2 Loyalty Application


(using the Deprecated API)
/**
Copyright (c) 2002 by GlobalPlatform Inc., all rights reserved. This software is the
property of GlobalPlatform Inc. and is protected under the copyright, trade secret and
confidentiality laws of the United States and other countries, including each of the
countries in which it is licensed.
/*
* Package: GPRiskMgmntPackage
* Filename: GPRiskMgmntApplet.java
* Class:
GPRiskMgmntApplet
* Date:
Apr 15, 2002 3:53:02 PM
*/
/* This applet uses card life cycle and applet life cycle to implement risk management.
Additional mechanisms for risk management are not considered by this applet. */
/* disclaimer: this sample applet is being developed for educational purposes. therefore it
is not intended to be optimized with respect to execution speed or memory size
requirements. */
package GPRiskMgmntPackage;
import javacard.framework.*;
import visa.openplatform.*;
public class GPRiskMgmntApplet extends javacard.framework.Applet{
// commands the applet implements
final static byte STOREDATA = (byte) 0xE2;
final static byte SETSTATUS = (byte) 0xF0;
final static byte VERIFY = (byte) 0x20;
final static byte COLLECT = (byte) 0xC2;
final static byte REDEEM = (byte) 0xC4;
// constants for the applet Password
final static byte TRYLIMIT = (byte) 4;
final static byte PWLENGTH = (byte) 8;
// return codes
final static short SW_INVALID_PW = 0x63C0;
// this applets own stuff....
// the applet's own Password, GlobalPlatform Global PIN is not used
OwnerPIN AppletPW;
// the current loyalty points value
short sLoyaltyPoints;
/******************************************************************/
public static void install(byte[] bArray, short bOffset, byte bLength){
new GPRiskMgmntApplet (bArray, (short)(bOffset + 1), bArray[bOffset]);
} /* end method */
/******************************************************************/
private GPRiskMgmntApplet (byte[] bArray, short bOffset, byte bLength) {
AppletPW = new OwnerPIN(TRYLIMIT, PWLENGTH);
register(bArray, bOffset, bLength);
} /* end method */
/******************************************************************/
// deselect() and select() method are not required by this implementation
/******************************************************************/

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

62

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

public void process(APDU apdu){


byte[] buffer = apdu.getBuffer();
if ( selectingApplet() ){
AppletPW.reset();
return;
} /* end if */
switch ( buffer[ISO7816.OFFSET_INS] ) {
case (byte) SETSTATUS: cmd_SETSTATUS (apdu);
break;
case (byte) STOREDATA: cmd_STOREDATA (apdu);
break;
case (byte) VERIFY: cmd_VERIFY (apdu);
break;
case (byte) COLLECT: cmd_COLLECT (apdu);
break;
case (byte) REDEEM: cmd_REDEEM (apdu);
break;
default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
break;
} /* end switch */
return;
} /* end method */
/******************************************************************/
/*
cmd_SETSTATUS
*
set the applet specific life cycle state
*
this applet implements the checking for the state transitions as follows:
*
APPLET_SELECTABLE ==> APPLET_PERSONALIZED <==> APPLET_BLOCKED
*
card life cycle state is not used for state transitions in this implementation
*
future development: use SCP when performing post issuance life cycle transitions
(see source code comments)
*/
private void cmd_SETSTATUS(APDU apdu) {
byte[] buffer = apdu.getBuffer();
byte bAppletLifeCycle = OPSystem.getCardContentState();
byte bNewAppletLifeCycle = buffer[ISO7816.OFFSET_P2];
// from APPLET_SELECTABLE it is only possible to go to APPLET_PERSONALIZED
if (bAppletLifeCycle == OPSystem.APPLET_SELECTABLE) {
if (bNewAppletLifeCycle != OPSystem.APPLET_PERSONALIZED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} /* end if */
} /* end if */
// from APPLET_PERSONALIZED it is only possible to go to APPLET_BLOCKED
if (bAppletLifeCycle == OPSystem.APPLET_PERSONALIZED) {
if (bNewAppletLifeCycle != OPSystem.APPLET_BLOCKED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} /* end if */
} /* end if */
// from APPLET_BLOCKED it is only possible to go to APPLET_PERSONALIZED
if (bAppletLifeCycle == OPSystem.APPLET_BLOCKED) {
// applet life cycle is APPLET_BLOCKED and should go to APPLET_PERSONALIZED
// conditions: card life cycle must be post-issuance, Password presentation
// successfull
check_CARD_SECURED();
check_PERSONALIZED();
check_PWVALIDATED();
AppletPW.resetAndUnblock(); // and also the Password is unblocked but reset!
} // end if
OPSystem.setCardContentState(bNewAppletLifeCycle);
return;
} /* end method */

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

63

/******************************************************************/
/*
cmd_STOREDATA
*
applet personalization code:
*
personalize the Password
*/
private void cmd_STOREDATA (APDU apdu) {
byte[] buffer = apdu.getBuffer();
byte bReadBytes = (byte)(apdu.setIncomingAndReceive());
if ((OPSystem.getCardContentState()) == OPSystem.APPLET_SELECTABLE) {
// the applet has not been personalized yet, perform regular personalization
// check for card life cycle
if ((OPSystem.getCardManagerState()) == OPSystem.CARD_SECURED ) {
// it's post-issuance
// this applet does not implement support for this situation
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} else {
AppletPW.update(buffer, ISO7816.OFFSET_CDATA,
(byte)buffer[ISO7816.OFFSET_LC]);
} /* end if */
} else {
// the applet is personalized, but a perso command is received
// this applet does not implement support for this situation.
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} /* end if */
} /* end method */
/******************************************************************/
/*
cmd_VERIFY
*
verification of the applet Password for card holder verification
*/
private void cmd_VERIFY (APDU apdu) {
byte[] buffer = apdu.getBuffer();
byte bAppletLifeCycle = OPSystem.getCardContentState();
byte bReadBytes = (byte)(apdu.setIncomingAndReceive());
// this command is only executed in CARD_SECURED,
check_CARD_SECURED();
if ((AppletPW.check(buffer, ISO7816.OFFSET_CDATA, (byte)buffer[ISO7816.OFFSET_LC]))
== false) {
// Are there any Password verification tries left?
if ((AppletPW.getTriesRemaining()) == (byte) 1) {
// if there is one try left, block application
// now there is only one more chance!
// Otherwise Password will be blocked
OPSystem.setCardContentState(OPSystem.APPLET_BLOCKED);
} /* end if */
ISOException.throwIt((short)(SW_INVALID_PW +
(short)(AppletPW.getTriesRemaining())));
} /* end if */
} /* end method */
/******************************************************************/
/*
cmd_COLLECT
*
collect more loyalty points
*/
private void cmd_COLLECT (APDU apdu) {
byte[] buffer = apdu.getBuffer();
byte bReadbytes = (byte)(apdu.setIncomingAndReceive());
/* loyalty collection is only done when:
*
(a) card life cycle is post-issuance
*
(b) applet is personalized,
*
(c) card holder verification was successfull */
check_CARD_SECURED();
check_PERSONALIZED();
check_PWVALIDATED();
sLoyaltyPoints = (short) (sLoyaltyPoints + buffer[ISO7816.OFFSET_CDATA]);
} // end method

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

64

December 2002
Guidelines for Developing Java Card Applications on GlobalPlatform 2.1 Cards
Version 1.0

/******************************************************************/
/*
cmd_REDEEM
*
Redeem some of the loyalty points
*/
private void cmd_REDEEM (APDU apdu) {
byte[] buffer = apdu.getBuffer();
byte bReadbytes = (byte)(apdu.setIncomingAndReceive());
byte bRedeemAmount = buffer[ISO7816.OFFSET_CDATA];
/* loyalty redeeming is only done when:
*
(a) card life cycle is post-issuance
*
(b) applet is personalized,
*
(c) card holder verification was successfull */
check_CARD_SECURED();
check_PERSONALIZED();
check_PWVALIDATED();
if ((short)bRedeemAmount > sLoyaltyPoints) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} else {
sLoyaltyPoints = (short) (sLoyaltyPoints - (short)bRedeemAmount);
} // end if
Util.setShort(buffer, (short)0, sLoyaltyPoints);
apdu.setOutgoingAndSend((short)0, (short)2);
} // end method
/******************************************************************/
private void check_PERSONALIZED () {
if (OPSystem.getCardContentState() != OPSystem.APPLET_PERSONALIZED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} /* end if */
} /* end method */
/******************************************************************/
private void check_PWVALIDATED () {
if (AppletPW.isValidated() == false) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} // end if
} // end method
/******************************************************************/
/*
check_CARD_SECURED */
private void check_CARD_SECURED () {
if (OPSystem.getCardManagerState() != OPSystem.CARD_SECURED) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} // end if
} // end method
} // end applet

Copyright 2002 GlobalPlatform Inc. All Rights Reserved.


The technology provided or described herein is subject to updates, revisions, and extensions by GlobalPlatform. Use of
this information is governed by the GlobalPlatform license agreement and any use inconsistent with that agreement is
strictly prohibited.

Filename:
GP_Guidelines_for_Developing_Apps_on_GP_Cards_v1.0a
Directory:
C:\Documents and Settings\kekichef\My
Documents\Data\GlobalPlatform\CSD WG
Template:
C:\Documents and Settings\kekichef\Application
Data\Microsoft\Templates\Normal.dot
Title:
GP Guidelines for developing Applications on GP cards
Subject:
GP Application development
Author:
Mike Berg
Keywords:
Comments:
Creation Date:
12/17/2002 1:07 PM
Change Number:
4
Last Saved On:
12/18/2002 3:58 PM
Last Saved By:
Kekichef
Total Editing Time:
7 Minutes
Last Printed On:
12/18/2002 3:59 PM
As of Last Complete Printing
Number of Pages: 64
Number of Words: 18,912 (approx.)
Number of Characters:
107,800 (approx.)

S-ar putea să vă placă și