Skip to content

Commit

Permalink
Merge pull request arekinath#1 from pongpet-licel/#178globalarray
Browse files Browse the repository at this point in the history
Support JCSystem.makeGlobalArray() call
  • Loading branch information
pongpet-licel authored May 27, 2022
2 parents 83fe9f8 + 7467713 commit b306a99
Show file tree
Hide file tree
Showing 8 changed files with 644 additions and 0 deletions.
30 changes: 30 additions & 0 deletions src/main/java/com/licel/jcardsim/base/TransientMemory.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,36 @@ public Object[] makeObjectArray(short length, byte event) {
return array;
}

/**
* @see javacard.framework.JCSystem#makeGlobalArray(byte,short)
* @param type the array type - must be one of : ARRAY_TYPE_BOOLEAN, ARRAY_TYPE_BYTE, ARRAY_TYPE_SHORT, ARRAY_TYPE_INT, or ARRAY_TYPE_OBJECT
* @param length the length of the global transient array
* @return the new transient Object array
*/
public Object makeGlobalArray(byte type, short length){
Object array = null;
switch (type){
case JCSystem.ARRAY_TYPE_BOOLEAN:
array = makeBooleanArray(length, JCSystem.CLEAR_ON_RESET);
break;
case JCSystem.ARRAY_TYPE_BYTE:
array = makeByteArray(length, JCSystem.CLEAR_ON_RESET);
break;
case JCSystem.ARRAY_TYPE_SHORT:
array = makeShortArray(length, JCSystem.CLEAR_ON_RESET);
break;
case JCSystem.ARRAY_TYPE_OBJECT:
array = makeObjectArray(length, JCSystem.CLEAR_ON_RESET);
break;
case JCSystem.ARRAY_TYPE_INT:
default:
SystemException.throwIt(SystemException.ILLEGAL_VALUE);
break;
}

return array;
}

/**
* @see javacard.framework.JCSystem#isTransient(Object)
* @param theObj the object being queried
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/com/licel/jcardsim/framework/JCSystemProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,25 @@ public static Object[] makeTransientObjectArray(short length, byte event)
return SimulatorSystem.instance().getTransientMemory().makeObjectArray(length, event);
}

/**
* Creates a global <code>CLEAR_ON_RESET</code> transient array of the type specified, with the specified array length.
* A global array can be accessed from any applet context.
* References to global arrays cannot be stored in class variables or instance variables or array components.
* (See Runtime Environment Specification, Java Card Platform, Classic Edition, section 6.2.2 for details)
* @param type the array type - must be one of : ARRAY_TYPE_BOOLEAN, ARRAY_TYPE_BYTE, ARRAY_TYPE_SHORT, ARRAY_TYPE_INT, or ARRAY_TYPE_OBJECT
* @param length the length of the global transient array
* @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 type is not a valid type code. An implementation which does not support the "int" type may throw this exception if type is ARRAY_TYPE_INT
* <li><code>SystemException.NO_TRANSIENT_SPACE</code> if sufficient transient space is not available.
* </ul>
*/
public static Object makeGlobalArray(byte type, short length){
return SimulatorSystem.instance().getTransientMemory().makeGlobalArray(type,length);
}

/**
* Returns the current major and minor version of the Java Card API.
* @return version number as byte.byte (major.minor)
Expand Down
24 changes: 24 additions & 0 deletions src/main/java/com/licel/jcardsim/samples/GlobalArrayAccess.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2022 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.samples;
import javacard.framework.Shareable;
/**
* Grants access to the global array.
*
*/
public interface GlobalArrayAccess extends Shareable{
public Object getGlobalArrayRef();
}
116 changes: 116 additions & 0 deletions src/main/java/com/licel/jcardsim/samples/GlobalArrayClientApplet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Copyright 2022 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.samples;

import com.licel.jcardsim.utils.AIDUtil;

import javacard.framework.*;

