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

Protocol

public class Protocol extends Object implements com.sun.cldc.io.ConnectionBaseInterface, APDUConnection, StreamConnection
This is the implementation class for APDUConnection interface and provides a high-level API to the J2ME applications allowing them to connect and communicate with the card applications. An instance of this class is created when Connector.open method is called with 'apdu' as protocol. An instance of this class is only returned to the calling J2ME application if the card application selection is successful. If there are any errors that occur during the card application selection, IOException is thrown. The application calls Connector.open with an APDU URL string and obtains a {@link javax.microedition.apdu.APDUConnection} object.

Fields Summary
private static com.sun.midp.security.SecurityToken
classSecurityToken
This class has a different security domain than the MIDlet suite
private com.sun.satsa.acl.APDUPermissions
verifier
This object verifies access rights of the MIDlet.
private boolean
openForSAT
This flag is to indicate if this APDU connection is to be used for communicating with SAT.
private Handle
h
Connection handle.
Constructors Summary
Methods Summary
public byte[]changePin(int pinID)
A call to changePin method pops up a UI that requests the the user for an old or existing PIN value and the new PIN value to change the value of the PIN. The pinID field indicates which PIN is to be changed. The user can either cancel the request or continue. If the user enters the PIN values and chooses to continue the implementation is responsible for presenting the PIN value to the card to the card.

param
pinID the type of PIN the implementation is suppose to prompt the user to change.
return
result of changing the PIN value which is the status word recived from the smart card in the form of a byte array. This method would return null if the user cancels the request.
exception
IOException is thrown if the PIN could not be communicated with the card due to IO problems such as if the connection was closed before the command could be completed successfully.
exception
InterruptedIOException is thrown if the connection object is closed before a reply from the card is received.
exception
SecurityException is thrown if the J2ME application does not have appropriate rights to ask for changing the PIN value.

        return doEnterPin(pinID, 0, ACLPermissions.CMD_CHANGE);
    
private voidcheckHandle(Handle h)
Checks if given handle is still valid.

param
h Handle to be checked.
exception
IOException is thrown if connection is closed
exception
InterruptedIOException is thrown if connection closed and re-established again.

        if (h == null || !h.opened 
                || h.getCardSessionId() == -1) {
            throw new IOException("Connection closed");
        }
        if (h.getCardSessionId() != h.cardSessionId) {
            throw new InterruptedIOException("Connection closed");
        }
    
public voidclose()
Closes the connection.

exception
IOException if an I/O error occurs

        /* 
         * IMPL_NOTE: To pass JDTS test 
         * com.sun.satsa.apdu.exchange.interruptedIOClosed next lines 
         * should be uncommented
         */
         // try {Thread.sleep(1000); } 
         // catch (InterruptedException ignored) {}
         
        if (h != null) {
            Handle w = h;
            h = null;
            APDUManager.closeConnection(w);
        }
    
public byte[]disablePin(int pinID)
A call to disablePin method pops up a UI that requests the the user to enter the value for the PIN that is to be disabled. The pinID field indicates which PIN is to be disabled. The user can either cancel the request or continue. If the user enters the PIN and chooses to continue the implementation is responsible for presenting the PIN value to the card to disable PIN.

param
pinID the type of PIN the implementation is required to prompt the user to enter.
return
result of disabling the PIN value which is the status word recived from the smart card in the form of a byte array. This method would return null if the user cancels the request.
exception
IOException is thrown if the PIN could not be communicated with the card due to IO problems such as if the connection was closed before the command could be completed successfully.
exception
InterruptedIOException is thrown if the connection object is closed before a reply from the card is received.
exception
SecurityException is thrown if the J2ME application does not have appropriate rights to ask for disabling the PIN.

        return doEnterPin(pinID, 0, ACLPermissions.CMD_DISABLE);
    
private byte[]doEnterPin(int pinID, int uPinID, int action)
Performs PIN entry operation.

