/** * Searches for an index to the file specified by the id in the file structure starting from * position start. * * @param fileStructureArray the array with the file structure * @param shift the shift in the input array (e.g. when the array is the APDU with the header * bytes) * @param start starting position to search * @param lastOffset the last valid offset in the input array * @param id the id of the file that is searched * @return the index of the file, if found * @throws ArrayIndexOutOfBoundsException when start and lastOffset point outside of the input * array * @throws FileNotFoundException when file not found */ short searchId(byte[] fileStructureArray, short shift, short start, short lastOffset, short id) throws ArrayIndexOutOfBoundsException, FileNotFoundException { if (start < 0 || start > (short) (lastOffset - 5)) { // This sould produce ArrayIndexOutOfBoundsException fileStructureArray[fileStructureArray.length] = (byte) 0xFF; } short fid = Util.getShort(fileStructureArray, (short) (start + 1)); if (fid == id) { return start; } if (fileStructureArray[start] != DIR) { throw fnfe; } else { short childNum = fileStructureArray[(short) (start + 4)]; if (start > (short) ((short) (lastOffset - 5) - childNum)) { fileStructureArray[fileStructureArray.length] = (byte) 0xFF; } for (short i = 0; i < childNum; i++) { try { return searchId( fileStructureArray, shift, (short) (fileStructureArray[(short) (start + (short) (5 + i))] + shift), lastOffset, id); } catch (FileNotFoundException e) { } } } throw fnfe; }
/* 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; }
private void processCreateFile(APDU apdu) { if (state != STATE_INITIAL) { ISOException.throwIt(SW_INS_NOT_SUPPORTED); } byte[] buf = apdu.getBuffer(); short lc = unsigned(buf[OFFSET_LC]); apdu.setIncomingAndReceive(); if (lc != 5) { ISOException.throwIt(SW_WRONG_LENGTH); } short offset = OFFSET_CDATA; short id = Util.getShort(buf, offset); offset += 2; short len = Util.getShort(buf, offset); offset += 2; byte perm = buf[offset]; if (!fileSystem.createFile(id, len, perm)) { ISOException.throwIt(SW_WRONG_DATA); } }
/* 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; }
/** * \brief Decode the length field of a TLV-entry. * * <p>The length field itself can be 1, 2 or 3 bytes long: - If the length is between 0 and 127, * it is 1 byte long. - If the length is between 128 and 255, it is 2 bytes long. The first byte * is 0x81 to indicate this. - If the length is between 256 and 65535, it is 3 bytes long. The * first byte is 0x82, the following 2 contain the actual length. Note: Only lengths up to 0x7FFF * (32767) are supported here, because a short in Java is signed. * * <p>\param buf The buffer containing the length field. * * <p>\param offset The offset at where the length field starts. * * <p>\param length The length of the buffer (buf). This is to prevent that the index gets out of * bounds. * * <p>\return The (positive) length encoded by the length field, or in case of an error, -1. * * <p>\throw InvalidArgumentsException If offset is too big for a signed Java short If the first * byte of the length field is invalid */ public static short decodeLengthField(byte[] buf, short offset) throws InvalidArgumentsException { if (buf[offset] == (byte) 0x82) { // 256..65535 // Check for short overflow // (In Java, a short is signed: positive values are 0000..7FFF) if (buf[(short) (offset + 1)] < 0) { // 80..FF throw InvalidArgumentsException.getInstance(); } return Util.getShort(buf, (short) (offset + 1)); } else if (buf[offset] == (byte) 0x81) { return (short) (0x00FF & buf[(short) (offset + 1)]); } else if (buf[offset] > 0) { // 00..7F return (short) (0x007F & buf[offset]); } else { throw InvalidArgumentsException.getInstance(); } }
private short findEntryRelative(short start, short id) throws FileNotFoundException { try { if (fileStructure[start] != DIR) { throw fnfe; } short childNum = fileStructure[(short) (start + 4)]; for (short i = 0; i < childNum; i++) { short index = fileStructure[(short) (start + (short) (5 + i))]; short fid = Util.getShort(fileStructure, (short) (index + 1)); if (fid == id) { return index; } } } catch (ArrayIndexOutOfBoundsException aioobe) { } throw fnfe; }
private short getFileIndex(short fid) throws ISOException { short result = -1; switch (fid) { case EF_DG1_FID: result = EF_DG1_INDEX; break; case EF_DG2_FID: result = EF_DG2_INDEX; break; case EF_DG3_FID: result = EF_DG3_INDEX; break; case EF_DG4_FID: result = EF_DG4_INDEX; break; case EF_DG5_FID: result = EF_DG5_INDEX; break; case EF_DG6_FID: result = EF_DG6_INDEX; break; case EF_DG7_FID: result = EF_DG7_INDEX; break; case EF_DG8_FID: result = EF_DG8_INDEX; break; case EF_DG9_FID: result = EF_DG9_INDEX; break; case EF_DG10_FID: result = EF_DG10_INDEX; break; case EF_DG11_FID: result = EF_DG11_INDEX; break; case EF_DG12_FID: result = EF_DG12_INDEX; break; case EF_DG13_FID: result = EF_DG13_INDEX; break; case EF_DG14_FID: result = EF_DG14_INDEX; break; case EF_DG15_FID: result = EF_DG15_INDEX; break; case EF_DG16_FID: result = EF_DG16_INDEX; break; case EF_SOD_FID: result = EF_SOD_INDEX; break; case EF_COM_FID: result = EF_COM_INDEX; break; default: result = -1; break; } if (result != -1 && SmartIDApplet.isLocked() && SmartIDApplet.hasMutualAuthenticationKeys()) { // We are in the personalized state and BAC is active, // we need to control the access // a. check that the current authorization level is sufficient to // access // the given file // b. if we are passed the EAC protocol we also need to check // whether the current certificate authorization allows us to read the file. byte perm = filePerms[result]; if ((byte) (perm & SmartIDApplet.volatileState[0]) != perm) { ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED); } if (result <= EF_DG16_INDEX && SmartIDApplet.hasTerminalAuthenticated() && perm == SmartIDApplet.TERMINAL_AUTHENTICATED) { short m = (short) (0x1 << result); if ((Util.getShort(currentAuthorization, (short) 1) & m) != m) { ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED); } } } return result; }