/* * GidsApplet: A Java Card implementation of the GIDS (Generic Identity * Device Specification) specification * https://msdn.microsoft.com/en-us/library/windows/hardware/dn642100%28v=vs.85%29.aspx * Copyright (C) 2016 Vincent Le Toux(vincent.letoux@mysmartlogon.com) * * It has been based on the IsoApplet * Copyright (C) 2014 Philip Wendland (wendlandphilip@gmail.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package com.mysmartlogon.gidsApplet; import javacard.framework.*; /** * \brief The ISO 7816 compliant GidsFileSystem class. * * It is the root of the file structure and is therefor equivalent to the ISO Master File (MF). * Normally, most of the file system oriented operations should happen through one object of this class. * * Due to the ISO 7816-4 DF and EF selection (see section 7.1) the currently selected DF and EF * are being saved internally. File-related operations are being executed upon those selected files respectively. * It is therefor possible to select a file and execute a number of operations upon this file without the need to * specify a target in each individual method call. This also saves execution time and reduces stack usage. * */ public class GidsFileSystem extends ApplicationFile { /* Additional ISO Status Words */ public static final byte OFFSET_CURRENT_DF = 0; public static final byte OFFSET_CURRENT_EF = 1; private Object[] currentlySelectedFiles = null; short currentRecordNum; private TransmitManager transmitManager = null; public static final short AFDID = 0x3FFF; private GidsPINManager pinManager = null; /** * \brief Instantiate a new ISO 7816 compliant GidsFileSystem. * * The GidsFileSystem class should normally only be instanciated once. It represents the file system and * is therefor equivalemt to the ISO Master File (MF). * Most of the file system related operations are performed through the returned object. * * \see GidsFileSystem. * * \param fileID The file ID of the master file. Should be 0x3F00 as specified by ISO. * * \param fileControlInformation The FCI according to ISO 7816-4 table 12. Necessary tags: 82, 83. No copy is made. */ public GidsFileSystem(GidsPINManager pinManager, TransmitManager transmitManager, short fileID, byte[] fileControlParameter, byte[] fileControlInformation, byte[] fileManagementData) { super(fileID, fileControlParameter, fileControlInformation, fileManagementData); this.currentRecordNum = 0; this.currentlySelectedFiles = JCSystem.makeTransientObjectArray((short) 2, JCSystem.CLEAR_ON_DESELECT); this.currentlySelectedFiles[OFFSET_CURRENT_DF] = this; this.pinManager = pinManager; this.transmitManager = transmitManager; // file system is in creation state } /** * \brief Get the currently selected DF. * * \return The currently selected DF. */ public DedicatedFile getCurrentlySelectedDF() { return ((DedicatedFile)currentlySelectedFiles[OFFSET_CURRENT_DF]); } /** * \brief Set the currently selected DF. * * \param fileID The ID of the file. * * \throw NotFoundException If the specified file was not found or was of the wrong type. */ public void setCurrentlySelectedDF(short fileID) throws NotFoundException { selectFile( findFile(fileID, SPECIFY_DF) ); return; } /** * \brief Get the currently selected Elementary File. * * \return The currently selected EF. */ public ElementaryFile getCurrentlySelectedEF() { return ((ElementaryFile)currentlySelectedFiles[OFFSET_CURRENT_EF]); } /** * \brief Set the currently selected Elementary File. * * \brief fileID The ID of the file. * * \throw NotFoundException If the specified file was not found or was of the wrong type. */ public void setCurrentlyselectedEF(short fileID) throws NotFoundException { selectFile( findFile(fileID, SPECIFY_EF) ); return; } /** * \brief Search for the DF with the specified name. * * \param dfName The array containing the up to 16 byte long DedicatedFile name. * * \param nameOffset The offset at which the DF name begins in the name array. * * \param nameLength The length of the DF name. * * \throw NotFoundException If the file was not found. * * \return The requested DedicatedFile (if found). */ public DedicatedFile findDedicatedFileByName(byte[] dfName, short nameOffset, short nameLength) throws NotFoundException { if (isName(dfName, nameOffset, nameLength)) { return this; } return super.findDedicatedFileByNameRec(dfName, nameOffset, nameLength); } /** * \brief find the file with the specified file ID. * * \param fileID the ID of the file. * * \param flag A flag to specify if the currently selected EF or DF is the target (SPECIFY_EF, SPECIFY_DF, SPECIFY_ANY). * * \throw NotFoundException If the file could not be found. * * \return The File (if found). */ public File findFile(short fileID, byte flag) throws NotFoundException { if(fileID == getFileID() && flag != SPECIFY_EF) { return this; } return super.findChildrenRec(fileID, flag); } public CRTKeyFile findKeyCRT(byte keyID) throws NotFoundException { File file = findFile(Util.makeShort((byte)0xB0, keyID), SPECIFY_EF); if (!(file instanceof CRTKeyFile)) { throw NotFoundException.getInstance(); } return (CRTKeyFile) file; } /** * \brief Set the given file as the selected. * * If the file is a DedicatedFile, only the currently selected DF is changed. * In case of an ElementaryFile the currently selected EF will be the file specified and the * currently selected DF will become its parent according to ISO 7816-4, section 7.1.1. * * \param file The file to select. Must be of DedicatedFile, GidsFileSystem or any subclass of ElementaryFile. * It should be member of the file system hierarchy (not checked). */ public void selectFile(File file) { if(file == null) { currentlySelectedFiles[OFFSET_CURRENT_DF] = this; currentlySelectedFiles[OFFSET_CURRENT_EF] = null; } else if(file instanceof DedicatedFile) { currentlySelectedFiles[OFFSET_CURRENT_DF] = file; currentlySelectedFiles[OFFSET_CURRENT_EF] = null; } else if (file instanceof ElementaryFile) { currentlySelectedFiles[OFFSET_CURRENT_EF] = file; currentlySelectedFiles[OFFSET_CURRENT_DF] = ((ElementaryFile)currentlySelectedFiles[OFFSET_CURRENT_EF]).getParentDF(); this.currentRecordNum = 0; } return; } /** * \brief Add a file to the currently selected DedicatedFile. * * The currently selected DF becomes the parent of the file. * The DF's child and the EF's parent relation is being updated. * * \param file A reference of the file to save. * * \throw NotEnoughSpaceException If the maximum amount of * children would have been exceeded. */ public void addFile(File file) throws NotEnoughSpaceException { file.setParentDF(getCurrentlySelectedDF()); getCurrentlySelectedDF().addChildren(file); return; } /** * \brief "Safely" instantiate a File according to the provided File Control Information. * * Used by processCreateFile(). * * \callergraph * * \param fci The array containing the file control information (FCI) according to * ISO7816-4 table 12. Mandatory Tags: 82, 83. A copy of the FCI will be * made for the new file. * * \param offset The offset of the FCI information in the array. * * \param length The length of the FCI information. Should be consistent with the length * field if the FCI (6F) tag. * * \throw ISOException SW_SECURITY_STATUS_NOT_SATISFIED. * * \return The new file of the FCI was valid, null else. */ public File getSafeFile(byte[] fci, short offset, short length) throws ISOException, InvalidArgumentsException, NotFoundException { short fileID; byte fileDescByte; final short innerLength, innerOffset; short pos, len; /* ********************** * Check FCI structure. * ************************/ // Are we in bounds? if((short)(fci.length) <= (short)(offset+length)) { throw InvalidArgumentsException.getInstance(); } // FCI must begin with tag "6F". Or we have FCP, tag "62". if(fci[(offset)] != (byte) 0x6F && fci[(offset)] != (byte) 0x62) { throw NotFoundException.getInstance(); } // length and length-field of outer FCI tag consistency check. innerLength = UtilTLV.decodeLengthField(fci, (short)(offset+1)); if(innerLength != (short)(length-1-UtilTLV.getLengthFieldLength(fci, (short)(offset+1)))) { throw InvalidArgumentsException.getInstance(); } // Let innerOffset point to the first inner TLV entry. innerOffset = (short) (offset + 1 + UtilTLV.getLengthFieldLength(fci, (short)(offset+1))); // Now we check for the consistency of the lower level TLV entries. if( ! UtilTLV.isTLVconsistent(fci, innerOffset, innerLength) ) { throw InvalidArgumentsException.getInstance(); } // Extract the FID from the FCI which is passed to the FileXXX contructor and saved // separately for performance reasons. pos = UtilTLV.findTag(fci, innerOffset, innerLength, (byte) 0x83); len = UtilTLV.decodeLengthField(fci, (short)(pos+1)); if (len != (short) 2) { throw InvalidArgumentsException.getInstance(); } fileID = Util.getShort(fci, (short)(pos+1+UtilTLV.getLengthFieldLength(fci, (short)(pos+1)))); // The fileID must be unique. try { this.findFile(fileID, SPECIFY_ANY); throw InvalidArgumentsException.getInstance(); } catch(NotFoundException e) { } // Check and get the File Descriptor Byte (ISO 7816-4 table 14). pos = UtilTLV.findTag(fci, innerOffset, innerLength, (byte) 0x82); len = UtilTLV.decodeLengthField(fci, (short)(pos+1)); // Ensure position found and correct length: if(len < (short)1 || len > (short)6) { throw InvalidArgumentsException.getInstance(); } fileDescByte = fci[(short)(pos+2)]; byte[] fciEEPROM = null; if(fileDescByte == 0x39) { // BER-TLV // Check the permissions. ((DedicatedFile)currentlySelectedFiles[OFFSET_CURRENT_DF]).CheckPermission(pinManager, ACL_OP_DF_CREATE_EF); fciEEPROM = new byte[length]; Util.arrayCopy(fci, offset, fciEEPROM, (short) 0, length); return new BerTlvFile(fileID, fciEEPROM); } else if(fileDescByte == 0x18) { // key file descriptor // Check if there is a CRT template // Search the CRT tag (A5). If not found, then raise an error try { pos = UtilTLV.findTag(fci, innerOffset, innerLength, (byte) 0xA5); len = UtilTLV.decodeLengthField(fci, (short)(pos+1)); } catch (NotFoundException e) { throw InvalidArgumentsException.getInstance(); } CRTKeyFile.CheckCRT(fci, pos, len); ((DedicatedFile)currentlySelectedFiles[OFFSET_CURRENT_DF]).CheckPermission(pinManager, ACL_OP_DF_CREATE_EF); fciEEPROM = new byte[length]; Util.arrayCopy(fci, offset, fciEEPROM, (short) 0, length); return new CRTKeyFile(fileID, fciEEPROM, (short) (pos - offset), len); } else { // Not a supported file format. throw InvalidArgumentsException.getInstance(); } } /* ************************************** * processXXX methods for ISO commands: * ****************************************/ /* ISO 7816-4 */ /** * \brief Process the SELECT (FILE) apdu. * * This method updates the currently selected EF or DF, according to the parameters in the apdu. * Every selection method according to ISO 7816-4 Table 39 is valid. * There are limitations of the P2 byte (b8...b1) at the moment, however: * - The first or only occurence is the only supported file occurence (b2b1 = 00) * - No FMD is returned. (b4b3 != 10, if b4b3 = 00 then the response only contains the FCP template.) * * \param apdu The SELECT (FILE) apdu * * \throw ISOException SW_INCORRECT_P1P2 and SW_FILE_NOT_FOUND. */ public void processSelectFile(APDU apdu, boolean selectingApplet) throws ISOException { byte[] buf = apdu.getBuffer(); byte p1 = buf[ISO7816.OFFSET_P1]; byte p2 = buf[ISO7816.OFFSET_P2]; short lc; short fid; File fileToSelect = null; if (selectingApplet) { fileToSelect = this; } else { // Only "first or only occurence" supported at the moment (ISO 7816-4 Table 40). if((p2 & 0xF3) != 0x00) { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } // Bytes received must be Lc. lc = apdu.setIncomingAndReceive(); // Select the file. switch(p1) { case 0x00: /* MF, DF or EF using FID */ if(lc == 0) { fileToSelect = this; } else if(lc == 2) { // we have a FID fid = Util.makeShort(buf[ISO7816.OFFSET_CDATA], buf[(short)(ISO7816.OFFSET_CDATA+1)]); if (fid == AFDID) { fileToSelect = this; } else { try { fileToSelect = findFile(fid , SPECIFY_ANY); } catch(NotFoundException e) { ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND); } } } break; case 0x04: /* by DF name */ try { fileToSelect = findDedicatedFileByName(buf, ISO7816.OFFSET_CDATA, lc); } catch(NotFoundException e) { ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND); } break; default: ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } } selectFile( fileToSelect ); /* * The file is selected now. We still have to check P2 to see if we need to return any FCI/FCP/FMD information. * If we have to, we can use the apdu buffer to save the TLV encoded entries as that is what we want to send back anyway (for performance reasons). * We don't use javacardx.framework.tlv.BERTLV as smartcard support is scarce.. */ lc = 0; // We re-use lc here for the length of the response data. switch(p2 & 0xFC) { case 0x00: /* Return FCI. */ if (fileToSelect instanceof ApplicationFile) { byte[] fci = ((ApplicationFile) fileToSelect).getFileControlInformation(); if(fci != null) { Util.arrayCopy(fci, (short) 0, buf, (short) 0, (short) (fci.length)); lc += (short) (fci.length); } else { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } } else { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } break; case 0x04: // Return FCP. if(fileToSelect.getFileControlParameter() != null) { Util.arrayCopy(fileToSelect.getFileControlParameter(), (short) 0, buf, (short) 0, (short) fileToSelect.getFileControlParameter().length); lc += (short) fileToSelect.getFileControlParameter().length; } break; case 0x08: // Return FMD. if (fileToSelect instanceof ApplicationFile) { byte[] fmd = ((ApplicationFile) fileToSelect).getFileManagementData(); if(fmd != null) { Util.arrayCopy(fmd, (short) 0, buf, (short) 0, (short) fmd.length); lc += (short) fmd.length; } else { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } } else { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } break; case 0x0C: // Return nothing. break; } if( lc > 0) { apdu.setOutgoingAndSend((short) 0, lc); } return; } /** * \brief Process the DELETE FILE apdu. * * \attention Only deletion by FID is supported. Lc must be 2, the DATA field * must contain the file ID. P1P2 must be 0000. * * \todo Add support for other file identification methods as in SELECT. * * \param apdu The DELETE FILE apdu. * * \throw ISOException SW_INCORRECT_P1P2, SW_WRONG_LENGTH, SW_FILE_NOT_FOUND and * SW_SECURITY_STATUS_NOT_SATISFIED. */ public void processDeleteFile(APDU apdu) throws ISOException { byte[] buf = apdu.getBuffer(); byte p1 = buf[ISO7816.OFFSET_P1]; byte p2 = buf[ISO7816.OFFSET_P2]; short lc; File fileToDelete = null; // Only P1P2 = 0000 is currently supported. // (File identifier must be encoded in the command data field.) if( p1 != 0x00 || p2 != 0x00 ) { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } // Bytes received must be Lc. lc = apdu.setIncomingAndReceive(); // One FID in DATA. if (lc == 0) { fileToDelete = getCurrentlySelectedEF(); if (fileToDelete == null) { fileToDelete = getCurrentlySelectedDF(); } } else { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } // Don't delete the MF. if(fileToDelete == this) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } // Permissions. fileToDelete.CheckPermission(pinManager, ACL_OP_EF_DELETE); // Update current DF before deletion. currentlySelectedFiles[OFFSET_CURRENT_DF] = (fileToDelete.getParentDF()); currentlySelectedFiles[OFFSET_CURRENT_EF] = null; // Remove from tree. Garbage collector has already been called by deleteChildren(). try { getCurrentlySelectedDF().deleteChildren(fileToDelete.getFileID()); } catch(NotFoundException e) { ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND); } } /** * \brief Process the CREATE FILE apdu. * * This method creates a file, adds it to the filesystem structure and selects it. * Configuration options are taken from the DATA field of the APDU. (I.e. P1 and P2 must be 00.) * The data field of the APDU must be 2-level nested TLV encoded. The upper level is the FCI (6F) or FCP (62) tag. * The nested information will be added to the file as FCI. Also, the following information is being taken in * order to allocate the right ressources: * - The file ID (tag 83) * - The file description byte (tag 82) to determine the type, also following information to determine record * sizes and amounts in case of non-transparent EFs. * - In the case of a transparent EF, the data size (excluding structural information) (tag 80) in order to * allocate enough space. * * \param apdu The SELECT (FILE) apdu * * \throw ISOException SW_INCORRECT_P1P2, SW_DATA_INVALID, SW_FILE_FULL and SW_SECURITY_STATUS_NOT_SATISFIED. */ public void processCreateFile(APDU apdu) throws ISOException { byte[] buf = apdu.getBuffer(); byte p1 = buf[ISO7816.OFFSET_P1]; byte p2 = buf[ISO7816.OFFSET_P2]; short lc; // Only P1P2 = 0000 supported. // (File identifier and parameters must be encoded in the command data field.) if( p1 != 0x00 || p2 != 0x00 ) { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } // Bytes received must be Lc. lc = apdu.setIncomingAndReceive(); try { // Add the file to the filesystem and select it. File fileToAdd = getSafeFile(buf, ISO7816.OFFSET_CDATA, lc); // getSafeFile performs permission checks. addFile(fileToAdd); selectFile(fileToAdd); } catch (NotFoundException e) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } catch (InvalidArgumentsException e) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } catch(NotEnoughSpaceException e) { ISOException.throwIt(ISO7816.SW_FILE_FULL); } catch(SystemException e) { if(e.getReason() == SystemException.NO_RESOURCE) { ISOException.throwIt(ISO7816.SW_FILE_FULL); } ISOException.throwIt(ISO7816.SW_UNKNOWN); } return; } public void processGetData(APDU apdu) { byte[] buf = apdu.getBuffer(); byte ins = buf[ISO7816.OFFSET_INS]; byte p1 = buf[ISO7816.OFFSET_P1]; byte p2 = buf[ISO7816.OFFSET_P2]; short lc, pos = 0, len = 0, fileID; File file = null; BerTlvFile bertlvfile = null; if (ins != (byte) 0xCB) { ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } // Bytes received must be Lc. lc = apdu.setIncomingAndReceive(); if (p1 == 0x3F && p2 == (byte) 0xFF) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } else if (p1 == 0x00 && p2 == 0x00) { file = getCurrentlySelectedEF(); } else if (p1 == (byte) 0xFF && p2 == (byte) 0xFF) { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } else { fileID = Util.getShort(buf, (short) 2); try { file = findFile(fileID, SPECIFY_EF); } catch (NotFoundException e) { ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND); } } if(!(file instanceof BerTlvFile)) { ISOException.throwIt(ErrorCode.SW_COMMAND_INCOMPATIBLE_WITH_FILE_STRUCTURE); } bertlvfile = (BerTlvFile) file; file.CheckPermission(pinManager, ACL_OP_DO_GET_DATA); fileID = bertlvfile.getFileID(); if (fileID != (short) 0x2F00 && fileID != (short) 0x2F01 && fileID != (short) 0x3F00 && fileID != (short) 0x0000) { // implicit selection not valid for every file selectFile(bertlvfile); } try { // Extract the FID from the FCI which is passed to the FileXXX contructor and saved // separately for performance reasons. pos = UtilTLV.findTag(buf, ISO7816.OFFSET_CDATA, (byte) lc, (byte) 0x5C); if (buf[(short)(pos+(short)1)] == (byte) 0) { len = (short) 0; } else { len = UtilTLV.decodeLengthField(buf, (short)(pos+1)); } } catch (Exception e) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } if ((len == 0) || (len == 1 && buf[(short) (pos+2)]== (byte)0x5C)) { transmitManager.sendRecords(apdu, bertlvfile.getAllData()); } else { try { Record record = bertlvfile.getData(buf, (short)(pos+1+UtilTLV.getLengthFieldLength(buf, (short)(pos+1))), (short) (ISO7816.OFFSET_CDATA + lc)); transmitManager.sendRecord(apdu,record); } catch (NotFoundException e) { ISOException.throwIt(ErrorCode.SW_REFERENCE_DATA_NOT_FOUND); } } } public void processPutData(APDU apdu) { byte[] buf = apdu.getBuffer(); byte ins = buf[ISO7816.OFFSET_INS]; byte p1 = buf[ISO7816.OFFSET_P1]; byte p2 = buf[ISO7816.OFFSET_P2]; short lc; short fileID; File file = null; BerTlvFile bertlvfile = null; short size; Record record = null; if (ins != (byte) 0xDB) { ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } if (p1 == (byte) 0x3F && p2 == (byte) 0xFF) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } else if (p1 == 0x00 && p2 == 0x00) { file = getCurrentlySelectedEF(); } else if (p1 == (byte) 0xFF && p2 == (byte) 0xFF) { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } else { fileID = Util.getShort(buf, (short) 2); try { file = findFile(fileID, SPECIFY_EF); } catch (NotFoundException e) { ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND); } } if(!(file instanceof BerTlvFile)) { ISOException.throwIt(ErrorCode.SW_COMMAND_INCOMPATIBLE_WITH_FILE_STRUCTURE); } bertlvfile = (BerTlvFile) file; file.CheckPermission(pinManager, ACL_OP_DO_PUT_DATA); selectFile(bertlvfile); lc = apdu.setIncomingAndReceive(); record = transmitManager.returnCachedRecord(); if (record == null && TransmitManager.isCommandChainingCLA(apdu)) { // handle first chained APDU size = UtilTLV.CheckBERTLV(buf, ISO7816.OFFSET_CDATA, (short) (ISO7816.OFFSET_CDATA + lc)); try { record = bertlvfile.addChildren(buf, ISO7816.OFFSET_CDATA, size, lc); } catch(NotEnoughSpaceException e) { ISOException.throwIt(ISO7816.SW_FILE_FULL); } catch(SystemException e) { if(e.getReason() == SystemException.NO_RESOURCE) { ISOException.throwIt(ISO7816.SW_FILE_FULL); } ISOException.throwIt(ISO7816.SW_UNKNOWN); } transmitManager.setCachedRecord(record); transmitManager.setCachedOffset(lc); } else if (record != null) { // handle next chained APDU short offset = transmitManager.returnCachedOffset(); byte[] data = record.GetData(); if ((short) (offset + lc) > data.length) { transmitManager.clearCachedRecord(); ISOException.throwIt(ISO7816.SW_DATA_INVALID); } Util.arrayCopyNonAtomic(buf, ISO7816.OFFSET_CDATA, data, offset, lc); transmitManager.setCachedOffset((short) (offset + lc)); if ((short) (offset + lc) == data.length) { transmitManager.clearCachedRecord(); } else if (!TransmitManager.isCommandChainingCLA(apdu)) { // the data sent is too short // clear it transmitManager.clearCachedRecord(); Util.arrayFillNonAtomic(data, (short) 0, (short) data.length, (byte) 0); ISOException.throwIt(ISO7816.SW_DATA_INVALID); } // else wait for the next record } else { size = UtilTLV.CheckBERTLV(buf, ISO7816.OFFSET_CDATA, (short) (ISO7816.OFFSET_CDATA + lc)); if (size <= 0) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } try { bertlvfile.addChildren(buf, ISO7816.OFFSET_CDATA, size, lc); } catch(NotEnoughSpaceException e) { ISOException.throwIt(ISO7816.SW_FILE_FULL); } catch(SystemException e) { if(e.getReason() == SystemException.NO_RESOURCE) { ISOException.throwIt(ISO7816.SW_FILE_FULL); } ISOException.throwIt(ISO7816.SW_UNKNOWN); } } return; } public void processActivateFile(APDU apdu) throws ISOException { byte[] buf = apdu.getBuffer(); byte p1 = buf[ISO7816.OFFSET_P1]; byte p2 = buf[ISO7816.OFFSET_P2]; if (p1 != 0x00 || p2 != 0x00) { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } // only a file or the applet can be selected File file = getCurrentlySelectedEF(); if (file == null) { file = getCurrentlySelectedDF(); if (file != this) { ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND); } } file.CheckPermission(pinManager, ACL_OP_EF_ACTIVATE); file.setState(STATE_OPERATIONAL_ACTIVATED); if (file == this) { pinManager.SetInitializationMode(false); } } }