/* * Copyright 2015 Licel Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.licel.jcardsim.framework; import com.licel.jcardsim.base.SimulatorSystem; import java.lang.reflect.Field; import javacard.framework.AID; import javacard.framework.JCSystem; import javacard.framework.Shareable; import javacard.framework.SystemException; import javacard.framework.TransactionException; import javacard.security.MessageDigest; /** * ProxyClass for <code>JCSystem</code> * @see JCSystem */ public class JCSystemProxy { // implementation api version private static final short API_VERSION; static { short detectedVersion; try { Field f = MessageDigest.class.getDeclaredField("ALG_SHA_224"); detectedVersion = 0x0300; } catch (Exception ex) { detectedVersion = 0x0202; } API_VERSION = detectedVersion; } /** * Checks if the specified object is transient. * <p>Note: * <ul> * <li><em>This method returns </em><code>NOT_A_TRANSIENT_OBJECT</code><em> if the specified object is * <code>null</code> or is not an array type.</em></li> * </ul> * @param theObj the object being queried * @return <code>NOT_A_TRANSIENT_OBJECT</code>, <code>CLEAR_ON_RESET</code>, or <code>CLEAR_ON_DESELECT</code> * @see #makeTransientBooleanArray(short, byte) * @see #makeTransientByteArray(short, byte) * @see #makeTransientObjectArray(short, byte) * @see #makeTransientShortArray(short, byte) */ public static byte isTransient(Object theObj) { return SimulatorSystem.instance().getTransientMemory().isTransient(theObj); } /** * Creates a transient boolean array with the specified array length. * @param length the length of the boolean array * @param event the <code>CLEAR_ON...</code> event which causes the array elements to be cleared * @return the new transient boolean array * @throws NegativeArraySizeException if the <CODE>length</CODE> parameter is negative * @throws SystemException with the following reason codes: * <ul> * <li><code>SystemException.ILLEGAL_VALUE</code> if event is not a valid event code. * <li><code>SystemException.NO_TRANSIENT_SPACE</code> if sufficient transient space is not available. * <li><code>SystemException.ILLEGAL_TRANSIENT</code> if the current applet context * is not the currently selected applet context and <code>CLEAR_ON_DESELECT</code> is specified. * </ul> */ public static boolean[] makeTransientBooleanArray(short length, byte event) throws NegativeArraySizeException, SystemException { return SimulatorSystem.instance().getTransientMemory().makeBooleanArray(length, event); } /** * Creates a transient byte array with the specified array length. * @param length the length of the byte array * @param event the <code>CLEAR_ON...</code> event which causes the array elements to be cleared * @return the new transient byte array * @throws NegativeArraySizeException if the <CODE>length</CODE> parameter is negative * @throws SystemException with the following reason codes: * <ul> * <li><code>SystemException.ILLEGAL_VALUE</code> if event is not a valid event code. * <li><code>SystemException.NO_TRANSIENT_SPACE</code> if sufficient transient space is not available. * <li><code>SystemException.ILLEGAL_TRANSIENT</code> if the current applet context * is not the currently selected applet context and <code>CLEAR_ON_DESELECT</code> is specified. * </ul> */ public static byte[] makeTransientByteArray(short length, byte event) throws NegativeArraySizeException, SystemException { return SimulatorSystem.instance().getTransientMemory().makeByteArray(length, event); } /** * Creates a transient short array with the specified array length. * @param length the length of the short array * @param event the <code>CLEAR_ON...</code> event which causes the array elements to be cleared * @return the new transient short array * @throws NegativeArraySizeException if the <CODE>length</CODE> parameter is negative * @throws SystemException with the following reason codes: * <ul> * <li><code>SystemException.ILLEGAL_VALUE</code> if event is not a valid event code. * <li><code>SystemException.NO_TRANSIENT_SPACE</code> if sufficient transient space is not available. * <li><code>SystemException.ILLEGAL_TRANSIENT</code> if the current applet context * is not the currently selected applet context and <code>CLEAR_ON_DESELECT</code> is specified. * </ul> */ public static short[] makeTransientShortArray(short length, byte event) throws NegativeArraySizeException, SystemException { return SimulatorSystem.instance().getTransientMemory().makeShortArray(length, event); } /** * Creates a transient array of <code>Object</code> with the specified array length. * @param length the length of the Object array * @param event the <code>CLEAR_ON...</code> event which causes the array elements to be cleared * @return the new transient Object array * @throws NegativeArraySizeException if the <CODE>length</CODE> parameter is negative * @throws SystemException with the following reason codes: * <ul> * <li><code>SystemException.ILLEGAL_VALUE</code> if event is not a valid event code. * <li><code>SystemException.NO_TRANSIENT_SPACE</code> if sufficient transient space is not available. * <li><code>SystemException.ILLEGAL_TRANSIENT</code> if the current applet context * is not the currently selected applet context and <code>CLEAR_ON_DESELECT</code> is specified. * </ul> */ public static Object[] makeTransientObjectArray(short length, byte event) throws NegativeArraySizeException, SystemException { return SimulatorSystem.instance().getTransientMemory().makeObjectArray(length, event); } /** * Returns the current major and minor version of the Java Card API. * @return version number as byte.byte (major.minor) */ public static short getVersion() { return API_VERSION; } /** * Returns the Java Card runtime environment-owned instance of the <code>AID</code> object associated with * the current applet context, or * <code>null</code> if the <code>Applet.register()</code> method * has not yet been invoked. * <p>Java Card runtime environment-owned instances of <code>AID</code> are permanent Java Card runtime environment * Entry Point Objects and can be accessed from any applet context. * References to these permanent objects can be stored and re-used. * <p>See <em>Runtime Environment Specification for the Java Card Platform</em>, section 6.2.1 for details. * @return the <code>AID</code> object */ public static AID getAID() { return SimulatorSystem.instance().getAID(); } /** * Returns the Java Card runtime environment-owned instance of the <code>AID</code> object, if any, * encapsulating the specified AID bytes in the <code>buffer</code> parameter * if there exists a successfully installed applet on the card whose instance AID * exactly matches that of the specified AID bytes. * <p>Java Card runtime environment-owned instances of <code>AID</code> are permanent Java Card runtime environment * Entry Point Objects and can be accessed from any applet context. * References to these permanent objects can be stored and re-used. * <p>See <em>Runtime Environment Specification for the Java Card Platform</em>, section 6.2.1 for details. * @param buffer byte array containing the AID bytes * @param offset offset within buffer where AID bytes begin * @param length length of AID bytes in buffer * @return the <code>AID</code> object, if any; <code>null</code> otherwise. A VM exception * is thrown if <code>buffer</code> is <code>null</code>, * or if <code>offset</code> or <code>length</code> are out of range. */ public static AID lookupAID(byte buffer[], short offset, byte length) { return SimulatorSystem.instance().lookupAID(buffer, offset, length); } /** * Begins an atomic transaction. If a transaction is already in * progress (transaction nesting depth level != 0), a TransactionException is * thrown. * <p>Note: * <ul> * <li><em>This method may do nothing if the <code>Applet.register()</code> * method has not yet been invoked. In case of tear or failure prior to successful * registration, the Java Card runtime environment will roll back all atomically updated persistent state.</em> * </ul> * @throws TransactionException with the following reason codes: * <ul> * <li><code>TransactionException.IN_PROGRESS</code> if a transaction is already in progress. * </ul> * @see #abortTransaction() * @see #commitTransaction() */ public static void beginTransaction() throws TransactionException { SimulatorSystem.instance().beginTransaction(); } /** * Aborts the atomic transaction. The contents of the commit * buffer is discarded. * <p>Note: * <ul> * <li><em>This method may do nothing if the <code>Applet.register()</code> * method has not yet been invoked. In case of tear or failure prior to successful * registration, the Java Card runtime environment will roll back all atomically updated persistent state.</em> * <li><em>Do not call this method from within a transaction which creates new objects because * the Java Card runtime environment may not recover the heap space used by the new object instances.</em> * <li><em>Do not call this method from within a transaction which creates new objects because * the Java Card runtime environment may, to ensure the security of the card and to avoid heap space loss, * lock up the card session to force tear/reset processing.</em> * <li><em>The Java Card runtime environment ensures that any variable of reference type which references an object * instantiated from within this aborted transaction is equivalent to * a </em><code>null</code><em> reference.</em> * </ul> * @throws TransactionException - with the following reason codes: * <ul> * <li><code>TransactionException.NOT_IN_PROGRESS</code> if a transaction is not in progress. * </ul> * @see #beginTransaction() * @see #commitTransaction() */ public static void abortTransaction() throws TransactionException { SimulatorSystem.instance().abortTransaction(); } /** * Commits an atomic transaction. The contents of commit * buffer is atomically committed. If a transaction is not in * progress (transaction nesting depth level == 0) then a TransactionException is * thrown. * <p>Note: * <ul> * <li><em>This method may do nothing if the <code>Applet.register()</code> * method has not yet been invoked. In case of tear or failure prior to successful * registration, the Java Card runtime environment will roll back all atomically updated persistent state.</em> * </ul> * @throws TransactionException ith the following reason codes: * <ul> * <li><code>TransactionException.NOT_IN_PROGRESS</code> if a transaction is not in progress. * </ul> * @see #beginTransaction() * @see #abortTransaction() */ public static void commitTransaction() throws TransactionException { SimulatorSystem.instance().commitTransaction(); } /** * Returns the current transaction nesting depth level. At present, * only 1 transaction can be in progress at a time. * @return 1 if transaction in progress, 0 if not */ public static byte getTransactionDepth() { return SimulatorSystem.instance().getTransactionDepth(); } /** * Returns the number of bytes left in the commit buffer. * <p> Note:<ul> * <li><em>If the number of bytes left in the commit buffer is greater than * 32767, then this method returns 32767.</em> * </ul> * @return the number of bytes left in the commit buffer * @see #getMaxCommitCapacity() */ public static short getUnusedCommitCapacity() { return SimulatorSystem.instance().getUnusedCommitCapacity(); } /** * Returns the total number of bytes in the commit buffer. * This is approximately the maximum number of bytes of * persistent data which can be modified during a transaction. * However, the transaction subsystem requires additional bytes * of overhead data to be included in the commit buffer, and this * depends on the number of fields modified and the implementation * of the transaction subsystem. The application cannot determine * the actual maximum amount of data which can be modified during * a transaction without taking these overhead bytes into consideration. * <p> Note:<ul> * <li><em>If the total number of bytes in the commit buffer is greater than * 32767, then this method returns 32767.</em> * </ul> * @return the total number of bytes in the commit buffer * @see #getUnusedCommitCapacity() */ public static short getMaxCommitCapacity() { return SimulatorSystem.instance().getMaxCommitCapacity(); } /** * Obtains the Java Card runtime environment-owned instance of the <code>AID</code> object associated * with the previously active applet context. This method is typically used by a server applet, * while executing a shareable interface method to determine the identity of its client and * thereby control access privileges. * <p>Java Card runtime environment-owned instances of <code>AID</code> are permanent Java Card runtime environment * Entry Point Objects and can be accessed from any applet context. * References to these permanent objects can be stored and re-used. * <p>See <em>Runtime Environment Specification for the Java Card Platform</em>, section 6.2.1 for details. * @return the <code>AID</code> object of the previous context, or <code>null</code> if Java Card runtime environment */ public static AID getPreviousContextAID() { return SimulatorSystem.instance().getPreviousContextAID(); } /** * Obtains the amount of memory of the specified * type that is available to the applet. Note that implementation-dependent * memory overhead structures may also use the same memory pool. * <p>Notes: * <ul> * <li><em>The number of bytes returned is only an upper bound on the amount * of memory available due to overhead requirements.</em> * <li><em>Allocation of CLEAR_ON_RESET transient objects may affect the * amount of CLEAR_ON_DESELECT transient memory available.</em> * <li><em>Allocation of CLEAR_ON_DESELECT transient objects may affect the * amount of CLEAR_ON_RESET transient memory available.</em> * <li><em>If the number of available bytes is greater than 32767, then * this method returns 32767.</em> * <li><em>The returned count is not an indicator of the size of object which * may be created since memory fragmentation is possible.</em> </ul> * @param memoryType the type of memory being queried. One of the <CODE>MEMORY_TYPE_</CODE>.. * constants defined above * @return the upper bound on available bytes of memory for the specified type * @throws SystemException with the following reason codes:<ul> * <li><code>SystemException.ILLEGAL_VALUE</code> if <code>memoryType</code> is not a * valid memory type. * </ul> */ public static short getAvailableMemory(byte memoryType) throws SystemException { switch (memoryType) { case JCSystem.MEMORY_TYPE_PERSISTENT: return SimulatorSystem.instance().getAvailablePersistentMemory(); case JCSystem.MEMORY_TYPE_TRANSIENT_RESET: return SimulatorSystem.instance().getAvailableTransientResetMemory(); case JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT: return SimulatorSystem.instance().getAvailableTransientDeselectMemory(); } SystemException.throwIt(SystemException.ILLEGAL_VALUE); return 0; } /** * Called by a client applet to get a server applet's * shareable interface object. <p>This method returns <code>null</code> * if: * <ul> * <li>the <code>Applet.register()</code> has not yet been invoked</li> * <li>the server does not exist</li> * <li>the server returns <code>null</code></li> * </ul> * @param serverAID the AID of the server applet * @param parameter optional parameter data * @return the shareable interface object or <code>null</code> * @see Applet#getShareableInterfaceObject(AID, byte) */ public static Shareable getAppletShareableInterfaceObject(AID serverAID, byte parameter) { return SimulatorSystem.instance().getSharedObject(serverAID, parameter); } /** * This method is used to determine if the implementation for the Java Card platform supports * the object deletion mechanism. * @return <CODE>true</CODE> if the object deletion mechanism is supported, <CODE>false</CODE> otherwise */ public static boolean isObjectDeletionSupported() { return SimulatorSystem.instance().isObjectDeletionSupported(); } /** * This method is invoked by the applet to trigger the object deletion * service of the Java Card runtime environment. If the Java Card runtime environment implements the object deletion mechanism, * the request is merely logged at this time. The Java Card runtime environment * must schedule the object deletion service prior to the * next invocation of the <CODE>Applet.process()</CODE> method. The object deletion * mechanism must ensure that : * <ul> * <li>Any unreferenced persistent object owned by the current applet context * is deleted and the associated space is recovered for reuse prior to the * next invocation of the <CODE>Applet.process()</CODE> method. * <li>Any unreferenced <CODE>CLEAR_ON_DESELECT</CODE> or <CODE>CLEAR_ON_RESET</CODE> * transient object owned by the current applet context is deleted * and the associated space is recovered for reuse before the next card reset session. * </ul> * @throws SystemException with the following reason codes:<ul> * <li><code>SystemException.ILLEGAL_USE</code> if the object deletion mechanism is * not implemented. * </ul> */ public static void requestObjectDeletion() throws SystemException { SimulatorSystem.instance().requestObjectDeletion(); } /** * This method is called to obtain the logical channel number assigned to * the currently selected applet instance. The assigned logical channel is * the logical channel on which the currently selected applet instance is * or will be the active applet instance. This logical channel number is always * equal to the origin logical channel number returned by the APDU.getCLAChannel() * method except during selection and deselection via the MANAGE CHANNEL APDU command. * If this method is called from the <CODE>Applet.select()</CODE>, <CODE>Applet.deselect(</CODE>), * <CODE>MultiSelectable.select(boolean)</CODE> and <CODE>MultiSelectable.deselect(boolean)</CODE> methods * during MANAGE CHANNEL APDU command processing, the logical channel number * returned may be different. * @return the logical channel number in the range 0-3 assigned to the * currently selected applet instance */ public static byte getAssignedChannel() { return SimulatorSystem.instance().getAssignedChannel(); } /** * This method is used to determine if the specified applet is * active on the card. * <p>Note: * <ul> * <li><em>This method returns <code>false</code> if the specified applet is * not active, even if its context is active.</em> * </ul> * @param theApplet the AID of the applet object being queried * @return <code>true</code> if and only if the applet specified by the * AID parameter is currently active on this or another logical channel */ public static boolean isAppletActive(AID theApplet) { return (theApplet == SimulatorSystem.instance().getAID()); } }