param
pinID PIN identifier.
param
uPinID unblocking PIN identifier.
param
action PIN operation identifier.
return
result of PIN verification which is the status word received from the smart card in the form of a byte array. This method would return null if the user cancels the request.
exception
IOException is thrown if the PIN could not be communicated with the card due to IO problems such as if the connection was closed before the command could be completed successfully.
exception
InterruptedIOException is thrown if the connection object is closed before a reply from the card is received.
exception
SecurityException is thrown if the J2ME application does not have appropriate rights to ask for PIN verification.


        checkHandle(h);

        if (openForSAT) {
            throw new SecurityException();
        }

        int header = verifier.preparePIN(pinID, uPinID, action);

        Object[] pins = verifier.enterPIN(classSecurityToken, action);

        if (pins == null) {
            return null;
        }

        byte[] pin1 = (byte[]) pins[0];
        byte[] pin2 = (pins.length == 2) ? (byte[]) pins[1] : null;

        int dataSize = pin1.length;
        if (pin2 != null) {
            dataSize += pin2.length;
        }

        byte[] command = new byte[6 + dataSize];

        command[0] = (byte) (header >> 24);
        command[1] = (byte) (header >> 16);
        command[2] = (byte) (header >> 8);
        command[3] = (byte) header;
        command[4] = (byte) dataSize;
        System.arraycopy(pin1, 0, command, 5, pin1.length);

        if (pin2 != null) {
            System.arraycopy(pin2, 0, command, 5 + pin1.length, pin2.length);
        }
        command[5 + dataSize] = 0x7f;

        byte[] result;
        try {
            // CLA can be incompatible with this logical channel
            result = exchangeAPDU(command);
        } catch (IllegalArgumentException e) {
            throw new IOException(e.getMessage());
        }
        byte[] out = new byte[2];
        System.arraycopy(result, result.length - 2, out, 0, 2);
        return out;
    
public byte[]enablePin(int pinID)
A call to enablePin method pops up a UI that requests the the user to enter the value for the PIN that is to be enabled. The pinID field indicates which PIN is to be enabled. The user can either cancel the request or continue. If the user enters the PIN and chooses to continue the implementation is responsible for presenting the PIN value to the card for enabling the PIN.

param
pinID the type of PIN the implementation is required to prompt the user to enter.
return
result of enabling the PIN value which is the status word recived from the smart card in the form of a byte array. This method would return null if the user cancels the request.
exception
IOException is thrown if the PIN could not be communicated with the card due to IO problems such as if the connection was closed before the command could be completed successfully.
exception
InterruptedIOException is thrown if the connection object is closed before a reply from the card is received.
exception
SecurityException is thrown if the J2ME application does not have appropriate rights to ask for enabling the PIN.

        return doEnterPin(pinID, 0, ACLPermissions.CMD_ENABLE);
    
public byte[]enterPin(int pinID)
A call to enterPin method pops up a UI that requests the PIN from the user. The pinID field indicates which PIN must be requested from the user. The user can either cancel the request or continue. If the user enters the PIN and chooses to continue the implementation is responsible for presenting the PIN value to the card for verification.

param
pinID the type of PIN the implementation is suppose to prompt the user to enter.
return
result of PIN verification which is the status word recived from the smart card in the form of a byte array. This method would return null if the user cancels the request.
exception
IOException is thrown if the PIN could not be communicated with the card due to IO problems such as if the connection was closed before the command could be completed successfully.
exception
InterruptedIOException is thrown if the connection object is closed before a reply from the card is received.
exception
SecurityException is thrown if the J2ME application does not have appropriate rights to ask for PIN verification.

        return doEnterPin(pinID, 0, ACLPermissions.CMD_VERIFY);
    
public byte[]exchangeAPDU(byte[] commandAPDU)
Exchanges an APDU command with a smart card application. Communication to a smart card device is synchronous. This method will block until the response has been received from the smart card application, or is interrupted. The interruption could be due to the card being removed from the card access device, the operation may timeout, or the connection may be closed from another thread accessing this connection.

