0001: /*
0002: *
0003: *
0004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: */
0026:
0027: package com.sun.io.j2me.jcrmi;
0028:
0029: import com.sun.j2me.app.AppPackage;
0030: import com.sun.j2me.security.SatsaPermission;
0031: import java.io.*;
0032: import java.rmi.Remote;
0033: import java.rmi.RemoteException;
0034: import com.sun.j2me.crypto.NoSuchAlgorithmException;
0035: import com.sun.j2me.crypto.DigestException;
0036: import com.sun.j2me.crypto.MessageDigest;
0037: import javax.microedition.io.Connection;
0038: import javax.microedition.io.StreamConnection;
0039: import javax.microedition.jcrmi.JavaCardRMIConnection;
0040: import javax.microedition.jcrmi.RemoteStub;
0041:
0042: import com.sun.j2me.io.ConnectionBaseInterface;
0043: import com.sun.io.j2me.apdu.APDUManager;
0044: import com.sun.io.j2me.apdu.Handle;
0045: import com.sun.satsa.acl.ACLPermissions;
0046: import com.sun.satsa.acl.AccessControlManager;
0047: import com.sun.satsa.acl.JCRMIPermissions;
0048: import com.sun.satsa.util.Utils;
0049: import javacard.framework.*;
0050: import javacard.framework.service.ServiceException;
0051:
0052: import com.sun.j2me.main.Configuration;
0053:
0054: import com.sun.j2me.security.TrustedClass;
0055: import com.sun.j2me.security.Token;
0056: import com.sun.satsa.security.SecurityInitializer;
0057:
0058: /**
0059: * JCRMI connection to card application.
0060: */
0061: public class Protocol implements JavaCardRMIConnection,
0062: ConnectionBaseInterface, StreamConnection {
0063:
0064: /*
0065: * Inner class to request security token from SecurityTokenInitializer.
0066: * SecurityTokenInitializer should be able to check this inner class name.
0067: */
0068: static private class SecurityTrusted implements TrustedClass {
0069: };
0070:
0071: /** This class has a different security domain than the App suite */
0072: private static Token securityToken = SecurityInitializer
0073: .requestToken(new SecurityTrusted());
0074:
0075: /**
0076: * Size of APDU buffer.
0077: */
0078: private static final int APDUBufferSize = 255;
0079:
0080: /**
0081: * Stub object for initial remote reference.
0082: */
0083: private Remote initialReference;
0084:
0085: /**
0086: * Reference object for initial remote reference.
0087: */
0088: private Reference internalReference;
0089:
0090: /**
0091: * Remote reference uses this buffer to prepare INVOKE APDU command.
0092: */
0093: private byte[] APDUBuffer = new byte[APDUBufferSize];
0094:
0095: /**
0096: * Current offset in <code>APDUBuffer</code> buffer for
0097: * <code>write</code> methods.
0098: */
0099: private int offset;
0100:
0101: /**
0102: * Response APDU data.
0103: */
0104: private byte[] response;
0105:
0106: /**
0107: * Current offset in <code>response</code> buffer for
0108: * <code>read</code> methods.
0109: */
0110: private int r_offset;
0111:
0112: /**
0113: * SHA-1 message digest object used by this connection.
0114: */
0115: private MessageDigest SHA;
0116:
0117: /** The current APDU connection handle. */
0118: private Handle h;
0119:
0120: /**
0121: * A flag to indicate if connection is open or not.
0122: */
0123: private boolean connectionOpen;
0124:
0125: /**
0126: * This object verifies access rights of MIDlet.
0127: */
0128: private JCRMIPermissions verifier;
0129:
0130: /**
0131: * Connector uses this method to initialize the connection object.
0132: * This method establishes APDU connection with card application,
0133: * obtains FCI information and creates stub for initial remote
0134: * reference.
0135: * @param name the URL for the connection without protocol name
0136: * @param mode the access mode (Ignored)
0137: * @param timeouts a flag to indicate that the caller wants timeout
0138: * exceptions. Ignored
0139: * @return this connection
0140: * @throws IOException if the connection can not be initialized
0141: * @throws RemoteException if initial remote reference object can not be
0142: * created
0143: * @throws SecurityException if access is restricted by ACL
0144: */
0145: public Connection openPrim(String name, int mode, boolean timeouts)
0146: throws IOException {
0147:
0148: AppPackage appPackage = AppPackage.getInstance();
0149: try {
0150: appPackage
0151: .checkForPermission(SatsaPermission.JCRMI_CONNECTION);
0152: } catch (InterruptedException ie) {
0153: throw new InterruptedIOException(
0154: "Interrupted while trying to ask the user permission");
0155: }
0156:
0157: int slotInfo;
0158: // parse URL string for slot number and AID
0159: try {
0160: slotInfo = parseURL(name);
0161: } catch (NullPointerException npe) {
0162: throw new IllegalArgumentException("Invalid URL");
0163: } catch (IndexOutOfBoundsException iobe) {
0164: throw new IllegalArgumentException("Invalid URL");
0165: } catch (IllegalArgumentException iae) {
0166: throw new IllegalArgumentException("Invalid URL");
0167: }
0168:
0169: APDUManager.checkSlotNumber(slotInfo);
0170: // get card application selected
0171: APDUManager.initACL(slotInfo);
0172: verifier = AccessControlManager.getJCRMIPermissions(slotInfo,
0173: APDUBuffer, appPackage.getCA());
0174:
0175: h = APDUManager.selectApplication(APDUBuffer, slotInfo);
0176:
0177: connectionOpen = true;
0178:
0179: // parse FCI
0180: byte[] FCI = h.getFCI();
0181:
0182: byte invokeINS;
0183:
0184: try {
0185: // fci_tag or application_data_tag
0186: if (FCI[0] != 0x6f || FCI[2] != 0x6e) {
0187: throw new RemoteException("Incorrect FCI format");
0188: }
0189:
0190: int index = 4;
0191:
0192: // skip unnecessary tag/value pairs
0193: while (FCI[index] != 0x5E) { // jc_rmi_data_tag
0194: index += 2 + (FCI[index] & 0xff);
0195: }
0196:
0197: index += 4;
0198:
0199: invokeINS = FCI[index++];
0200:
0201: if (FCI[index++] != (byte) 0x81) { // normal_tag
0202: throw new RemoteException("Incorrect FCI format");
0203: }
0204:
0205: response = FCI;
0206: r_offset = index;
0207:
0208: initialReference = createStub();
0209:
0210: if (initialReference == null) {
0211: throw new RemoteException();
0212: }
0213: } catch (RemoteException e) {
0214: close();
0215: throw e;
0216: } catch (Throwable e) {
0217: close();
0218: throw new RemoteException("Can't create initial reference");
0219: }
0220:
0221: offset = 0;
0222: putByte(0x80 | h.channel);
0223: putByte(invokeINS);
0224: putShort(0x0202);
0225:
0226: try {
0227: SHA = new MessageDigest("SHA-1");
0228: } catch (NoSuchAlgorithmException e) {
0229: // Ignore this exception
0230: }
0231:
0232: return this ;
0233: }
0234:
0235: /**
0236: * Closes the connection.
0237: * @throws IOException If an I/O error occurs
0238: */
0239: public void close() throws IOException {
0240: synchronized (APDUBuffer) {
0241: if (connectionOpen) {
0242: connectionOpen = false;
0243: APDUManager.closeConnection(h);
0244: }
0245: }
0246: }
0247:
0248: /**
0249: * Returns the stub object for an initial remote reference.
0250: * @return the initial remote reference
0251: */
0252: public java.rmi.Remote getInitialReference() {
0253: return initialReference;
0254: }
0255:
0256: /**
0257: * Parses the URL to get the slot number and AID.
0258: * Prepares SELECT APDU in APDUBuffer.
0259: * @param URL contains the URL from which
0260: * the slot information is to be extracted
0261: * @return slot number for this connection
0262: */
0263: private int parseURL(String URL) {
0264:
0265: int slotIndex = URL.indexOf(":") + 1;
0266: int AIDIndex = URL.indexOf(";AID=");
0267:
0268: int slotInfo = (AIDIndex == slotIndex) ? 0 : Integer.parseInt(
0269: URL.substring(slotIndex, AIDIndex), 16);
0270:
0271: // prepare selection APDU
0272: offset = 0;
0273:
0274: // IMPL_NOTE: For JavaCard 2.1 compliant cards jcrmi emulation is used.
0275: String jcVersion = Configuration
0276: .getProperty("com.sun.javacard.version");
0277: if ((jcVersion.equals("2.1")) || (jcVersion.startsWith("2.1."))) {
0278: putInt(0x00a40400); // selection APDU header
0279: } else {
0280: putInt(0x00a40410); // selection APDU header
0281: }
0282: offset++; // length
0283:
0284: // parse for AID
0285: int AIDLength = APDUManager.parseDottedBytes(URL
0286: .substring(AIDIndex + 5), APDUBuffer, offset);
0287:
0288: if (AIDLength < 5 || AIDLength > 16)
0289: throw new IllegalArgumentException();
0290:
0291: APDUBuffer[4] = (byte) AIDLength;
0292: offset += AIDLength;
0293: putByte(255);
0294:
0295: return slotInfo;
0296: }
0297:
0298: /**
0299: * Writes <code>param</code> value into <code>APDUBuffer</code>.
0300: * @param param the value to be written
0301: */
0302: private void putByte(int param) {
0303: APDUBuffer[offset++] = (byte) param;
0304: }
0305:
0306: /**
0307: * Writes <code>param</code> value into <code>APDUBuffer</code>.
0308: * @param param the value to be written
0309: */
0310: private void putShort(int param) {
0311: putByte(param >> 8);
0312: putByte(param);
0313: }
0314:
0315: /**
0316: * Writes <code>param</code> value into <code>APDUBuffer</code>.
0317: * @param param the value to be written
0318: */
0319: private void putInt(int param) {
0320: putByte(param >> 24);
0321: putByte(param >> 16);
0322: putByte(param >> 8);
0323: putByte(param);
0324: }
0325:
0326: /**
0327: * Reads one byte from response APDU, zero-extends it to type
0328: * <code>int</code>, and returns the result.
0329: * @return the unsigned 8-bit value
0330: */
0331: private int getByte() {
0332: return response[r_offset++] & 0xff;
0333: }
0334:
0335: /**
0336: * Reads <code>short</code> value from response APDU
0337: * @return <code>short</code> value
0338: */
0339: private short getShort() {
0340: return (short) (getByte() << 8 | getByte());
0341: }
0342:
0343: /**
0344: * Reads <code>int</code> value from response APDU.
0345: * @return <code>int</code> value
0346: */
0347: private int getInt() {
0348: return (getByte() << 24) | (getByte() << 16) | (getByte() << 8)
0349: | getByte();
0350: }
0351:
0352: /**
0353: * Reads <code>String</code> value from response APDU.
0354: * @return <code>String</code> value
0355: */
0356: private String getString() throws RemoteException {
0357:
0358: int len = getByte();
0359:
0360: if (len == 0) {
0361: return null;
0362: }
0363:
0364: String S;
0365: try {
0366: S = new String(response, r_offset, len, Utils.utf8);
0367: } catch (UnsupportedEncodingException e) {
0368: throw new RemoteException("UTF-8 encoding is not supported");
0369: }
0370: r_offset += len;
0371: return S;
0372: }
0373:
0374: /**
0375: * Creates stub using remote reference descriptor in
0376: * <code>response</code> buffer at <code>r_offset </code> offset.
0377: * @return new stub object
0378: * @throws java.rmi.RemoteException if an error occurs
0379: */
0380: private Remote createStub() throws RemoteException {
0381:
0382: short objectID = getShort();
0383:
0384: if (objectID == (short) 0xffff) {
0385: return null; // null reference returned
0386: }
0387:
0388: // hash modifier
0389: String hashModifier = getString();
0390:
0391: // list of interfaces
0392:
0393: int count = getByte();
0394:
0395: Class stubClass = null;
0396: String className = null;
0397: String packageName = null;
0398: Class[] classes = new Class[count];
0399:
0400: for (int i = 0; i < count; i++) {
0401:
0402: String name = getString();
0403: if (name != null) {
0404: packageName = name.replace('/', '.');
0405: }
0406:
0407: name = packageName + "." + getString();
0408:
0409: try {
0410: classes[i] = Class.forName(name);
0411: } catch (ClassNotFoundException e) {
0412: throw new RemoteException("Class not found", e);
0413: }
0414:
0415: if (stubClass == null
0416: || stubClass.isAssignableFrom(classes[i])) {
0417: stubClass = classes[i];
0418: className = name;
0419: continue;
0420: }
0421: }
0422:
0423: for (int i = 0; i < count; i++) {
0424: if (!classes[i].isAssignableFrom(stubClass)) {
0425: throw new RemoteException(
0426: "Incorrect hierarchy in descriptor");
0427: }
0428: }
0429:
0430: RemoteStub stub;
0431: try {
0432: stub = RemoteStubCreation.createStub(className + "_Stub");
0433: } catch (ClassNotFoundException cnfe) {
0434: throw new RemoteException("Can't find stub class", cnfe);
0435: } catch (IllegalAccessException iae) {
0436: throw new RemoteException("Access to stub class denied",
0437: iae);
0438: } catch (InstantiationException ie) {
0439: throw new RemoteException("Can't create stub object", ie);
0440: }
0441: Reference r = new Reference(this , objectID, hashModifier,
0442: className);
0443: if (internalReference == null) {
0444: internalReference = r;
0445: }
0446: stub.setRef(r);
0447:
0448: return (Remote) stub;
0449: }
0450:
0451: /**
0452: * Constant for JCRMI protocol.
0453: */
0454: private static final byte NormalTag = (byte) 0x81;
0455: /**
0456: * Constant for JCRMI protocol.
0457: */
0458: private static final byte ExactExceptionTag = (byte) 0x82;
0459: /**
0460: * Constant for JCRMI protocol.
0461: */
0462: private static final byte ExceptionSubclassTag = (byte) 0x83;
0463: /**
0464: * Constant for JCRMI protocol.
0465: */
0466: private static final byte ErrorTag = (byte) 0x99;
0467:
0468: /**
0469: * Invokes a remote method.
0470: *
0471: * The remote method invoked on the card can throw an exception to
0472: * signal that an unexpected condition has been detected.<p>
0473: *
0474: * If the exception thrown on the card is an exception defined in
0475: * the Java Card 2.2 API, then the same exception is thrown to the
0476: * stub method. The client can access the reason code associated
0477: * with Java Card-specific exceptions using the standard
0478: * <code>getReason()</code> method.<p>
0479: *
0480: * If the exception thrown on the card is a subclass of an exception
0481: * defined in the Java Card 2.2 API, then the closest exception defined
0482: * in the API (along with the reason code, if applicable) is
0483: * thrown to the stub method. The detail message string of the
0484: * exception object may indicate that exception subclass was thrown
0485: * on the card.<p>
0486: *
0487: * Apart from the exceptions thrown by the remote method itself,
0488: * errors during communication, marshalling, protocol handling,
0489: * unmarshalling, stub object instantiation, and so on, related
0490: * to the JCRMI method invocation, results in a
0491: * <code>RemoteException</code> being thrown to the stub method.
0492: *
0493: * @param ref handle for remote object
0494: * @param method simple (not fully qualified) name of the method
0495: * followed by the method descriptor. Representation of a
0496: * method descriptor is the same as that described in The
0497: * Java Virtual Machine Specification (§ 4.3.3)
0498: * @param params the parameter list
0499: * @return result of remote method invocation
0500: * @exception java.lang.Exception if any exception occurs during
0501: * the remote method invocation
0502: */
0503: Object invoke(Reference ref, String method, Object[] params)
0504: throws Exception {
0505:
0506: if (!connectionOpen) {
0507: throw new RemoteException("Connection is closed.");
0508: }
0509:
0510: verifier.checkPermission(ref.getClassName(), method);
0511:
0512: synchronized (APDUBuffer) {
0513:
0514: try {
0515: marshal(ref, method, params);
0516: } catch (RuntimeException ai) {
0517: throw new RemoteException(
0518: "Error marshalling parameters");
0519: }
0520:
0521: try {
0522: response = APDUManager.exchangeAPDU(h, APDUBuffer);
0523: } catch (IOException e) {
0524: throw new RemoteException("IO error", e);
0525: }
0526:
0527: r_offset = response.length - 2;
0528:
0529: if (getShort() != (short) 0x9000) {
0530: throw new RemoteException("Incorrect status word");
0531: }
0532:
0533: r_offset = 0;
0534:
0535: byte tag = (byte) getByte();
0536:
0537: Exception ex = null;
0538: Object result = null;
0539:
0540: try {
0541: if (tag == ExactExceptionTag
0542: || tag == ExceptionSubclassTag) {
0543: ex = parseException(tag);
0544: } else if (tag == ErrorTag) {
0545: ex = parseError();
0546: } else if (tag == NormalTag) {
0547: result = parseResult(method);
0548: } else {
0549: throw new RemoteException("Incorrect tag value: "
0550: + tag);
0551: }
0552:
0553: getShort(); // status word
0554:
0555: } catch (RuntimeException e) {
0556: throw new RemoteException(
0557: "Incorrect response structure");
0558: }
0559:
0560: if (ex != null) {
0561: throw ex;
0562: }
0563:
0564: return result;
0565: }
0566: }
0567:
0568: /**
0569: * Prepares INVOKE APDU.
0570: * @param ref handle for remote object
0571: * @param method simple (not fully qualified) name of the method
0572: * followed by the method descriptor. Representation of a
0573: * method descriptor is the same as that described in The
0574: * Java Virtual Machine Specification (§ 4.3.3)
0575: * @param params the parameter list
0576: * @throws RemoteException if an error occurs
0577: */
0578: private void marshal(Reference ref, String method, Object[] params)
0579: throws RemoteException {
0580:
0581: offset = 5;
0582:
0583: putShort(ref.getObjectID());
0584:
0585: String hashString = method;
0586: String hashModifier = ref.getHashModifier();
0587:
0588: if (hashModifier != null) {
0589: hashString = hashModifier + hashString;
0590: }
0591:
0592: byte[] buf = Utils.stringToBytes(hashString);
0593:
0594: SHA.reset();
0595: SHA.update(buf, 0, buf.length);
0596: try {
0597: SHA.digest(APDUBuffer, offset, SHA.getDigestLength());
0598: } catch (DigestException e) {
0599: throw new RemoteException("SHA1 error");
0600: }
0601:
0602: offset += 2;
0603:
0604: if (params != null) {
0605: for (int i = 0; i < params.length; i++) {
0606:
0607: Object obj = params[i];
0608:
0609: if (obj == null) {
0610: putByte(0xff);
0611: continue;
0612: }
0613:
0614: if (obj instanceof Byte) {
0615: putByte(((Byte) obj).byteValue());
0616: continue;
0617: }
0618:
0619: if (obj instanceof Boolean) {
0620: putByte(((Boolean) obj).booleanValue() ? 1 : 0);
0621: continue;
0622: }
0623:
0624: if (obj instanceof Short) {
0625: putShort(((Short) obj).shortValue());
0626: continue;
0627: }
0628:
0629: if (obj instanceof Integer) {
0630: putInt(((Integer) obj).intValue());
0631: continue;
0632: }
0633:
0634: if (obj instanceof byte[]) {
0635: byte[] param = (byte[]) obj;
0636: putByte(param.length);
0637: for (int k = 0; k < param.length; k++) {
0638: putByte(param[k]);
0639: }
0640: continue;
0641: }
0642:
0643: if (obj instanceof boolean[]) {
0644: boolean[] param = (boolean[]) obj;
0645: putByte(param.length);
0646: for (int k = 0; k < param.length; k++) {
0647: putByte(param[k] ? 1 : 0);
0648: }
0649: continue;
0650: }
0651:
0652: if (obj instanceof short[]) {
0653: short[] param = (short[]) obj;
0654: putByte(param.length);
0655: for (int k = 0; k < param.length; k++) {
0656: putShort(param[k]);
0657: }
0658: continue;
0659: }
0660:
0661: if (obj instanceof int[]) {
0662: int[] param = (int[]) obj;
0663: putByte(param.length);
0664: for (int k = 0; k < param.length; k++) {
0665: putInt(param[k]);
0666: }
0667: continue;
0668: }
0669:
0670: throw new RemoteException("Incorrect parameter type");
0671: }
0672: }
0673: APDUBuffer[4] = (byte) (offset - 5);
0674:
0675: putByte(255);
0676: }
0677:
0678: /**
0679: * Parses response containing data about exception.
0680: * @param tag type tag of exception
0681: * @return the exception to be thrown to stub
0682: * @throws RemoteException if an error occurs during parsing
0683: */
0684: private Exception parseException(byte tag) throws RemoteException {
0685:
0686: String message = (tag == ExactExceptionTag) ? "Exception is thrown on card"
0687: : "Exception subclass is thrown on card";
0688:
0689: byte type = (byte) getByte();
0690: short reason = getShort();
0691:
0692: switch (type) {
0693: case 0x00:
0694: return new Exception(message + ": java.lang.Throwable");
0695: case 0x01:
0696: return new ArithmeticException(message);
0697: case 0x02:
0698: return new ArrayIndexOutOfBoundsException(message);
0699: case 0x03:
0700: return new ArrayStoreException(message);
0701: case 0x04:
0702: return new ClassCastException(message);
0703: case 0x05:
0704: return new Exception(message);
0705: case 0x06:
0706: return new IndexOutOfBoundsException(message);
0707: case 0x07:
0708: return new NegativeArraySizeException(message);
0709: case 0x08:
0710: return new NullPointerException(message);
0711: case 0x09:
0712: return new RuntimeException(message);
0713: case 0x0A:
0714: return new SecurityException(message);
0715: case 0x0B:
0716: return new IOException(message);
0717: case 0x0C:
0718: return new RemoteException(message);
0719: case 0x20:
0720: return new APDUException(reason);
0721: case 0x21:
0722: return new CardException(reason);
0723: case 0x22:
0724: return new CardRuntimeException(reason);
0725: case 0x23:
0726: return new ISOException(reason);
0727: case 0x24:
0728: return new PINException(reason);
0729: case 0x25:
0730: return new SystemException(reason);
0731: case 0x26:
0732: return new TransactionException(reason);
0733: case 0x27:
0734: return new UserException(reason);
0735: case 0x30:
0736: return new javacard.security.CryptoException(reason);
0737: case 0x40:
0738: return new ServiceException(reason);
0739: default:
0740: throw new RemoteException(
0741: "Unknown exception is thrown on card");
0742: }
0743: }
0744:
0745: /**
0746: * Parses response containing data about error.
0747: * @return the exception to be thrown to stub
0748: * @throws RemoteException if error code is unknown
0749: */
0750: private RemoteException parseError() throws RemoteException {
0751:
0752: short code = getShort();
0753:
0754: switch (code) {
0755: case 1:
0756: return new RemoteException("Object not exported");
0757: case 2:
0758: return new RemoteException("Method not found");
0759: case 3:
0760: return new RemoteException("Signature mismatch");
0761: case 4:
0762: return new RemoteException("Out of parameter resources");
0763: case 5:
0764: return new RemoteException("Out of response resources");
0765: case 6:
0766: return new RemoteException(
0767: "Protocol error reported by the card");
0768: default:
0769: throw new RemoteException("Error reported by the card: "
0770: + code);
0771: }
0772: }
0773:
0774: /**
0775: * Parses the normal JCRMI response.
0776: * @param method method name and signature
0777: * @return the value returned by method
0778: * @throws RemoteException if an error occurs during parsing
0779: */
0780: private Object parseResult(String method) throws RemoteException {
0781:
0782: int index = method.indexOf(')') + 1;
0783:
0784: if (index != -1) {
0785: switch (method.charAt(index)) {
0786: case 'V':
0787: return null;
0788: case 'B':
0789: return new Byte((byte) getByte());
0790: case 'Z':
0791: return new Boolean(getByte() == 1 ? true : false);
0792: case 'S':
0793: return new Short(getShort());
0794: case 'I':
0795: return new Integer(getInt());
0796: case 'L':
0797: return createStub();
0798: case '[': {
0799:
0800: int len = getByte();
0801:
0802: if (len == 255)
0803: return null;
0804:
0805: switch (method.charAt(index + 1)) {
0806: case 'B': {
0807: byte[] data = new byte[len];
0808:
0809: for (int i = 0; i < len; i++) {
0810: data[i] = (byte) getByte();
0811: }
0812: return data;
0813: }
0814: case 'Z': {
0815: boolean[] data = new boolean[len];
0816:
0817: for (int i = 0; i < len; i++) {
0818: data[i] = (getByte() == 1 ? true : false);
0819: }
0820: return data;
0821: }
0822: case 'S': {
0823: short[] data = new short[len];
0824:
0825: for (int i = 0; i < len; i++) {
0826: data[i] = getShort();
0827: }
0828: return data;
0829: }
0830: case 'I': {
0831: int[] data = new int[len];
0832:
0833: for (int i = 0; i < len; i++) {
0834: data[i] = getInt();
0835: }
0836: return data;
0837: }
0838: }
0839: }
0840: }
0841: }
0842: throw new RemoteException("Incorrect method signature");
0843: }
0844:
0845: /**
0846: * Returns the card session identifier for this connection.
0847: * @return the card session identifier
0848: */
0849: int getCardSessionId() {
0850: return h.cardSessionId;
0851: }
0852:
0853: /**
0854: * Returns the flag that indicates if connection is open.
0855: * @return true if the connection is open
0856: */
0857: boolean isOpened() {
0858: return connectionOpen;
0859: }
0860:
0861: /**
0862: * Open and return an input stream for a connection.
0863: * This method always throw
0864: * <code>IllegalArgumentException</code>.
0865: * @return An input stream
0866: * @exception IllegalArgumentException is thrown for all requests
0867: */
0868: public InputStream openInputStream() {
0869: throw new IllegalArgumentException("Not supported");
0870: }
0871:
0872: /**
0873: * Open and return a data input stream for a connection.
0874: * This method always throw
0875: * <code>IllegalArgumentException</code>.
0876: * @return An input stream
0877: * @exception IllegalArgumentException is thrown for all requests
0878: */
0879: public DataInputStream openDataInputStream() {
0880: throw new IllegalArgumentException("Not supported");
0881: }
0882:
0883: /**
0884: * Open and return an output stream for a connection.
0885: * This method always throw
0886: * <code>IllegalArgumentException</code>.
0887: * @return An output stream
0888: * @exception IllegalArgumentException is thrown for all requests
0889: */
0890: public OutputStream openOutputStream() {
0891: throw new IllegalArgumentException("Not supported");
0892: }
0893:
0894: /**
0895: * Open and return a data output stream for a connection.
0896: * This method always throw
0897: * <code>IllegalArgumentException</code>.
0898: * @return An output stream
0899: * @exception IllegalArgumentException is thrown for all requests
0900: */
0901: public DataOutputStream openDataOutputStream() {
0902: throw new IllegalArgumentException("Not supported");
0903: }
0904:
0905: /**
0906: * A call to enterPin method pops up a UI that requests the PIN
0907: * from the user. The pinID field indicates which PIN must be
0908: * requested from the user. The user can either cancel the request
0909: * or continue. If the user enters the PIN and chooses to continue,
0910: * The implementation is responsible for
0911: * presenting the PIN entered by the user to the card for verification.
0912: * @param pinID the type of PIN the implementation is suppose to prompt
0913: * the user to enter.
0914: * @return PINENTRY_CANCELLED if the user cancelled the PIN entry
0915: * request or the value returned by the remote method.
0916: * @exception java.rmi.RemoteException is thrown if the PIN could
0917: * not be communicated to the card or an exception is thrown
0918: * by the card in response to the PIN entry.
0919: * @exception SecurityException is thrown if the J2ME application does
0920: * not have appropriate rights to ask for PIN verification.
0921: */
0922: public short enterPin(int pinID) throws java.rmi.RemoteException {
0923: return doEnterPin(pinID, 0, ACLPermissions.CMD_VERIFY);
0924: }
0925:
0926: /**
0927: * A call to <code>changePin</code> method pops up a UI that requests
0928: * the user for an old or existing PIN value and the new PIN value to
0929: * to change the value of the PIN. The pinID field indicates which PIN is
0930: * to be changed. The user can either cancel the request
0931: * or continue. If the user enters the PIN values and chooses to continue
0932: * the implementation is responsible for presenting the
0933: * the old and new values of the PIN to the card.
0934: * @param pinID the type of PIN the implementation is suppose to prompt
0935: * the user to change.
0936: * @return PINENTRY_CANCELLED if the user cancelled the PIN entry
0937: * request or the value returned by the remote method.
0938: * @exception java.rmi.RemoteException is thrown if the PIN could
0939: * not be communicated to the card or an exception is thrown
0940: * by the card in response to the PIN entry.
0941: * @exception SecurityException is thrown if the J2ME application does
0942: * not have appropriate rights to ask for changing the PIN value.
0943: */
0944: public short changePin(int pinID) throws RemoteException {
0945: return doEnterPin(pinID, 0, ACLPermissions.CMD_CHANGE);
0946: }
0947:
0948: /**
0949: * A call to <code>disablePin</code> method pops up a UI that requests
0950: * the user to enter the value for the PIN that is to be disabled.
0951: * The pinID field
0952: * indicates which PIN is to be disabled. The user can
0953: * either cancel the request
0954: * or continue. If the user enters the PIN and chooses to continue the
0955: * implementation is responsible
0956: * for presenting the PIN value to the card to disable PIN.
0957: * @param pinID the type of PIN the implementation is required to prompt
0958: * the user to enter.
0959: * @return PINENTRY_CANCELLED if the user cancelled the PIN entry
0960: * request or the value returned by the remote method.
0961: * @exception java.rmi.RemoteException is thrown if the PIN could
0962: * not be communicated to the card or an exception is thrown
0963: * by the card in response to the PIN entry.
0964: * @exception SecurityException is thrown if the J2ME application does
0965: * not have appropriate rights to ask for disabling the PIN.
0966: */
0967: public short disablePin(int pinID) throws RemoteException {
0968: return doEnterPin(pinID, 0, ACLPermissions.CMD_DISABLE);
0969: }
0970:
0971: /**
0972: * A call to <code>enablePin</code> method pops up a UI that requests
0973: * the user to enter the value for the PIN that is to be enabled.
0974: * The pinID field
0975: * indicates which PIN is to be enabled. The user can
0976: * either cancel the request
0977: * or continue. If the user enters the PIN and chooses to continue the
0978: * implementation is responsible
0979: * for presenting the PIN value to the card for enabling the PIN.
0980: * @param pinID the type of PIN the implementation is required to prompt
0981: * the user to enter.
0982: * @return PINENTRY_CANCELLED if the user cancelled the PIN entry
0983: * request or the value returned by the remote method.
0984: * @exception java.rmi.RemoteException is thrown if the PIN could
0985: * not be communicated to the card or an exception is thrown
0986: * by the card in response to the PIN entry.
0987: * @exception SecurityException is thrown if the J2ME application does
0988: * not have appropriate rights to ask for enabling the PIN.
0989: */
0990: public short enablePin(int pinID) throws RemoteException {
0991: return doEnterPin(pinID, 0, ACLPermissions.CMD_ENABLE);
0992: }
0993:
0994: /**
0995: * This is a high-level method that lets the J2ME application
0996: * ask the user to enter the value for an unblocking PIN,
0997: * and the new value for the blocked PIN and send
0998: * these to the card.
0999: * A call to <code>unblockPin</code> method pops up a UI that requests
1000: * the user to enter the value for the unblocking PIN and the
1001: * new value for the blocked PIN.
1002: * The <code>unblockingPinID</code> field indicates which unblocking
1003: * PIN is to be
1004: * used to unblock the blocked PIN which is indicated by the field
1005: * <code>blockedPinId</code>.
1006: * The unblockingPinID field indicates which PIN is to be unblocked.
1007: * The user can either cancel the request
1008: * or continue. If the user enters the PIN values and chooses to continue,
1009: * the implementation is responsible
1010: * for presenting the PIN values to the card for unblocking the
1011: * blocked PIN.
1012: * If padding is required for either of the PIN values, the
1013: * implementation is responsible for providing appropriate padding.
1014: * @param blockedPinID the Id of PIN that is to be unblocked.
1015: * @param unblockingPinId the Id of unblocking PIN.
1016: * @return PINENTRY_CANCELLED if the user cancelled the PIN entry
1017: * request or the value returned by the remote method.
1018: * @exception java.rmi.RemoteException is thrown if the PIN could
1019: * not be communicated to the card or an exception is thrown
1020: * by the card in response to the PIN entry.
1021: * @exception SecurityException is thrown if the J2ME application does
1022: * not have appropriate rights to ask for unblocking the PIN.
1023: */
1024: public short unblockPin(int blockedPinID, int unblockingPinId)
1025: throws RemoteException {
1026: return doEnterPin(blockedPinID, unblockingPinId,
1027: ACLPermissions.CMD_UNBLOCK);
1028: }
1029:
1030: /**
1031: * Performs PIN entry operation.
1032: * @param pinID PIN identifier.
1033: * @param uPinID unblocking PIN identifier.
1034: * @param action PIN operation identifier.
1035: * @return PINENTRY_CANCELLED if the user cancelled the PIN entry
1036: * request or the value returned by the remote method.
1037: * @exception java.rmi.RemoteException is thrown if the PIN could
1038: * not be communicated to the card or an exception is thrown
1039: * by the card in response to the PIN entry.
1040: * @exception SecurityException is thrown if the J2ME application does
1041: * not have appropriate rights to ask for unblocking the PIN.
1042: */
1043: private short doEnterPin(int pinID, int uPinID, int action)
1044: throws RemoteException {
1045:
1046: if (!connectionOpen) {
1047: throw new RemoteException("Connection is closed.");
1048: }
1049:
1050: String method = null;
1051: method = verifier.preparePIN(pinID, uPinID, action,
1052: internalReference.getClassName());
1053: Object[] pins = verifier.enterPIN(action, securityToken);
1054:
1055: if (pins == null) {
1056: return PINENTRY_CANCELLED;
1057: }
1058:
1059: try {
1060: Short r = (Short) invoke(internalReference, method, pins);
1061: return r.shortValue();
1062: } catch (Exception e) {
1063: throw new RemoteException("" + e);
1064: }
1065: }
1066: }
|