Fields Summary |
---|
private static com.sun.midp.security.SecurityToken | classSecurityTokenThis class has a different security domain than the MIDlet suite |
private static final int | APDUBufferSizeSize of APDU buffer. |
private Remote | initialReferenceStub object for initial remote reference. |
private Reference | internalReferenceReference object for initial remote reference. |
private byte[] | APDUBufferRemote reference uses this buffer to prepare INVOKE APDU command. |
private int | offsetCurrent offset in APDUBuffer buffer for
write methods. |
private byte[] | responseResponse APDU data. |
private int | r_offsetCurrent offset in response buffer for
read methods. |
private com.sun.midp.crypto.MessageDigest | SHASHA-1 message digest object used by this connection. |
private com.sun.midp.io.j2me.apdu.Handle | hThe current APDU connection handle. |
private boolean | connectionOpenA flag to indicate if connection is open or not. |
private com.sun.satsa.acl.JCRMIPermissions | verifierThis object verifies access rights of MIDlet. |
private static final byte | NormalTagConstant for JCRMI protocol. |
private static final byte | ExactExceptionTagConstant for JCRMI protocol. |
private static final byte | ExceptionSubclassTagConstant for JCRMI protocol. |
private static final byte | ErrorTagConstant for JCRMI protocol. |
Methods Summary |
---|
public short | changePin(int pinID)A call to changePin method pops up a UI that requests
the user for an old or existing PIN value and the new PIN value to
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
the old and new values of the PIN to the card.
return doEnterPin(pinID, 0, ACLPermissions.CMD_CHANGE);
|
public void | close()Closes the connection.
synchronized (APDUBuffer) {
if (connectionOpen) {
connectionOpen = false;
APDUManager.closeConnection(h);
}
}
|
private java.rmi.Remote | createStub()Creates stub using remote reference descriptor in
response buffer at r_offset offset.
short objectID = getShort();
if (objectID == (short) 0xffff) {
return null; // null reference returned
}
// hash modifier
String hashModifier = getString();
// list of interfaces
int count = getByte();
Class stubClass = null;
String className = null;
String packageName = null;
Class[] classes = new Class[count];
for (int i = 0; i < count; i++) {
String name = getString();
if (name != null) {
packageName = name.replace('/", '.");
}
name = packageName + "." + getString();
try {
classes[i] = Class.forName(name);
} catch (ClassNotFoundException e) {
throw new RemoteException("Class not found", e);
}
if (stubClass == null ||
stubClass.isAssignableFrom(classes[i])) {
stubClass = classes[i];
className = name;
continue;
}
}
for (int i = 0; i < count; i++) {
if (! classes[i].isAssignableFrom(stubClass)) {
throw new RemoteException(
"Incorrect hierarchy in descriptor");
}
}
RemoteStub stub;
try {
stub = (RemoteStub)
(Class.forName(className + "_Stub").newInstance());
} catch (ClassNotFoundException cnfe) {
throw new RemoteException("Can't find stub class", cnfe);
} catch (IllegalAccessException iae) {
throw new RemoteException("Access to stub class denied", iae);
} catch (InstantiationException ie) {
throw new RemoteException("Can't create stub object", ie);
}
Reference r = new Reference(this, objectID, hashModifier, className);
if (internalReference == null) {
internalReference = r;
}
stub.setRef(r);
return (Remote) stub;
|
public short | disablePin(int pinID)A call to disablePin method pops up a UI that requests
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.
return doEnterPin(pinID, 0, ACLPermissions.CMD_DISABLE);
|
private short | doEnterPin(int pinID, int uPinID, int action)Performs PIN entry operation.
if (! connectionOpen) {
throw new RemoteException("Connection is closed.");
}
String method = null;
method = verifier.preparePIN(pinID, uPinID, action,
internalReference.getClassName());
Object[] pins = verifier.enterPIN(classSecurityToken, action);
if (pins == null) {
return PINENTRY_CANCELLED;
}
try {
Short r = (Short) invoke(internalReference, method, pins);
return r.shortValue();
} catch (Exception e) {
throw new RemoteException("" + e);
}
|
public short | enablePin(int pinID)A call to enablePin method pops up a UI that requests
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.
return doEnterPin(pinID, 0, ACLPermissions.CMD_ENABLE);
|
public short | 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 entered by the user to the card for verification.
return doEnterPin(pinID, 0, ACLPermissions.CMD_VERIFY);
|
private int | getByte()Reads one byte from response APDU, zero-extends it to type
int , and returns the result.
return response[r_offset++] & 0xff;
|
int | getCardSessionId()Returns the card session identifier for this connection.
return h.cardSessionId;
|
public java.rmi.Remote | getInitialReference()Returns the stub object for an initial remote reference.
return initialReference;
|
private int | getInt()Reads int value from response APDU.
return (getByte() << 24) |
(getByte() << 16) |
(getByte() << 8) |
getByte();
|
private short | getShort()Reads short value from response APDU
return (short) (getByte() << 8 | getByte());
|
private java.lang.String | getString()Reads String value from response APDU.
int len = getByte();
if (len == 0) {
return null;
}
String S;
try {
S = new String(response, r_offset, len, Utils.utf8);
} catch (UnsupportedEncodingException e) {
throw new RemoteException("UTF-8 encoding is not supported");
}
r_offset += len;
return S;
|
java.lang.Object | invoke(Reference ref, java.lang.String method, java.lang.Object[] params)Invokes a remote method.
The remote method invoked on the card can throw an exception to
signal that an unexpected condition has been detected.
If the exception thrown on the card is an exception defined in
the Java Card 2.2 API, then the same exception is thrown to the
stub method. The client can access the reason code associated
with Java Card-specific exceptions using the standard
getReason() method.
If the exception thrown on the card is a subclass of an exception
defined in the Java Card 2.2 API, then the closest exception defined
in the API (along with the reason code, if applicable) is
thrown to the stub method. The detail message string of the
exception object may indicate that exception subclass was thrown
on the card.
Apart from the exceptions thrown by the remote method itself,
errors during communication, marshalling, protocol handling,
unmarshalling, stub object instantiation, and so on, related
to the JCRMI method invocation, results in a
RemoteException being thrown to the stub method.
if (! connectionOpen) {
throw new RemoteException("Connection is closed.");
}
verifier.checkPermission(ref.getClassName(), method);
synchronized (APDUBuffer) {
try {
marshal(ref, method, params);
} catch (RuntimeException ai) {
throw new RemoteException("Error marshalling parameters");
}
try {
response = APDUManager.exchangeAPDU(h, APDUBuffer);
} catch (IOException e) {
throw new RemoteException("IO error", e);
}
r_offset = response.length - 2;
if (getShort() != (short) 0x9000) {
throw new RemoteException("Incorrect status word");
}
r_offset = 0;
byte tag = (byte) getByte();
Exception ex = null;
Object result = null;
try {
if (tag == ExactExceptionTag || tag == ExceptionSubclassTag) {
ex = parseException(tag);
} else
if (tag == ErrorTag) {
ex = parseError();
} else
if (tag == NormalTag) {
result = parseResult(method);
} else {
throw new RemoteException("Incorrect tag value: " + tag);
}
getShort(); // status word
} catch (RuntimeException e) {
throw new RemoteException("Incorrect response structure");
}
if (ex != null) {
throw ex;
}
return result;
}
|
boolean | isOpened()Returns the flag that indicates if connection is open.
return connectionOpen;
|
private void | marshal(Reference ref, java.lang.String method, java.lang.Object[] params)Prepares INVOKE APDU.
offset = 5;
putShort(ref.getObjectID());
String hashString = method;
String hashModifier = ref.getHashModifier();
if (hashModifier != null) {
hashString = hashModifier + hashString;
}
byte[] buf = Utils.stringToBytes(hashString);
SHA.reset();
SHA.update(buf, 0, buf.length);
try {
SHA.digest(APDUBuffer, offset, SHA.getDigestLength());
} catch (GeneralSecurityException e) {
throw new RemoteException("SHA1 error");
}
offset += 2;
if (params != null) {
for (int i = 0; i < params.length; i++) {
Object obj = params[i];
if (obj == null) {
putByte(0xff);
continue;
}
if (obj instanceof Byte) {
putByte(((Byte)obj).byteValue());
continue;
}
if (obj instanceof Boolean) {
putByte(((Boolean)obj).booleanValue() ? 1 : 0);
continue;
}
if (obj instanceof Short) {
putShort(((Short)obj).shortValue());
continue;
}
if (obj instanceof Integer) {
putInt(((Integer)obj).intValue());
continue;
}
if (obj instanceof byte[]) {
byte[] param = (byte[]) obj;
putByte(param.length);
for (int k = 0; k < param.length; k++) {
putByte(param[k]);
}
continue;
}
if (obj instanceof boolean[]) {
boolean[] param = (boolean[]) obj;
putByte(param.length);
for (int k = 0; k < param.length; k++) {
putByte(param[k] ? 1 : 0);
}
continue;
}
if (obj instanceof short[]) {
short[] param = (short[]) obj;
putByte(param.length);
for (int k = 0; k < param.length; k++) {
putShort(param[k]);
}
continue;
}
if (obj instanceof int[]) {
int[] param = (int[]) obj;
putByte(param.length);
for (int k = 0; k < param.length; k++) {
putInt(param[k]);
}
continue;
}
throw new RemoteException("Incorrect parameter type");
}
}
APDUBuffer[4] = (byte) (offset - 5);
putByte(255);
|
public java.io.DataInputStream | openDataInputStream()Open and return a data input stream for a connection.
This method always throw
IllegalArgumentException .
throw new IllegalArgumentException("Not supported");
|
public java.io.DataOutputStream | openDataOutputStream()Open and return a data output stream for a connection.
This method always throw
IllegalArgumentException .
throw new IllegalArgumentException("Not supported");
|
public java.io.InputStream | openInputStream()Open and return an input stream for a connection.
This method always throw
IllegalArgumentException .
throw new IllegalArgumentException("Not supported");
|
public java.io.OutputStream | openOutputStream()Open and return an output stream for a connection.
This method always throw
IllegalArgumentException .
throw new IllegalArgumentException("Not supported");
|
public javax.microedition.io.Connection | openPrim(java.lang.String name, int mode, boolean timeouts)Connector uses this method to initialize the connection object.
This method establishes APDU connection with card application,
obtains FCI information and creates stub for initial remote
reference.
MIDletSuite midletSuite =
MIDletStateHandler.getMidletStateHandler().getMIDletSuite();
try {
midletSuite.checkForPermission(Permissions.JCRMI_CONNECTION, null);
} catch (InterruptedException ie) {
throw new InterruptedIOException(
"Interrupted while trying to ask the user permission");
}
int slotInfo;
// parse URL string for slot number and AID
try {
slotInfo = parseURL(name);
} catch (NullPointerException npe) {
throw new IllegalArgumentException("Invalid URL");
} catch (IndexOutOfBoundsException iobe) {
throw new IllegalArgumentException("Invalid URL");
} catch (IllegalArgumentException iae) {
throw new IllegalArgumentException("Invalid URL");
}
APDUManager.checkSlotNumber(slotInfo);
// get card application selected
APDUManager.initACL(slotInfo, classSecurityToken);
verifier = AccessControlManager
.getJCRMIPermissions(slotInfo,
APDUBuffer,
((MIDletSuiteImpl)midletSuite)
.getInstallInfo().getCA());
h = APDUManager.selectApplication(APDUBuffer, slotInfo,
classSecurityToken);
connectionOpen = true;
// parse FCI
byte[] FCI = h.getFCI();
byte invokeINS;
try {
// fci_tag or application_data_tag
if (FCI[0] != 0x6f || FCI[2] != 0x6e) {
throw new RemoteException("Incorrect FCI format");
}
int index = 4;
// skip unnecessary tag/value pairs
while (FCI[index] != 0x5E) { // jc_rmi_data_tag
index += 2 + (FCI[index] & 0xff);
}
index += 4;
invokeINS = FCI[index++];
if (FCI[index++] != (byte) 0x81) { // normal_tag
throw new RemoteException("Incorrect FCI format");
}
response = FCI;
r_offset = index;
initialReference = createStub();
if (initialReference == null) {
throw new RemoteException();
}
} catch (RemoteException e) {
close();
throw e;
} catch (Throwable e) {
close();
throw new RemoteException("Can't create initial reference");
}
offset = 0;
putByte(0x80 | h.channel);
putByte(invokeINS);
putShort(0x0202);
try {
SHA = MessageDigest.getInstance("SHA-1");
} catch (GeneralSecurityException e) {
// Ignore this exception
}
return this;
|
private java.rmi.RemoteException | parseError()Parses response containing data about error.
short code = getShort();
switch (code) {
case 1: return new RemoteException("Object not exported");
case 2: return new RemoteException("Method not found");
case 3: return new RemoteException("Signature mismatch");
case 4: return new RemoteException("Out of parameter resources");
case 5: return new RemoteException("Out of response resources");
case 6: return new RemoteException(
"Protocol error reported by the card");
default:
throw new RemoteException("Error reported by the card: " +
code);
}
|
private java.lang.Exception | parseException(byte tag)Parses response containing data about exception.
String message = (tag == ExactExceptionTag) ?
"Exception is thrown on card" :
"Exception subclass is thrown on card";
byte type = (byte) getByte();
short reason = getShort();
switch (type) {
case 0x00:
return new Exception(message + ": java.lang.Throwable");
case 0x01:
return new ArithmeticException(message);
case 0x02:
return new ArrayIndexOutOfBoundsException(message);
case 0x03:
return new ArrayStoreException(message);
case 0x04:
return new ClassCastException(message);
case 0x05:
return new Exception(message);
case 0x06:
return new IndexOutOfBoundsException(message);
case 0x07:
return new NegativeArraySizeException(message);
case 0x08:
return new NullPointerException(message);
case 0x09:
return new RuntimeException(message);
case 0x0A:
return new SecurityException(message);
case 0x0B:
return new IOException(message);
case 0x0C:
return new RemoteException(message);
case 0x20:
return new APDUException(reason);
case 0x21:
return new CardException(reason);
case 0x22:
return new CardRuntimeException(reason);
case 0x23:
return new ISOException(reason);
case 0x24:
return new PINException(reason);
case 0x25:
return new SystemException(reason);
case 0x26:
return new TransactionException(reason);
case 0x27:
return new UserException(reason);
case 0x30:
return new javacard.security.CryptoException(reason);
case 0x40:
return new ServiceException(reason);
default:
throw new RemoteException(
"Unknown exception is thrown on card");
}
|
private java.lang.Object | parseResult(java.lang.String method)Parses the normal JCRMI response.
int index = method.indexOf(')") + 1;
if (index != -1) {
switch (method.charAt(index)) {
case 'V": return null;
case 'B": return new Byte((byte) getByte());
case 'Z": return new Boolean(getByte() == 1 ? true : false);
case 'S": return new Short(getShort());
case 'I": return new Integer(getInt());
case 'L": return createStub();
case '[": {
int len = getByte();
if (len == 255)
return null;
switch (method.charAt(index + 1)) {
case 'B": {
byte[] data = new byte[len];
for (int i = 0; i < len; i++) {
data[i] = (byte) getByte();
}
return data;
}
case 'Z": {
boolean[] data = new boolean[len];
for (int i = 0; i < len; i++) {
data[i] = (getByte() == 1 ? true : false);
}
return data;
}
case 'S": {
short[] data = new short[len];
for (int i = 0; i < len; i++) {
data[i] = getShort();
}
return data;
}
case 'I": {
int[] data = new int[len];
for (int i = 0; i < len; i++) {
data[i] = getInt();
}
return data;
}
}
}
}
}
throw new RemoteException("Incorrect method signature");
|
private int | parseURL(java.lang.String URL)Parses the URL to get the slot number and AID.
Prepares SELECT APDU in APDUBuffer.
int slotIndex = URL.indexOf(":") + 1;
int AIDIndex = URL.indexOf(";AID=");
int slotInfo = (AIDIndex == slotIndex) ? 0 :
Integer.parseInt(URL.substring(slotIndex, AIDIndex), 16);
// prepare selection APDU
offset = 0;
// IMPL_NOTE: if the card does not support JC2.2 you must use: putInt(0x00a40400);
putInt(0x00a40410); // selection APDU header
offset++; // length
// parse for AID
int AIDLength = APDUManager.parseDottedBytes(
URL.substring(AIDIndex + 5), APDUBuffer, offset);
if (AIDLength < 5 || AIDLength > 16)
throw new IllegalArgumentException();
APDUBuffer[4] = (byte) AIDLength;
offset += AIDLength;
putByte(255);
return slotInfo;
|
private void | putByte(int param)Writes param value into APDUBuffer .
APDUBuffer[offset++] = (byte) param;
|
private void | putInt(int param)Writes param value into APDUBuffer .
putByte(param >> 24);
putByte(param >> 16);
putByte(param >> 8);
putByte(param);
|
private void | putShort(int param)Writes param value into APDUBuffer .
putByte(param >> 8);
putByte(param);
|
public short | 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.
return doEnterPin(blockedPinID, unblockingPinId,
ACLPermissions.CMD_UNBLOCK);
|