param
commandAPDU a byte encoded command for the smart card application
return
a byte encoded response to the requested operation
exception
IOException is thrown if the operation was not successful, or if the connection was already closed
throws
InterruptedIOException if a timeout occurs while either trying to send the command or if this Connection object is closed during this exchange operation
throws
NullPointerException if the parameter is null
throws
SecurityException if the application does not have permission to exchange the message

            
        checkHandle(h);
        if (commandAPDU == null || commandAPDU.length < 4) {
            throw new IllegalArgumentException();
        }

        int nibble = commandAPDU[0] & 0xF0;
        boolean channelEncoded = (nibble == 0 ||
                                  (nibble >= 0x80 && nibble <= 0xA0));

        if (channelEncoded) {
            // mask off the channel information
            commandAPDU[0] &= 0xFC;
        }

        int command = Utils.getInt(commandAPDU, 0);

        if (openForSAT) {
            // check if this is an envelope by checking the INS, P1 and
            // P2 which should have values 0xC2, 0 and 0 respectively.
            if ((command & 0xffffff) != 0xC20000) {
                throw new IllegalArgumentException("Non-envelope APDU");
            }
            commandAPDU[0] = (byte) 0x80;
        } else {

            int cmd = command >> 8;
            if (cmd == 0xA404 || cmd == 0x7000 || cmd == 0x7080) {
                throw new IllegalArgumentException
                    ("Selection or channel management APDUs are not allowed");
            }

            // if channel is non-zero, valid CLA bytes are only:
            // 0x0X, 0x8X, 0x9X or 0xAX i.e. the one that can have
            // the channel information encoded in it
            if (h.channel != 0 && ! channelEncoded) {
                throw new IllegalArgumentException
                        ("Invalid CLA byte for a non-zero channel");
            }

            // check if allowed by the ACL
            verifier.checkPermission(command);

            if (channelEncoded) {
                // set channel bits in two LSB
                commandAPDU[0] |= h.channel;
            }
        }
        return APDUManager.exchangeAPDU(h, commandAPDU);
    
public byte[]getATR()
Returns the ATR message sent by smart card in response to the reset operation.

return
the ATR response message, or null if there is no message available

        byte[] result = null;
        try {
            checkHandle(h);
            result = h.getATR();
        } catch (IOException e) {
            result = null;
        }
        return result;
    
public java.io.DataInputStreamopenDataInputStream()
This method always throw IllegalArgumentException.

return
An input stream
exception
IOException If an I/O error occurs
exception
IllegalArgumentException is thrown for all requests

        throw new IllegalArgumentException("Not supported");
    
public java.io.DataOutputStreamopenDataOutputStream()
This method always throw IllegalArgumentException.

return
An output stream
exception
IOException If an I/O error occurs
exception
IllegalArgumentException is thrown for all requests

        throw new IllegalArgumentException("Not supported");
    
public java.io.InputStreamopenInputStream()
This method always throw IllegalArgumentException.

return
An input stream
exception
IOException If an I/O error occurs
exception
IllegalArgumentException is thrown for all requests

        throw new IllegalArgumentException("Not supported");
    
public java.io.OutputStreamopenOutputStream()
This method always throw IllegalArgumentException.

return
An output stream
exception
IOException If an I/O error occurs
exception
IllegalArgumentException is thrown for all requests

        throw new IllegalArgumentException("Not supported");
    
public ConnectionopenPrim(java.lang.String name, int mode, boolean timeouts)
Opens a connection.

