1 package com.android.cts.omapi.test; 2 3 import javacard.framework.APDU; 4 import javacard.framework.ISO7816; 5 import javacard.framework.Applet; 6 import javacard.framework.ISOException; 7 import javacard.framework.Util; 8 9 public class CtsAndroidOmapiTestApplet extends Applet { 10 11 final private static byte NO_DATA_INS_1 = (byte) 0x06; 12 final private static byte NO_DATA_INS_2 = (byte) 0x0A; 13 14 final private static byte DATA_INS_1 = (byte) 0x08; 15 final private static byte DATA_INS_2 = (byte) 0x0C; 16 17 final private static byte SW_62xx_APDU_INS = (byte) 0xF3; 18 final private static byte SW_62xx_DATA_APDU_P2 = (byte) 0x08; 19 final private static byte SW_62xx_VALIDATE_DATA_P2 = (byte) 0x0C; 20 private final static byte[] SW_62xx_VALIDATE_DATA_RESP = 21 new byte[]{0x01, (byte) 0xF3, 0x00, 0x0C, 0x01, (byte) 0xAA, 0x00}; 22 private final static short[] SW_62xx_resp = new short[]{ 23 (short)0x6200, (short)0x6281, (short)0x6282, (short)0x6283, 24 (short)0x6285, (short)0x62F1, (short)0x62F2, (short)0x63F1, 25 (short)0x63F2, (short)0x63C2, (short)0x6202, (short)0x6280, 26 (short)0x6284, (short)0x6286, (short)0x6300, (short)0x6381, 27 }; 28 29 final public static byte SEGMENTED_RESP_INS_1 = (byte) 0xC2; 30 final public static byte SEGMENTED_RESP_INS_2 = (byte) 0xC4; 31 final public static byte SEGMENTED_RESP_INS_3 = (byte) 0xC6; 32 final public static byte SEGMENTED_RESP_INS_4 = (byte) 0xC8; 33 final public static byte SEGMENTED_RESP_INS_5 = (byte) 0xCF; 34 35 final private static byte CHECK_SELECT_P2_APDU = (byte)0xF4; 36 final public static byte GET_RESPONSE_INS = (byte) 0xC0; 37 38 final private static byte BER_TLV_TYPE = (byte) 0x1F; 39 final private static short SELECT_RESPONSE_DATA_LENGTH = (short)252; 40 41 private byte[] respBuf; 42 private short respBuffOffset = 0; 43 44 final private static short LENGTH_256 = (short) 0x0100; 45 private final static byte[] resp_bytes256 = new byte[]{ 46 (byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, 47 (byte)0x06, (byte)0x07, (byte)0x08, (byte)0x09, (byte)0x0A, (byte)0x0B, 48 (byte)0x0C, (byte)0x0D, (byte)0x0E, (byte)0x0F, 49 (byte)0x10, (byte)0x11, (byte)0x12, (byte)0x13, (byte)0x14, (byte)0x15, 50 (byte)0x16, (byte)0x17, (byte)0x18, (byte)0x19, (byte)0x1A, (byte)0x1B, 51 (byte)0x1C, (byte)0x1D, (byte)0x1E, (byte)0x1F, 52 (byte)0x20, (byte)0x21, (byte)0x22, (byte)0x23, (byte)0x24, (byte)0x25, 53 (byte)0x26, (byte)0x27, (byte)0x28, (byte)0x29, (byte)0x2A, (byte)0x2B, 54 (byte)0x2C, (byte)0x2D, (byte)0x2E, (byte)0x2F, 55 (byte)0x30, (byte)0x31, (byte)0x32, (byte)0x33, (byte)0x34, (byte)0x35, 56 (byte)0x36, (byte)0x37, (byte)0x38, (byte)0x39, (byte)0x3A, (byte)0x3B, 57 (byte)0x3C, (byte)0x3D, (byte)0x3E, (byte)0x3F, 58 (byte)0x40, (byte)0x41, (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, 59 (byte)0x46, (byte)0x47, (byte)0x48, (byte)0x49, (byte)0x4A, (byte)0x4B, 60 (byte)0x4C, (byte)0x4D, (byte)0x4E, (byte)0x4F, 61 (byte)0x50, (byte)0x51, (byte)0x52, (byte)0x53, (byte)0x54, (byte)0x55, 62 (byte)0x56, (byte)0x57, (byte)0x58, (byte)0x59, (byte)0x5A, (byte)0x5B, 63 (byte)0x5C, (byte)0x5D, (byte)0x5E, (byte)0x5F, 64 (byte)0x60, (byte)0x61, (byte)0x62, (byte)0x63, (byte)0x64, (byte)0x65, 65 (byte)0x66, (byte)0x67, (byte)0x68, (byte)0x69, (byte)0x6A, (byte)0x6B, 66 (byte)0x6C, (byte)0x6D, (byte)0x6E, (byte)0x6F, 67 (byte)0x70, (byte)0x71, (byte)0x72, (byte)0x73, (byte)0x74, (byte)0x75, 68 (byte)0x76, (byte)0x77, (byte)0x78, (byte)0x79, (byte)0x7A, (byte)0x7B, 69 (byte)0x7C, (byte)0x7D, (byte)0x7E, (byte)0x7F, 70 (byte)0x80, (byte)0x81, (byte)0x82, (byte)0x83, (byte)0x84, (byte)0x85, 71 (byte)0x86, (byte)0x87, (byte)0x88, (byte)0x89, (byte)0x8A, (byte)0x8B, 72 (byte)0x8C, (byte)0x8D, (byte)0x8E, (byte)0x8F, 73 (byte)0x90, (byte)0x91, (byte)0x92, (byte)0x93, (byte)0x94, (byte)0x95, 74 (byte)0x96, (byte)0x97, (byte)0x98, (byte)0x99, (byte)0x9A, (byte)0x9B, 75 (byte)0x9C, (byte)0x9D, (byte)0x9E, (byte)0x9F, 76 (byte)0xA0, (byte)0xA1, (byte)0xA2, (byte)0xA3, (byte)0xA4, (byte)0xA5, 77 (byte)0xA6, (byte)0xA7, (byte)0xA8, (byte)0xA9, (byte)0xAA, (byte)0xAB, 78 (byte)0xAC, (byte)0xAD, (byte)0xAE, (byte)0xAF, 79 (byte)0xB0, (byte)0xB1, (byte)0xB2, (byte)0xB3, (byte)0xB4, (byte)0xB5, 80 (byte)0xB6, (byte)0xB7, (byte)0xB8, (byte)0xB9, (byte)0xBA, (byte)0xBB, 81 (byte)0xBC, (byte)0xBD, (byte)0xBE, (byte)0xBF, 82 (byte)0xC0, (byte)0xC1, (byte)0xC2, (byte)0xC3, (byte)0xC4, (byte)0xC5, 83 (byte)0xC6, (byte)0xC7, (byte)0xC8, (byte)0xC9, (byte)0xCA, (byte)0xCB, 84 (byte)0xCC, (byte)0xCD, (byte)0xCE, (byte)0xCF, 85 (byte)0xD0, (byte)0xD1, (byte)0xD2, (byte)0xD3, (byte)0xD4, (byte)0xD5, 86 (byte)0xD6, (byte)0xD7, (byte)0xD8, (byte)0xD9, (byte)0xDA, (byte)0xDB, 87 (byte)0xDC, (byte)0xDD, (byte)0xDE, (byte)0xDF, 88 (byte)0xE0, (byte)0xE1, (byte)0xE2, (byte)0xE3, (byte)0xE4, (byte)0xE5, 89 (byte)0xE6, (byte)0xE7, (byte)0xE8, (byte)0xE9, (byte)0xEA, (byte)0xEB, 90 (byte)0xEC, (byte)0xED, (byte)0xEE, (byte)0xEF, 91 (byte)0xF0, (byte)0xF1, (byte)0xF2, (byte)0xF3, (byte)0xF4, (byte)0xF5, 92 (byte)0xF6, (byte)0xF7, (byte)0xF8, (byte)0xF9, (byte)0xFA, (byte)0xFB, 93 (byte)0xFC, (byte)0xFD, (byte)0xFE, (byte)0xFF 94 }; 95 install(byte[] bArray, short bOffset, byte bLength)96 public static void install(byte[] bArray, short bOffset, byte bLength) { 97 // GP-compliant JavaCard applet registration 98 new com.android.cts.omapi.test.CtsAndroidOmapiTestApplet().register(bArray, (short) (bOffset + 1), bArray[bOffset]); 99 } 100 process(APDU apdu)101 public void process(APDU apdu) { 102 byte[] buf = apdu.getBuffer(); 103 short le, lc; 104 short sendLen; 105 byte p1 = buf[ISO7816.OFFSET_P1]; 106 byte p2 = buf[ISO7816.OFFSET_P2]; 107 108 if (selectingApplet()) { 109 lc = buf[ISO7816.OFFSET_LC]; 110 if (buf[(short)(lc + ISO7816.OFFSET_CDATA - 1)] == 0x31) { 111 //AID: A000000476416E64726F696443545331 112 ISOException.throwIt(ISO7816.SW_NO_ERROR); 113 } else { 114 //A000000476416E64726F696443545332 115 sendLen = fillBerTLVBytes(SELECT_RESPONSE_DATA_LENGTH); 116 le = apdu.setOutgoing(); 117 apdu.setOutgoingLength((short)sendLen); 118 Util.arrayCopy(respBuf, (short)0, buf, (short)0, (short)respBuf.length); 119 apdu.sendBytesLong(buf, respBuffOffset, sendLen); 120 return; 121 } 122 } 123 switch (buf[ISO7816.OFFSET_INS]) { 124 case NO_DATA_INS_1: 125 case NO_DATA_INS_2: 126 ISOException.throwIt(ISO7816.SW_NO_ERROR); 127 break; 128 case DATA_INS_2: 129 apdu.setIncomingAndReceive(); 130 //case 3 APDU, return 256 bytes data 131 sendLen = fillBytes((short)256); 132 le = apdu.setOutgoing(); 133 apdu.setOutgoingLength((short)sendLen); 134 Util.arrayCopy(respBuf, (short)0, buf, (short)0, (short)respBuf.length); 135 apdu.sendBytesLong(buf, respBuffOffset, sendLen); 136 break; 137 case GET_RESPONSE_INS: 138 apdu.setIncomingAndReceive(); 139 //ISO GET_RESPONSE command 140 if (respBuf == null) { 141 ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); 142 } else { 143 le = apdu.setOutgoing(); 144 sendLen = (short) (respBuf.length - respBuffOffset); 145 sendLen = le > sendLen ? sendLen : le; 146 apdu.setOutgoingLength(sendLen); 147 apdu.sendBytesLong(respBuf, respBuffOffset, sendLen); 148 respBuffOffset += sendLen; 149 sendLen = (short) (respBuf.length - respBuffOffset); 150 if (sendLen > 0) { 151 if (sendLen > 256) sendLen = 0x00; 152 ISOException.throwIt((short)(ISO7816.SW_BYTES_REMAINING_00 | sendLen)); 153 } else { 154 respBuf = null; 155 } 156 } 157 break; 158 case DATA_INS_1: 159 // return 256 bytes data 160 sendLen = fillBytes((short)256); 161 le = apdu.setOutgoing(); 162 apdu.setOutgoingLength((short) sendLen); 163 Util.arrayCopy(respBuf, (short)0, buf, (short)0, (short)respBuf.length); 164 apdu.sendBytesLong(buf, respBuffOffset, sendLen); 165 break; 166 case SW_62xx_APDU_INS: 167 if (p1 > 16 || p1 < 1) { 168 ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); 169 } else if (p2 == SW_62xx_DATA_APDU_P2){ 170 sendLen = fillBytes((short)3); 171 le = apdu.setOutgoing(); 172 apdu.setOutgoingLength((short)sendLen); 173 Util.arrayCopy(respBuf, (short)0, buf, (short)0, (short) respBuf.length); 174 apdu.sendBytesLong(buf, respBuffOffset, sendLen); 175 ISOException.throwIt(SW_62xx_resp[p1 -1]); 176 } else if (p2 == SW_62xx_VALIDATE_DATA_P2){ 177 le = apdu.setOutgoing(); 178 apdu.setOutgoingLength((short) (SW_62xx_VALIDATE_DATA_RESP.length)); 179 Util.arrayCopy(SW_62xx_VALIDATE_DATA_RESP, (short) 0, buf, (short) 0, 180 (short) SW_62xx_VALIDATE_DATA_RESP.length); 181 buf[ISO7816.OFFSET_P1] = p1; 182 apdu.sendBytesLong(buf, (short)0, (short) SW_62xx_VALIDATE_DATA_RESP.length); 183 ISOException.throwIt(SW_62xx_resp[p1 -1]); 184 } else { 185 ISOException.throwIt(SW_62xx_resp[p1 -1]); 186 } 187 break; 188 case SEGMENTED_RESP_INS_1: 189 case SEGMENTED_RESP_INS_2: 190 le = (short)((short)((p1 & 0xFF)<< 8) | (short)(p2 & 0xFF)); 191 sendLen = fillBytes(le); 192 le = apdu.setOutgoing(); 193 sendLen = le > sendLen ? sendLen : le; 194 if (sendLen > 0xFF) sendLen = 0xFF; 195 apdu.setOutgoingLength(sendLen); 196 apdu.sendBytesLong(respBuf, respBuffOffset, sendLen); 197 respBuffOffset += sendLen; 198 sendLen = (short) (respBuf.length - respBuffOffset); 199 if (sendLen > 0) { 200 if (sendLen > 256) sendLen = 0x00; 201 ISOException.throwIt((short) (ISO7816.SW_BYTES_REMAINING_00 | sendLen)); 202 } 203 break; 204 case SEGMENTED_RESP_INS_3: 205 case SEGMENTED_RESP_INS_4: 206 le = (short)((short)((p1 & 0xFF)<< 8) | (short)(p2 & 0xFF)); 207 sendLen = fillBytes(le); 208 le = apdu.setOutgoing(); 209 sendLen = le > sendLen ? sendLen : le; 210 apdu.setOutgoingLength(sendLen); 211 apdu.sendBytesLong(respBuf, respBuffOffset, sendLen); 212 respBuffOffset += sendLen; 213 sendLen = (short) (respBuf.length - respBuffOffset); 214 if (sendLen > 0) { 215 if (sendLen > 256) sendLen = 0x00; 216 ISOException.throwIt((short) (ISO7816.SW_BYTES_REMAINING_00 | sendLen)); 217 } 218 break; 219 220 case SEGMENTED_RESP_INS_5: 221 le = apdu.setOutgoing(); 222 if (le != 0xFF) { 223 short buffer_len = (short)((short)((p1 & 0xFF)<< 8) | (short)(p2 & 0xFF)); 224 sendLen = fillBytes(buffer_len); 225 sendLen = le > sendLen ? sendLen : le; 226 apdu.setOutgoingLength(sendLen); 227 apdu.sendBytesLong(respBuf, respBuffOffset, sendLen); 228 respBuffOffset += sendLen; 229 sendLen = (short) (respBuf.length - respBuffOffset); 230 if (sendLen > 0) { 231 if (sendLen > 256) sendLen = 0x00; 232 ISOException.throwIt((short)(ISO7816.SW_BYTES_REMAINING_00 | sendLen)); 233 } 234 } else { 235 ISOException.throwIt((short)(ISO7816.SW_CORRECT_LENGTH_00 | 0xFF)); 236 } 237 break; 238 case CHECK_SELECT_P2_APDU: 239 byte[] p2_00 = new byte[] {0x00}; 240 le = apdu.setOutgoing(); 241 apdu.setOutgoingLength((short) p2_00.length); 242 Util.arrayCopy(p2_00, (short) 0, buf, (short) 0, (short) p2_00.length); 243 apdu.sendBytesLong(buf, (short)0, (short)p2_00.length); 244 break; 245 default: 246 // Case is not known. 247 ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); 248 } 249 } 250 251 /** 252 * Fills APDU buffer with a pattern. 253 * 254 * @param le - length of outgoing data. 255 */ fillBerTLVBytes(short le)256 public short fillBerTLVBytes(short le) { 257 //support length from 0x00 - 0x7FFF 258 short total_len; 259 short le_len = 1; 260 if (le < (short)0x80) { 261 le_len = 1; 262 } else if (le < (short)0x100) { 263 le_len = 2; 264 } else { 265 le_len = 3; 266 } 267 total_len = (short)(le + 2 + le_len); 268 short i = 0; 269 respBuf = new byte[total_len]; 270 respBuf[(short)i] = BER_TLV_TYPE; 271 i = (short)(i + 1); 272 respBuf[(short)i] = 0x00; //second byte of Type 273 i = (short)(i + 1); 274 if (le < (short)0x80) { 275 respBuf[(short)i] = (byte)le; 276 i = (short)(i + 1); 277 } else if (le < (short)0x100) { 278 respBuf[(short)i] = (byte)0x81; 279 i = (short)(i + 1); 280 respBuf[(short)i] = (byte)le; 281 i = (short)(i + 1); 282 } else { 283 respBuf[(short)i] = (byte)0x82; 284 i = (short)(i + 1); 285 respBuf[(short)i] = (byte)(le >> 8); 286 i = (short)(i + 1); 287 respBuf[(short)i] = (byte)(le & 0xFF); 288 i = (short)(i + 1); 289 } 290 while (i < total_len) { 291 respBuf[i] = (byte)((i - 2 - le_len) & 0xFF); 292 i = (short)(i + 1); 293 } 294 respBuf[(short)(respBuf.length - 1)] = (byte)0xFF; 295 respBuffOffset = (short) 0; 296 return total_len; 297 } 298 fillBytes(short total_len)299 public short fillBytes(short total_len) { 300 short i = 0; 301 short len = total_len; 302 respBuf = new byte[total_len]; 303 while (i < total_len) { 304 if (len >= LENGTH_256) { 305 Util.arrayCopyNonAtomic(resp_bytes256, (short)0, respBuf, 306 (short)i, LENGTH_256); 307 i = (short)(i + LENGTH_256); 308 len = (short)(len - LENGTH_256); 309 } else { 310 respBuf[i] = (byte)(i & 0xFF); 311 i = (short)(i + 1); 312 } 313 } 314 respBuffOffset = (short) 0; 315 //set the last byte to 0xFF for CTS validation 316 respBuf[(short)(respBuf.length - 1)] = (byte)0xFF; 317 return total_len; 318 } 319 } 320