/* input data is supposed to have been validaded before */ public static short GetBERTLVDataLen(byte[] buf, short offset, short len) { short size = 0; short sizeforsize = 0; short i = 1; if ((buf[offset] & 0x1F) != 0x1F) { // simplified tag } else { // tag start with all 5 last bits to 1 // skip the tag while (((buf[(short) (offset + i)] & 0x80) != 0) && ((short) (i + offset)) < len) { i++; } // pass the last byte of the tag i += 1; } // check the size if ((buf[(short) (offset + i)] & 0x80) != 0) { // size encoded in many bytes sizeforsize = (short) (buf[(short) (offset + i)] & 0x7F); if (sizeforsize > 2) { // more than two bytes for encoding => not something than we can handle return 0; } else if (sizeforsize == 1) { size = Util.makeShort((byte) 0, buf[(short) (offset + i + 1)]); } else if (sizeforsize == 2) { size = Util.getShort(buf, (short) (offset + i + 1)); } } else { // size encode in one byte size = Util.makeShort((byte) 0, buf[(short) (offset + i)]); } return size; }
/* returns 0 or the size of the BERTLV structure */ public static short CheckBERTLV(byte[] buf, short offset, short len) { short size = 0; short sizeforsize = 0; short i = 1; short totalsize = 0; if ((buf[offset] & 0x1F) != 0x1F) { // simplified tag } else { // tag start with all 5 last bits to 1 // skip the tag while (((buf[(short) (offset + i)] & 0x80) != 0) && i < len) { i++; } // pass the last byte of the tag i += 1; } if ((short) (i + 1) > len) { return 0; } // check the size if ((buf[(short) (offset + i)] & 0x80) != 0) { // size encoded in many bytes sizeforsize = (short) (buf[(short) (offset + i)] & 0x7F); if ((short) (i + 1 + sizeforsize) > len) { return 0; } if (sizeforsize > (short) 2) { // more than two bytes for encoding => not something than we can handle return 0; } else if (sizeforsize == (short) 1) { if ((short) (offset + i + 1 + sizeforsize) > len) { return 0; } size = Util.makeShort((byte) 0, buf[(short) (offset + i + 1)]); } else if (sizeforsize == 2) { totalsize = (short) (i + 1 + sizeforsize + size); if ((short) (offset + i + 1 + sizeforsize) > len) { return (short) 0; } size = Util.getShort(buf, (short) (offset + i + 1)); } } else { // size encode in one byte size = Util.makeShort((byte) 0, buf[(short) (offset + i)]); } totalsize = (short) (i + 1 + sizeforsize + size); if (totalsize < (short) 240 && (short) (offset + totalsize) > len) { return (short) 0; } return totalsize; }
/** Process the WRITE BINARY Instruction (0xD0). ISO7816-4 Section 7.2.4 */ private void processWriteBinary(APDU apdu) throws ISOException { if (state != STATE_INITIAL) { ISOException.throwIt(SW_INS_NOT_SUPPORTED); } byte[] buf = apdu.getBuffer(); byte p1 = buf[OFFSET_P1]; byte p2 = buf[OFFSET_P2]; short offset = 0; short ef = -1; if ((byte) (p1 & MASK_SFI) == MASK_SFI) { byte sfi = (byte) (p1 | ~MASK_SFI); if (sfi >= 0x1F) { ISOException.throwIt(SW_INCORRECT_P1P2); } ef = fileSystem.findCurrentSFI(sfi); if (ef == -1) { ISOException.throwIt(SW_FILE_NOT_FOUND); } ef = fileSystem.fileStructure[ef]; offset = unsigned(p2); } else { ef = fileSystem.getCurrentIndex(); if (fileSystem.getFile(ef) == null) { ISOException.throwIt(SW_COMMAND_NOT_ALLOWED); } offset = Util.makeShort(p1, p2); } byte[] file = fileSystem.getFile(ef); short lc = unsigned(buf[OFFSET_LC]); if ((short) (offset + lc) > file.length) { ISOException.throwIt(SW_WRONG_LENGTH); } apdu.setIncomingAndReceive(); Util.arrayCopyNonAtomic(buf, OFFSET_CDATA, file, offset, lc); }
/** * Process the READ BINARY instruction (0xB0) ISO7816-4 Section 7.2.3 * * <p>We handle only the INS == 0xB0 case. */ private void processReadBinary(APDU apdu) { if (state != STATE_PERSONALISED) { ISOException.throwIt(SW_CONDITIONS_NOT_SATISFIED); } byte[] buf = apdu.getBuffer(); byte p1 = buf[OFFSET_P1]; byte p2 = buf[OFFSET_P2]; short offset = 0; short ef = -1; if ((byte) (p1 & MASK_SFI) == MASK_SFI) { byte sfi = (byte) (p1 & ~MASK_SFI); if (sfi >= 0x1F) { ISOException.throwIt(SW_INCORRECT_P1P2); } ef = fileSystem.findCurrentSFI(sfi); if (ef == -1) { ISOException.throwIt(SW_FILE_NOT_FOUND); } ef = fileSystem.fileStructure[ef]; offset = unsigned(p2); } else { ef = fileSystem.getCurrentIndex(); if (fileSystem.getFile(ef) == null) { ISOException.throwIt(SW_COMMAND_NOT_ALLOWED); } offset = Util.makeShort(p1, p2); } byte[] file = fileSystem.getFile(ef); if (offset > file.length) { ISOException.throwIt(SW_INCORRECT_P1P2); } if (fileSystem.getPerm(ef) == FileSystem.PERM_PIN && !pin.isValidated()) { ISOException.throwIt(SW_SECURITY_STATUS_NOT_SATISFIED); } short le = apdu.setOutgoing(); if (le == 0 || le == 256) { le = (short) (file.length - offset); if (le > 256) le = 256; } boolean eof = false; if ((short) (file.length - offset) < le) { le = (short) (file.length - offset); eof = true; } apdu.setOutgoingLength(le); apdu.sendBytesLong(file, offset, le); if (eof) { ISOException.throwIt(SW_END_OF_FILE); } }
private short findEntryPath(short start, byte[] path, short offset, short length) throws FileNotFoundException { try { if (length == 0) { return start; } short id = Util.makeShort(path[offset], path[(short) (offset + 1)]); start = findEntryRelative(start, id); offset += 2; length = (short) (length - 2); return findEntryPath(start, path, offset, length); } catch (ArrayIndexOutOfBoundsException aioobe) { throw fnfe; } }
/** Process the SELECT (file) instruction (0xA4) ISO7816-4 Section 7.1.1 */ private void processSelectFile(APDU apdu) { byte[] buf = apdu.getBuffer(); byte p1 = buf[OFFSET_P1]; // byte p2 = buf[OFFSET_P2]; short lc = unsigned(buf[OFFSET_LC]); if (p1 == 0x04) { // Select the AID of the applet // do heavy verification, just for the fun of it ;) if (lc != (short) 0x0C) { ISOException.throwIt(SW_WRONG_LENGTH); } apdu.setIncomingAndReceive(); if (Util.arrayCompare(buf, OFFSET_CDATA, myAID, (short) 0, lc) != 0) { ISOException.throwIt(SW_WRONG_DATA); } return; } short id = 0; switch (p1) { case (byte) 0x00: // Direct selection of MF, DF, or EF: if (lc != 0 && lc != 2) { ISOException.throwIt(SW_WRONG_LENGTH); } if (lc > 0) { apdu.setIncomingAndReceive(); id = Util.makeShort(buf[OFFSET_CDATA], buf[(short) (OFFSET_CDATA + 1)]); } else { id = FileSystem.MASTER_FILE_ID; } if (!fileSystem.selectEntryAbsolute(id)) { ISOException.throwIt(SW_FILE_NOT_FOUND); } break; case (byte) 0x01: case (byte) 0x02: // Select the child under the current DF, // p1 0x01 DF identifier in data field // p1 0x02 EF identifier in data field if (lc != 2) { ISOException.throwIt(SW_WRONG_LENGTH); } apdu.setIncomingAndReceive(); id = Util.makeShort(buf[OFFSET_CDATA], buf[(short) (OFFSET_CDATA + 1)]); if (!fileSystem.selectEntryUnderCurrent(id, p1 == (byte) 0x02)) { ISOException.throwIt(SW_FILE_NOT_FOUND); } break; case (byte) 0x03: // Select the parent of the current DF // no command data if (lc != 0) { ISOException.throwIt(SW_WRONG_LENGTH); } if (!fileSystem.selectEntryParent()) { ISOException.throwIt(SW_FILE_NOT_FOUND); } break; case (byte) 0x08: case (byte) 0x09: // Select by path // p1 0x08 from MF // p1 0x09 from current DF // data field: the path without the head if (lc == 0 || (short) (lc % 2) != 0) { ISOException.throwIt(SW_WRONG_LENGTH); } apdu.setIncomingAndReceive(); if (!fileSystem.selectEntryByPath(buf, OFFSET_CDATA, lc, p1 == (byte) 0x08)) { ISOException.throwIt(SW_FILE_NOT_FOUND); } break; default: ISOException.throwIt(SW_INCORRECT_P1P2); } }