/* * DrivingLicenseApplet - A reference implementation of the ISO18013 standards. * Based on the passport applet code developed by the JMRTD team, see * http://jmrtd.org * * Copyright (C) 2006 SoS group, Radboud University * Copyright (C) 2009 Wojciech Mostowski, Radboud University * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ package org.isodl.applet; import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.JCSystem; import javacard.framework.Util; /** * Files system (with different authorization levels). * * @author Martijn Oostdijk (martijno@cs.ru.nl) * @author Cees-Bart Breunesse (ceesb@cs.ru.nl) * @author Wojciech Mostowski <woj@cs.ru.nl> * */ public class FileSystem { static final short EF_DG1_FID = (short) 0x0001; static final short EF_DG2_FID = (short) 0x0002; static final short EF_DG3_FID = (short) 0x0003; static final short EF_DG4_FID = (short) 0x0004; static final short EF_DG5_FID = (short) 0x0005; static final short EF_DG6_FID = (short) 0x0006; static final short EF_DG7_FID = (short) 0x0007; static final short EF_DG8_FID = (short) 0x0008; static final short EF_DG9_FID = (short) 0x0009; static final short EF_DG10_FID = (short) 0x000A; static final short EF_DG11_FID = (short) 0x000B; static final short EF_DG12_FID = (short) 0x000C; static final short EF_DG13_FID = (short) 0x000D; static final short EF_DG14_FID = (short) 0x000E; static final short EF_DG15_FID = (short) 0x000F; static final short EF_SOD_FID = (short) 0x001D; static final short EF_COM_FID = (short) 0x001E; static final short SOS_LOG_FID = (short) 0xdead; private static final short EF_DG1_INDEX = (short) 0; private static final short EF_DG2_INDEX = (short) 1; private static final short EF_DG3_INDEX = (short) 2; private static final short EF_DG4_INDEX = (short) 3; private static final short EF_DG5_INDEX = (short) 4; private static final short EF_DG6_INDEX = (short) 5; private static final short EF_DG7_INDEX = (short) 6; private static final short EF_DG8_INDEX = (short) 7; private static final short EF_DG9_INDEX = (short) 8; private static final short EF_DG10_INDEX = (short) 9; private static final short EF_DG11_INDEX = (short) 10; private static final short EF_DG12_INDEX = (short) 11; private static final short EF_DG13_INDEX = (short) 12; private static final short EF_DG14_INDEX = (short) 13; private static final short EF_DG15_INDEX = (short) 14; private static final short EF_SOD_INDEX = (short) 15; private static final short EF_COM_INDEX = (short) 16; private static final short SOS_LOG_INDEX = (short) 17; private Object[] files; private short[] fileSizes; private byte[] filePerms; byte[] currentAuthorization; FileSystem() { files = new Object[18]; fileSizes = new short[18]; filePerms = new byte[18]; currentAuthorization = JCSystem.makeTransientByteArray((short) 3, JCSystem.CLEAR_ON_DESELECT); // The default read authorization for all DGs is mutual authentication // required for (short i = 0; i < 18; i++) { filePerms[i] = LicenseApplet.MUTUAL_AUTHENTICATED; } filePerms[EF_DG14_INDEX] = (byte) 0x00; } void createFile(short fid, short size, boolean eapProtection) { short idx = getFileIndex(fid); // first create determines maximum file size if (files[idx] == null) files[idx] = new byte[size]; if (((byte[]) files[idx]).length < size) ISOException.throwIt(ISO7816.SW_FILE_FULL); fileSizes[idx] = size; if(eapProtection) { filePerms[idx] = LicenseApplet.TERMINAL_AUTHENTICATED; } } void writeData(short fid, short file_offset, byte[] data, short data_offset, short length) { byte[] file = getFile(fid); short fileSize = getFileSize(fid); if (file == null) { ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND); } if (fileSize < (short) (file_offset + length)) ISOException.throwIt(ISO7816.SW_FILE_FULL); Util.arrayCopyNonAtomic(data, data_offset, file, file_offset, length); // Extract the pointers to where the Root and Alternate root CVCA certificate // identifiers are stored. Properly this should be done with a BERTLVScanner or // similar. if(fid == EF_COM_FID) { short cvcaRootIndex = -1; short cvcaAltIndex = -1; for(short i = 0; i<length ; i++) { if(data[i] == 0x04 && data[(short)(i+1)] == 0x11) { if(cvcaRootIndex == -1) { cvcaRootIndex = (short)((short)(file_offset + i) + 2); }else{ cvcaAltIndex = (short)((short)(file_offset + i) + 2); } } } LicenseApplet.certificate.setCOMFileData(file, cvcaRootIndex, cvcaAltIndex); } } byte[] getFile(short fid) { short idx = getFileIndex(fid); if (idx == -1) { return null; } return (byte[]) files[idx]; } short getFileSize(short fid) { short idx = getFileIndex(fid); if (idx == -1) { return -1; } return fileSizes[idx]; } 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_SOD_FID: result = EF_SOD_INDEX; break; case EF_COM_FID: result = EF_COM_INDEX; break; case SOS_LOG_FID: result = SOS_LOG_INDEX; break; default: result = -1; break; } if (result != -1 && LicenseApplet.isLocked() && LicenseApplet.hasMutualAuthenticationKeys()) { // We are in the personalised state and BAP is active, // we need to control the access // a. check that the current autorization level is sufficient to // access // the given file // b. if we are passed the EAP protocol we also need to check // whether the // current certificate authorization allows us to read the file. // See ISO18013-3 Table 24 and related for details. byte perm = filePerms[result]; if ((byte) (perm & LicenseApplet.volatileState[0]) != perm) { ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED); } if (result <= EF_DG15_INDEX && LicenseApplet.hasTerminalAuthenticated() && perm == LicenseApplet.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; } }