FileDocCategorySizeDatePackage
APDUManager.javaAPI DocphoneME MR2 API (J2ME)19212Wed May 02 18:00:38 BST 2007com.sun.midp.io.j2me.apdu

APDUManager

public class APDUManager extends Object
This class provides an interface to the low level APDU protocol details as described below: 1. Manage Card power up/reset. 2. APDU scheduler-Can assign priorities to APDUs to synchronize card access. Synchronization is required between APDUs being sent by native telecom software and APDUs sent by J2ME application. The reference implementation will only have APDUs sent by the J2ME application which would all have the same priority. 3. APDU Dispatcher-Support APDU exchange with the card. It has transaction capabilities to receive the APDUs from applications on the consumer device and return the responses to the corresponding application. 4. J2ME applications are oblivious of the logical channel information. Getting the logical channel for communicating with the smart card application is the responsibility of the APDUManager which sends appropriate APDUs to the card to get the logical channels assigned for a new connection or close channels when the connection is closed.

Fields Summary
private static final String
SAT_APDU_PROP
SAT selection APDU for testing purposes.
static Slot[]
slots
Contains references to all supported slots.
Constructors Summary
Methods Summary
public static voidcheckSlotNumber(int slot)
Verifies that slot number is correct. Invokes init method if necessary.

param
slot the slot number
throws
ConnectionNotFoundException if slot number is wrong


        try {
            init();
        } catch (IOException e) {
            throw new ConnectionNotFoundException(
                "Invalid configuration: " + e);
        }
        if (slot < 0 || slot >= getSlotCount()) {
            throw new ConnectionNotFoundException(
                    "Invalid slot identifier: " + slot);
        }
    
private static voidclean(Slot slot)
Cleans the slot object before a reset.

param
slot The slot object.

        slot.basicChannelInUse = false;
        slot.SIMPresent = false;
        slot.FCI = null;
    
private static voidcloseChannel(Slot slot, int channel)
This method is used to close connection with the card. If the channel number passed to this method is for basic channel then the basic channel is marked as available and nothing is communicated with the card. If the channel is not the basic channel, a request to close the channel is sent to the card.

param
slot the slot object
param
channel channel number
exception
IOException if a communication error happens

        
        if (channel == 0) {
            slot.basicChannelInUse = false;
            return;
        }

        try {
            slot.closeChannelAPDU[3] = (byte) channel;
            exchangeAPDU(slot, slot.closeChannelAPDU);
        } catch (IOException ioException) {
            throw new IOException("Error closing connection: " + ioException);
        }
    
public static voidcloseConnection(Handle h)
Closes the connection.

param
h connection handle
exception
IOException if there are any IO problems

        Slot cardSlot = h.cardSlot;
        synchronized (cardSlot) {
            h.opened = false;
            if (h.cardSessionId != cardSlot.cardSessionId) {
                throw new IOException();
            }
            closeChannel(cardSlot, h.channel);
        }
    
public static byte[]exchangeAPDU(Handle h, byte[] apduData)
This public method takes in the command APDU in the form of a byte array and calls the native exchangeAPDU0 method to send the APDU to the card. If there are no errors, this method gets the response APDU data from the card and returns that.

param
h connection handle
param
apduData APDU data in byte array form
return
response APDU data in byte array form
exception
IOException if there are any IO problems

        byte[] retData;
        
        Slot slot = h.cardSlot;
        try {
            synchronized (slot) {
                byte[] respBuffer = slot.respBuffer;
                int respLen = exchangeAPDU0(h, null, apduData, respBuffer);
                retData = new byte[respLen];
                System.arraycopy(respBuffer, 0, retData, 0, respLen);
            }
            return retData;
        } catch (IOException e) {
            if (!slot.powered) {
                // power up the slot after removal/insertion
                isAlive(slot);
            }
            throw e;
        }
    
private static byte[]exchangeAPDU(Slot slot, byte[] apduData)
This internal method takes in the command APDU in the form of a byte array and calls the native exchangeAPDU0 method to send the APDU to the card. If there are no errors, this method gets the response APDU data from the card and returns that.

param
slot the slot object
param
apduData APDU data in byte array form
return
response APDU data in byte array form
exception
IOException if there are any IO problems

        byte[] retData;
        synchronized (slot) {
            byte[] respBuffer = slot.respBuffer;
            int respLen = exchangeAPDU0(null, slot, apduData, respBuffer);
            retData = new byte[respLen];
            System.arraycopy(respBuffer, 0, retData, 0, respLen);
        }
        return retData;
    