/**
* Global array client applet.
*
* <p>Supported APDUs:</p>
*
* <ul>
* <li><code>CLA=0x10 INS=1</code> Read global byte array with size from <code>Le</code></li>
* <li><code>CLA=0x10 INS=2</code> Write global byte array value from <code>CData</code></li>
* </ul>
*/
public class GlobalArrayClientApplet extends BaseApplet{
private final static byte CLA = 0x10;
private final static byte INS_READ_GLOBAL_ARRAY_BYTE = 0x01;
private final static byte INS_WRITE_GLOBAL_ARRAY_BYTE = 0x02;

private static final short MAX_ALLOWED_GLOBAL_ARRAY_SIZE_BYTES = 64;

private AID serverAppletAID;

/**
* This method is called once during applet instantiation process.
* @param bArray the array containing installation parameters
* @param bOffset the starting offset in bArray
* @param bLength the length in bytes of the parameter data in bArray
* @throws ISOException if the install method failed
*/
public static void install(byte[] bArray, short bOffset, byte bLength)
throws ISOException {
new GlobalArrayClientApplet(bArray,bOffset,bLength);
}

protected GlobalArrayClientApplet(byte[] bArray, short bOffset, byte bLength){
byte aidLen = bArray[bOffset];
byte[] aidBytes = new byte[aidLen];
Util.arrayCopyNonAtomic(bArray, (short) (bOffset+1), aidBytes, (short) 0, aidLen);

serverAppletAID = AIDUtil.create(aidBytes);

register();
}


public void process(APDU apdu) {
if(selectingApplet())
return;

byte[] buffer = apdu.getBuffer();

if( buffer[ISO7816.OFFSET_CLA] != CLA)
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);

switch(buffer[ISO7816.OFFSET_INS]){
case INS_READ_GLOBAL_ARRAY_BYTE:
readGlobalArrayByte(apdu);
return;

case INS_WRITE_GLOBAL_ARRAY_BYTE:
writeGlobalArrayByte(apdu);
return;

default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
}

private void readGlobalArrayByte(APDU apdu){
GlobalArrayAccess shared = (GlobalArrayAccess)JCSystem.getAppletShareableInterfaceObject(serverAppletAID, (byte) 0);
byte[] globalArrayByte = (byte[]) shared.getGlobalArrayRef();

short le = apdu.setOutgoing();
apdu.setOutgoingLength(le);
apdu.sendBytesLong(globalArrayByte, (short) 0, le);
}

private void writeGlobalArrayByte(APDU apdu){
byte[] buffer = apdu.getBuffer();
byte numBytes = buffer[ISO7816.OFFSET_LC];
if( (numBytes > MAX_ALLOWED_GLOBAL_ARRAY_SIZE_BYTES) || (numBytes == 0) ){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}

GlobalArrayAccess shared = (GlobalArrayAccess)JCSystem.getAppletShareableInterfaceObject(serverAppletAID, (byte) 0);
byte[] globalArrayByte = (byte[]) shared.getGlobalArrayRef();

byte bytesRead = (byte)apdu.setIncomingAndReceive();
byte bufferOffset = 0;

while(bytesRead >0){
Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, globalArrayByte, bufferOffset, bytesRead);
bufferOffset += bytesRead;
bytesRead = (byte)apdu.receiveBytes(ISO7816.OFFSET_CDATA);
}
}

}
125 changes: 125 additions & 0 deletions src/main/java/com/licel/jcardsim/samples/GlobalArrayServerApplet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright 2022 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.samples;

import javacard.framework.*;

/**
* Global array server applet.
*
* <p>Supported APDUs:</p>
*
* <ul>
* <li><code>CLA=0x10 INS=1</code> Create global byte array with size form <code>P1</code> and fill each byte with data from <code>P2</code></li>
* <li><code>CLA=0x10 INS=2</code> Store global byte array value from <code>CData</code></li>
* </ul>
*/

public class GlobalArrayServerApplet extends BaseApplet implements GlobalArrayAccess{
private final static byte CLA = 0x10;
private final static byte INS_INIT_GLOBAL_ARRAY_BYTE = 0x01;
private final static byte INS_WRITE_GLOBAL_ARRAY_BYTE = 0x02;

private final byte[] transientMemory;
private static final short MAX_ALLOWED_GLOBAL_ARRAY_SIZE_BYTES = 64;

private Object globalArray = null;

protected GlobalArrayServerApplet(){
transientMemory = JCSystem.makeTransientByteArray(MAX_ALLOWED_GLOBAL_ARRAY_SIZE_BYTES, JCSystem.CLEAR_ON_DESELECT);
register();
}

public static void install(byte[] bArray, short bOffset, byte bLength)
throws ISOException {
new GlobalArrayServerApplet();
}

@Override
public void process(APDU apdu) throws ISOException {
if(selectingApplet()) {
return;
}

byte[] buffer = apdu.getBuffer();

// Verify CLA
if( buffer[ISO7816.OFFSET_CLA] != CLA){
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
}

switch(buffer[ISO7816.OFFSET_INS]){
case INS_INIT_GLOBAL_ARRAY_BYTE:
initGlobalArrayByte(apdu);
return;
case INS_WRITE_GLOBAL_ARRAY_BYTE:
writeGlobalArrayByte(apdu);
return;

default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);

}
}