param
name the target of the connection
param
mode indicates whether the caller intends to write to the connection. Currently, this parameter is ignored.
param
timeouts indicates whether the caller wants timeout exceptions. Currently, this parameter is ignored.
return
this connection
throws
IOException if the connection is closed or unavailable
throws
SecurityException if access is restricted by ACL


                                                                                                                          
           
              

        // parse the URI for slot number and target
        int slotIndex = name.indexOf(":");
        int targetIndex = name.indexOf(";target=");

        if (targetIndex < 0) {
            throw new IllegalArgumentException(
                    "Target missing in connection URL");
        }

        int slot;

        if (targetIndex == slotIndex + 1) {
            slot = 0;
        } else {
            try {
                slot = Integer.parseInt(
                        name.substring(slotIndex + 1, targetIndex), 16);
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Invalid slot number");
            }
        }

        String target = name.substring(targetIndex + 8);

        boolean isSAT = target.equals("SAT");
        
        // verify MIDlet permissions
        MIDletSuite ms =
            MIDletStateHandler.getMidletStateHandler().getMIDletSuite();
        try {
            if (isSAT) {
                ms.checkForPermission(Permissions.APDU_CHANNEL0,
                        "apdu:satopen");
            } else {
                ms.checkForPermission(Permissions.APDU_CONNECTION,
                        "apdu:open");
            }
        } catch (InterruptedException ie) {
            throw new InterruptedIOException(
                    "Interrupted while trying to ask the user permission");
        } 

        // open connection

        if (isSAT) {
            boolean satSlot;
            try {
                satSlot = APDUManager.isSatSlot(slot);
            } catch (IllegalArgumentException e) {
                satSlot = false;
            }
            if (!satSlot) {
                throw new ConnectionNotFoundException("Invalid slot for SIM");
            }
            h = APDUManager.openSATConnection(slot, classSecurityToken);
            openForSAT = true;
        } else {

            APDUManager.checkSlotNumber(slot);

            byte[] apdu = new byte[32];
            apdu[1] = (byte) 0xa4;
            apdu[2] = 4;

            boolean ok;
            try {
                int len = APDUManager.parseDottedBytes(target, apdu, 5);
                apdu[4] = (byte) len;
                apdu[5 + len] = 127;
                ok = len > 4 && len < 17;
            } catch (NullPointerException npe) {
                ok = false;
            } catch (IndexOutOfBoundsException iobe) {
                ok = false;
            } catch (NumberFormatException nfe) {
                ok = false;
            } catch (IllegalArgumentException iae) {
                ok = false;
            }

            if (! ok) {
                throw new IllegalArgumentException("Invalid AID");
            }

            APDUManager.initACL(slot, classSecurityToken);
            verifier = AccessControlManager
                .getAPDUPermissions(slot,
                apdu,
                ((MIDletSuiteImpl)ms).getInstallInfo().getCA());

            h = APDUManager.selectApplication(apdu, slot,
                                              classSecurityToken);
        }
        return this;
    
public byte[]unblockPin(int blockedPinID, int unblockingPinId)
This is a high-level method that lets the J2ME application ask the user to enter the value for an unblocking PIN, and the new value for the blocked PIN and send these to the card. A call to unblockPin method pops up a UI that requests the user to enter the value for the unblocking PIN and the new value for the blocked PIN. The unblockingPinID field indicates which unblocking PIN is to be used to unblock the blocked PIN which is indicated by the field blockedPinId. The unblockingPinID field indicates which PIN is to be unblocked. The user can either cancel the request or continue. If the user enters the PIN values and chooses to continue, the implementation is responsible for presenting the PIN values to the card for unblocking the blocked PIN. If padding is required for either of the PIN values, the implementation is responsible for providing appropriate padding.

param
blockedPinID the Id of PIN that is to be unblocked.
param
unblockingPinId the Id of unblocking PIN.
return
result of unblocking the PIN value which is the status word received from the smart card in the form of a byte array. This method would return null if the user cancels the request.
exception
IOException is thrown if the PIN could not be communicated with the card because the connection was closed before this method was called or because of communication problems.
throws
InterruptedIOException can be thrown in any of these situations:
  • if this Connection object is closed during the exchange operation
  • if the card is removed after connection is established and then reinserted, and attempt is made to unblock PIN without re-establishing the connection
exception
SecurityException is thrown if the J2ME application does not have appropriate rights to ask for unblocking the PIN.

        return doEnterPin(blockedPinID, unblockingPinId,
                          ACLPermissions.CMD_UNBLOCK);