private static native intexchangeAPDU0(Handle h, Slot slot, byte[] request, byte[] response)
Performs data transfer to the device. This method must be called within synchronize block with the Slot object.

param
h Connection handle. Can be null for internal purposes
param
slot Slot object. Unused when h is not null. Must be provided if h is null.
param
request Buffer with request data
param
response Buffer for response data
return
Length of response data
exception
NullPointerException if any needed parameter is null
exception
IllegalArgumentException if request does not contain proper APDU
exception
InterruptedIOException if the connection handle is suddenly closed in the middle of exchange or the card was removed and inserted again
exception
IOException if any I/O troubles occured

public static byte[]getATR(int slot)
This method returns the ATR received from the card.

param
slot the slot number
return
ATR information received from the card at startup or reset. In case of I/O troubles returns null.

        byte[] result = null;
        Slot cardSlot = slots[slot];
        
        if (isAlive(cardSlot) && cardSlot.atr != null) {
            int len = cardSlot.atr.length;
            result = new byte[len];
            System.arraycopy(cardSlot.atr, 0, result, 0, len);
        }
        return result;
    
public static intgetSlotCount()
Returns the number of slots.

return
the number of slots. If error occured it returns 0.

        try {
            init();
        }
        catch (IOException e) {
            return 0;
        }
        return slots.length;
    
private static synchronized voidinit()
This method reads the configuration file for number of slots and their parameters and performs necessary initialization.

exception
IOException if there are any config problem


        if (slots != null) {
            return;
        }
        int slotCount = init0();

        slots = new Slot[slotCount];
        for (int i = 0; i < slotCount; i++) {
            slots[i] = new Slot(i);
        }
    
private static native intinit0()
Initializes the device.

return
number of supported slots
exception
CardDeviceException If configuration failed.
exception
IOException in case of I/O problems.

public static voidinitACL(int slot, com.sun.midp.security.SecurityToken securityToken)
Initializes ACL for the slot (if needed). This method is invoked when an establishment of new connection is being performed.

param
slot The slot number
param
securityToken Security token for this class

        
        try {
            checkSlotNumber(slot);
            Slot cardSlot = slots[slot];
            if (!cardSlot.powered) {
                reset(cardSlot); // here a reading of ACL is being performed
            }
        } catch (IOException e) {} // ignored
    
private static booleanisAlive(Slot slot)
Checks if the the connection is still live or not. It sends special isAliveAPDU to the card and checks if an error occured.

param
slot The slot object.
return
true if the connection is alive, otherwise

        int tries = 2;
        do {
            if (!slot.powered) {
                try {
                    clean(slot);
                    reset(slot);
                } catch (IOException e) {} // ignored
            }
            try {
                exchangeAPDU(slot, slot.isAliveAPDU);
                return true;
            } catch (IOException e) {} // ignored
        } while (--tries > 0);
        return false;
    
private static native booleanisSAT(int slot)
Checks if this slot is SAT slot. This method is invoked once after a reset of the card.

param
slot Slot number
return
true if the slot is dedicated for SAT, false if not
exception
IOException in case of error

public static booleanisSatSlot(int slot)
Checks if this slot is SAT slot.

param
slot the slot number
return
SAT check result
throws
IOException If an error occured.

        checkSlotNumber(slot);
        return isSAT(slot);
    
public static HandleopenACLConnection(byte[] apdu, int slot, com.sun.midp.security.SecurityToken securityToken)
Opens a connection to a smart card for reading of ACL. This method is called from reset method, so it does not need synchronized statement.

param
apdu The APDU that will be used for opening
param
slot Slot number
param
securityToken Security token for this class
return
new connection handle
exception
IOException when a card is not present or connection cannot be established with the card.

        
        checkSlotNumber(slot);
        return selectApplication(true, apdu, slot, securityToken);
    
static HandleopenSATConnection(int slot, com.sun.midp.security.SecurityToken securityToken)
Creates SAT connection.