public Shareable getShareableInterfaceObject(AID clientAID, byte parameter) {
return this;
}


private void initGlobalArrayByte(APDU apdu) {
byte[] buffer = apdu.getBuffer();
byte size = buffer[ISO7816.OFFSET_P1];

if( (size > MAX_ALLOWED_GLOBAL_ARRAY_SIZE_BYTES) || (size == 0) ) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}

byte init_val = buffer[ISO7816.OFFSET_P2];
globalArray = JCSystem.makeGlobalArray( JCSystem.ARRAY_TYPE_BYTE,size);
for (byte i=0; i<size; i++ ) {
((byte[])globalArray)[i] = init_val;
}
}

private void writeGlobalArrayByte(APDU apdu){
byte[] buffer = apdu.getBuffer();
byte numBytes = buffer[ISO7816.OFFSET_LC];
if( (numBytes > MAX_ALLOWED_GLOBAL_ARRAY_SIZE_BYTES) || (numBytes == 0) ){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}

byte bytesRead = (byte)apdu.setIncomingAndReceive();
byte bufferOffset = 0;

while(bytesRead >0){
Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, transientMemory, bufferOffset, bytesRead);
bufferOffset += bytesRead;
bytesRead = (byte)apdu.receiveBytes(ISO7816.OFFSET_CDATA);
}

for (byte i=0; i<numBytes; i++ ) {
((byte[])globalArray)[i] = transientMemory[i];
}
}

@Override
public Object getGlobalArrayRef() {
return globalArray;
}


}
60 changes: 60 additions & 0 deletions src/test/java/com/licel/jcardsim/base/AppletShareableTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2022 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.base;

import com.licel.jcardsim.samples.GlobalArrayClientApplet;
import com.licel.jcardsim.samples.GlobalArrayServerApplet;
import com.licel.jcardsim.utils.AIDUtil;

import javacard.framework.AID;
import javacard.framework.JCSystem;
import junit.framework.Test;
import junit.framework.TestCase;

public class AppletShareableTest extends TestCase{
byte[] serverAppletAIDBytes = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 };
AID serverAppletAID;
public AppletShareableTest(String name){
super(name);
}

public void testGetShareableApplet(){
String shareableAppletAIDStr = "010203040506070809";
AID shareableAppletAID = AIDUtil.create(shareableAppletAIDStr);

Simulator instance = new Simulator();
assertEquals(instance.installApplet(shareableAppletAID,GlobalArrayServerApplet.class).equals(shareableAppletAID),true);
assertEquals(instance.selectApplet(shareableAppletAID), true);

assertNotNull(JCSystem.getAppletShareableInterfaceObject(shareableAppletAID, (byte) 0));

}

public void testGetNotShareableApplet(){
String appletAIDStr = "090807060504030201";
AID appletAID = AIDUtil.create(appletAIDStr);

byte[] clientAppletPar = new byte[1+serverAppletAIDBytes.length];
clientAppletPar[0] = (byte)serverAppletAIDBytes.length;
System.arraycopy(serverAppletAIDBytes, 0, clientAppletPar, 1, serverAppletAIDBytes.length);

Simulator instance = new Simulator();
assertEquals(instance.installApplet(appletAID,GlobalArrayClientApplet.class,clientAppletPar,(short)0,(byte)clientAppletPar.length).equals(appletAID),true);
assertEquals(instance.selectApplet(appletAID), true);

assertNull(JCSystem.getAppletShareableInterfaceObject(appletAID, (byte) 0));
}
}
Loading

0 comments on commit b306a99

Please sign in to comment.