param
slot Slot number
param
securityToken Security token for this class
return
new connection handle
exception
IOException when SIM is not present or connection cannot be established with the card.

    
                                          
         
          
        
        Handle h = null;
        
        checkSlotNumber(slot);
        Slot cardSlot = slots[slot];
        
        String satAPDU = Configuration.getProperty(SAT_APDU_PROP);
        if (satAPDU != null) {
            byte[] apdu = new byte[24];
            boolean ok;
            try {
                int len = parseDottedBytes(satAPDU, apdu, 0);
                ok = len >= 10 && len <= 22; // 5 bytes hdr + AID + Le
                int Lc = (apdu[4] & 0xFF);
                if (ok && (len < Lc + 5 || 
                           len > Lc + 5 + 1 ||
                           apdu[0] != (byte)0x00 ||
                           apdu[1] != (byte)0xA4 ||
                           apdu[2] != (byte)0x04)) {
                    ok = false;
                }
                if (ok && len == Lc + 5) {
                    apdu[len] = 0x7F;
                }
            } catch (NullPointerException npe) {
                ok = false;
            } catch (IndexOutOfBoundsException iobe) {
                ok = false;
            } catch (IllegalArgumentException iae) {
                ok = false;
            }

            if (ok) {
                h = selectApplication(true, apdu, slot, securityToken);
            }
        }
        if (h == null) {
            if (!isAlive(cardSlot)) {
                throw new ConnectionNotFoundException("SIM not found");
            }
            h = new Handle(slot, 0, securityToken);
        }
        return h;
    
public static intparseDottedBytes(java.lang.String src, byte[] dest, int offset)
Parses string that contains hexadecimal byte values separated by dots. May throw runtime exceptions.

param
src source string
param
dest destination array
param
offset target offset
return
number of bytes parsed


        int i = 0;
        int len = 0;
        int j;

        while (i != src.length() + 1) {

            if ((j = src.indexOf('.", i)) == -1) {
                j = src.length();
            }

            int l = Integer.parseInt(src.substring(i, j), 16);
            if (l != (l & 0xff)) {
                throw new IllegalArgumentException();
            }
            dest[offset + len++] = (byte) l;
            i = j + 1;
        }
        return len;
    
private static voidreset(Slot cardSlot)
Performs reset of device. Saves ATR into provided slot object. After the reset invokes an ACL loading for this slot.

param
cardSlot the slot object to be reset
throws
IOException If a reset failed.

        synchronized (cardSlot) {
            byte[] atr = reset0(cardSlot);
            cardSlot.atr = atr;
            // after reset we must reload access control file
            com.sun.satsa.acl.AccessControlManager.init(cardSlot.slot);
        }
    
private static native byte[]reset0(Slot slot)
Performs reset of the card in the slot. This method must be called within synchronize block with the Slot object.

param
slot Slot object
return
byte array with ATR
exception
NullPointerException if parameter is null
exception
IOException if any i/o troubles occured

public static HandleselectApplication(byte[] selectAPDU, int slot, com.sun.midp.security.SecurityToken securityToken)
The public method which should be called when application selection is required. Calls an internal method.

param
selectAPDU byte encoded selection APDU
param
slot slot number
param
securityToken Security token for this class
return
new connection handle
exception
IOException when selection is not successful

        checkSlotNumber(slot);
        return selectApplication(false, selectAPDU, slot, securityToken);
    
private static HandleselectApplication(boolean forSAT, byte[] selectAPDU, int slot, com.sun.midp.security.SecurityToken securityToken)
This method is called when there is a connection creation is in progress and specifically card application selection is required. If the card application selection is successful this method gets the channel information from the CAD which it returns to the APDUConnection object.

param
forSAT is this selection is making for SAT?
param
selectAPDU byte encoded selection APDU
param
slot slot number
param
securityToken Security token for this class
return
new connection handle
exception
IOException when selection is not successful


        int channel;
        
        Slot cardSlot = slots[slot]; // we have checked slot number earlier

        // Test if 'POWER UP' is needed or a card was changed
        if (!isAlive(cardSlot)) {
            throw new ConnectionNotFoundException("SmartCard not found");
        }

        if (!forSAT && (cardSlot.basicChannelInUse || cardSlot.SIMPresent)) {
            // get another channel for communication.
            byte[] response = exchangeAPDU(cardSlot, cardSlot.getChannelAPDU);
            if (response.length  == 2) {
                // just got back the status word
                throw new IOException("No logical channel available");
            }
            // new channel number is in the first byte of response
            channel = response[0];
        } else {
            cardSlot.basicChannelInUse = true;
            channel = 0;
        }
        
        selectAPDU[0] = (byte)((selectAPDU[0] & 0xFC) | channel);

        byte[] result = exchangeAPDU(cardSlot, selectAPDU);

        int sw1 = result[result.length - 2] & 0xFF;
        int sw2 = result[result.length - 1] & 0xFF;
        if ((sw1 << 8) + sw2 != 0x9000) {
            closeChannel(cardSlot, channel);
            throw new ConnectionNotFoundException(
                    "Card application selection failed");
        }
        cardSlot.FCI = result;
        return new Handle(slot, channel, securityToken);