/* * The MIT License (MIT) *

* Copyright (c) 2017 Bertrand Martel *

* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: *

* The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. *

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package fr.bmartel.aram; import fr.bmartel.aram.util.TestUtils; import javacard.framework.ISO7816; import org.junit.Before; import org.junit.Test; import pro.javacard.gp.GPDataException; import pro.javacard.gp.SEAccessControl; import javax.smartcardio.CardException; import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; import java.util.List; import static org.junit.Assert.*; /** * Testing ARAM applet. * * @author Bertrand Martel */ public class AramTest extends JavaCardTest { private void sendGetAll(byte[] data, int expectedSw, byte[] expectedResponse) throws CardException { TestUtils.sendCmdBatch(this, AramConstTest.CMD_GET_ALL, data, expectedSw, expectedResponse); } private void sendGetNext(byte[] data, int expectedSw, byte[] expectedResponse) throws CardException { TestUtils.sendCmdBatch(this, AramConstTest.CMD_GET_NEXT, data, expectedSw, expectedResponse); } private ResponseAPDU sendGetRefreshTag(byte[] data, int expectedSw) throws CardException { return TestUtils.sendCmdBatch(this, AramConstTest.CMD_GET_REFRESH_TAG, data, expectedSw); } private void deleteAllRules() throws CardException, GPDataException { CommandAPDU commandAPDU = new CommandAPDU(TestUtils.buildApdu(AramConstTest.CMD_GET_ALL, new byte[]{})); ResponseAPDU response = this.transmitCommand(commandAPDU); SEAccessControl.BerTlvData temp = SEAccessControl.AcrListResponse.getAcrListData(null, response.getData()); while (temp.getCurrentIndex() < temp.getLength()) { commandAPDU = new CommandAPDU(TestUtils.buildApdu(AramConstTest.CMD_GET_NEXT, new byte[]{})); response = this.transmitCommand(commandAPDU); temp = SEAccessControl.AcrListResponse.getAcrListData(temp, response.getData()); } List resp = SEAccessControl.AcrListResponse.fromBytes(temp.getLength(), temp.getData()).acrList; for (int i = 0; i < resp.size(); i++) { deleteData(resp.get(i).getBytes()); } sendGetAll(new byte[]{}, 0x9000, AramConstTest.GET_DATA_EMPTY_RESPONSE); } @Before public void initTest() throws NoSuchFieldException, IllegalAccessException, CardException, GPDataException { TestSuite.setup(); deleteAllRules(); } @Test public void wrongClass() throws CardException { TestUtils.sendCmdBatch(this, AramConstTest.CMD_WRONG_CLA, new byte[]{}, ISO7816.SW_CLA_NOT_SUPPORTED, new byte[]{}); } @Test public void wrongInstruction() throws CardException { TestUtils.sendCmdBatch(this, AramConstTest.CMD_WRONG_INS, new byte[]{}, ISO7816.SW_INS_NOT_SUPPORTED, new byte[]{}); } @Test public void wrongP1P2GetData() throws CardException { TestUtils.sendCmdBatch(this, AramConstTest.CMD_WRONG_P1P2_GET_DATA, new byte[]{}, ISO7816.SW_INCORRECT_P1P2, new byte[]{}); } @Test public void getAllEmptyTest() throws CardException { sendGetAll(new byte[]{}, 0x9000, AramConstTest.GET_DATA_EMPTY_RESPONSE); } @Test public void wrongP1P2StoreData() throws CardException { TestUtils.sendCmdBatch(this, AramConstTest.CMD_WRONG_P1P2_STORE_DATA, new byte[]{}, ISO7816.SW_INCORRECT_P1P2, new byte[]{}); } @Test public void storeDataWrongStore() throws CardException { TestUtils.sendCmdBatch(this, TestUtils.concatByteArray(AramConstTest.CMD_STORE_HEADER, new byte[]{(byte) AramConstTest.CMD_STORE_DATA_INVALID_CMD_STORE.length}, AramConstTest.CMD_STORE_DATA_INVALID_CMD_STORE), new byte[]{}, ISO7816.SW_DATA_INVALID, new byte[]{}); } @Test public void storeDataWrongRefArDo() throws CardException { TestUtils.sendCmdBatch(this, TestUtils.concatByteArray(AramConstTest.CMD_STORE_HEADER, new byte[]{(byte) AramConstTest.CMD_STORE_DATA_INVALID_REFARDO.length}, AramConstTest.CMD_STORE_DATA_INVALID_REFARDO), new byte[]{}, ISO7816.SW_DATA_INVALID, new byte[]{}); } @Test public void storeDataWrongRefDo() throws CardException { TestUtils.sendCmdBatch(this, TestUtils.concatByteArray(AramConstTest.CMD_STORE_HEADER, new byte[]{(byte) AramConstTest.CMD_STORE_DATA_INVALID_REFDO.length}, AramConstTest.CMD_STORE_DATA_INVALID_REFDO), new byte[]{}, ISO7816.SW_DATA_INVALID, new byte[]{}); } @Test public void storeDataWrongAidRefDo() throws CardException { TestUtils.sendCmdBatch(this, TestUtils.concatByteArray(AramConstTest.CMD_STORE_HEADER, new byte[]{(byte) AramConstTest.CMD_STORE_DATA_INVALID_AIDREFDO.length}, AramConstTest.CMD_STORE_DATA_INVALID_AIDREFDO), new byte[]{}, ISO7816.SW_DATA_INVALID, new byte[]{}); } @Test public void storeDataWrongHashRefDo() throws CardException { TestUtils.sendCmdBatch(this, TestUtils.concatByteArray(AramConstTest.CMD_STORE_HEADER, new byte[]{(byte) AramConstTest.CMD_STORE_DATA_INVALID_HASHREFDO.length}, AramConstTest.CMD_STORE_DATA_INVALID_HASHREFDO), new byte[]{}, ISO7816.SW_DATA_INVALID, new byte[]{}); } @Test public void storeDataWrongArDo() throws CardException { TestUtils.sendCmdBatch(this, TestUtils.concatByteArray(AramConstTest.CMD_STORE_HEADER, new byte[]{(byte) AramConstTest.CMD_STORE_DATA_INVALID_ARDO.length}, AramConstTest.CMD_STORE_DATA_INVALID_ARDO), new byte[]{}, ISO7816.SW_DATA_INVALID, new byte[]{}); } private void storeData(byte[] refArDo) throws CardException { byte[] request = TestUtils.concatByteArray(new byte[]{ //F0 = Command-Store-AR-DO (byte) 0xF0, (byte) refArDo.length }, refArDo); TestUtils.sendCmdBatch(this, TestUtils.concatByteArray(AramConstTest.CMD_STORE_HEADER, new byte[]{(byte) request.length}, request), new byte[]{}, 0x9000, new byte[]{}); } private void updateRefreshTag() throws CardException { byte[] request = new byte[]{ //F0 = Command-Store-AR-DO (byte) 0xF2, (byte) 0 }; TestUtils.sendCmdBatch(this, TestUtils.concatByteArray(AramConstTest.CMD_STORE_HEADER, new byte[]{(byte) request.length}, request), new byte[]{}, 0x9000, new byte[]{}); } private ResponseAPDU getSpecific(byte[] refDo, byte[] expected) throws CardException { byte[] request = TestUtils.concatByteArray(new byte[]{(byte) refDo.length}, refDo); return TestUtils.sendCmdBatch(this, TestUtils.concatByteArray(AramConstTest.CMD_GET_SPECIFIC, new byte[]{(byte) request.length}, request), new byte[]{}, 0x9000, expected); } private void deleteData(byte[] refArDo) throws CardException { byte[] request = TestUtils.concatByteArray(new byte[]{ //F1 = Command-Delete-AR-DO (byte) 0xF1, (byte) refArDo.length }, refArDo); TestUtils.sendCmdBatch(this, TestUtils.concatByteArray(AramConstTest.CMD_STORE_HEADER, new byte[]{(byte) request.length}, request), new byte[]{}, 0x9000, new byte[]{}); } @Test public void storeDataValid() throws CardException { storeData(AramConstTest.VALID_REF_AR_DO); sendGetAll(new byte[]{}, 0x9000, TestUtils.checkList(0, AramConstTest.VALID_REF_AR_DO)); } @Test public void storeDataMultiple() throws CardException { storeData(AramConstTest.VALID_REF_AR_DO); storeData(AramConstTest.VALID_REF_AR_DO1); sendGetAll(new byte[]{}, 0x9000, TestUtils.checkList(0, TestUtils.concatByteArray(AramConstTest.VALID_REF_AR_DO1, AramConstTest.VALID_REF_AR_DO))); } @Test public void storeDataMultipleNextLength2() throws CardException { storeData(AramConstTest.VALID_REF_AR_DO); storeData(AramConstTest.VALID_REF_AR_DO1); storeData(AramConstTest.VALID_REF_AR_DO2); storeData(AramConstTest.VALID_REF_AR_DO3); storeData(AramConstTest.VALID_REF_AR_DO4); sendGetAll(new byte[]{}, 0x9000, TestUtils.checkList(0, TestUtils.concatByteArray(AramConstTest.VALID_REF_AR_DO4, AramConstTest.VALID_REF_AR_DO3, AramConstTest.VALID_REF_AR_DO2, AramConstTest.VALID_REF_AR_DO1, AramConstTest.VALID_REF_AR_DO))); } @Test public void storeDataMultipleNextLength3() throws CardException { storeData(AramConstTest.VALID_REF_AR_DO); storeData(AramConstTest.VALID_REF_AR_DO1); storeData(AramConstTest.VALID_REF_AR_DO2); storeData(AramConstTest.VALID_REF_AR_DO3); storeData(AramConstTest.VALID_REF_AR_DO4); storeData(AramConstTest.VALID_REF_AR_DO5); sendGetAll(new byte[]{}, 0x9000, TestUtils.checkList(0, TestUtils.concatByteArray(AramConstTest.VALID_REF_AR_DO5, AramConstTest.VALID_REF_AR_DO4, AramConstTest.VALID_REF_AR_DO3, AramConstTest.VALID_REF_AR_DO2, AramConstTest.VALID_REF_AR_DO1, AramConstTest.VALID_REF_AR_DO))); } @Test public void storeDataMultipleNextLength1next() throws CardException { storeData(AramConstTest.VALID_REF_AR_DO); storeData(AramConstTest.VALID_REF_AR_DO1); storeData(AramConstTest.VALID_REF_AR_DO2); storeData(AramConstTest.VALID_REF_AR_DO3); storeData(AramConstTest.VALID_REF_AR_DO4); storeData(AramConstTest.VALID_REF_AR_DO5); storeData(AramConstTest.VALID_REF_AR_DO6); storeData(AramConstTest.VALID_REF_AR_DO7); byte[] expectedData = TestUtils.concatByteArray(AramConstTest.VALID_REF_AR_DO7, AramConstTest.VALID_REF_AR_DO6, AramConstTest.VALID_REF_AR_DO5, AramConstTest.VALID_REF_AR_DO4, AramConstTest.VALID_REF_AR_DO3, AramConstTest.VALID_REF_AR_DO2, AramConstTest.VALID_REF_AR_DO1, AramConstTest.VALID_REF_AR_DO); sendGetAll(new byte[]{}, 0x9000, TestUtils.checkList(0, expectedData)); sendGetNext(new byte[]{}, 0x9000, TestUtils.checkList(1, expectedData)); sendGetNext(new byte[]{}, 0x6A88, new byte[]{}); } @Test public void storeDataMultipleNextLength2next() throws CardException { storeData(AramConstTest.VALID_REF_AR_DO); storeData(AramConstTest.VALID_REF_AR_DO1); storeData(AramConstTest.VALID_REF_AR_DO2); storeData(AramConstTest.VALID_REF_AR_DO3); storeData(AramConstTest.VALID_REF_AR_DO4); storeData(AramConstTest.VALID_REF_AR_DO5); storeData(AramConstTest.VALID_REF_AR_DO6); storeData(AramConstTest.VALID_REF_AR_DO7); storeData(AramConstTest.VALID_REF_AR_DO8); storeData(AramConstTest.VALID_REF_AR_DO9); storeData(AramConstTest.VALID_REF_AR_DO10); byte[] expectedData = TestUtils.concatByteArray(AramConstTest.VALID_REF_AR_DO10, AramConstTest.VALID_REF_AR_DO9, AramConstTest.VALID_REF_AR_DO8, AramConstTest.VALID_REF_AR_DO7, AramConstTest.VALID_REF_AR_DO6, AramConstTest.VALID_REF_AR_DO5, AramConstTest.VALID_REF_AR_DO4, AramConstTest.VALID_REF_AR_DO3, AramConstTest.VALID_REF_AR_DO2, AramConstTest.VALID_REF_AR_DO1, AramConstTest.VALID_REF_AR_DO); sendGetAll(new byte[]{}, 0x9000, TestUtils.checkList(0, expectedData)); sendGetNext(new byte[]{}, 0x9000, TestUtils.checkList(1, expectedData)); sendGetNext(new byte[]{}, 0x9000, TestUtils.checkList(2, expectedData)); sendGetNext(new byte[]{}, 0x6A88, new byte[]{}); } @Test public void nextDataNotFound() throws CardException { sendGetNext(new byte[]{}, 0x6A88, new byte[]{}); } @Test public void nextDataSingleNextLengthRequest() throws CardException, IllegalAccessException, NoSuchFieldException, GPDataException { storeData(AramConstTest.VALID_REF_AR_DO); storeData(AramConstTest.VALID_REF_AR_DO1); storeData(AramConstTest.VALID_REF_AR_DO2); storeData(AramConstTest.VALID_REF_AR_DO3); storeData(AramConstTest.VALID_REF_AR_DO4); storeData(AramConstTest.VALID_REF_AR_DO5); byte[] expectedData = TestUtils.concatByteArray(AramConstTest.VALID_REF_AR_DO5, AramConstTest.VALID_REF_AR_DO4, AramConstTest.VALID_REF_AR_DO3, AramConstTest.VALID_REF_AR_DO2, AramConstTest.VALID_REF_AR_DO1, AramConstTest.VALID_REF_AR_DO); sendGetAll(new byte[]{}, 0x9000, TestUtils.checkList(0, expectedData)); sendGetNext(new byte[]{}, 0x9000, TestUtils.checkList(1, expectedData)); sendGetNext(new byte[]{}, 0x6A88, new byte[]{}); } @Test public void deleteAll() throws CardException { storeData(AramConstTest.VALID_REF_AR_DO); storeData(AramConstTest.VALID_REF_AR_DO_CLONE); deleteData(new byte[]{}); sendGetAll(new byte[]{}, 0x9000, AramConstTest.GET_DATA_EMPTY_RESPONSE); } @Test public void deleteByAid() throws CardException { storeData(AramConstTest.VALID_REF_AR_DO); sendGetAll(new byte[]{}, 0x9000, TestUtils.checkList(0, AramConstTest.VALID_REF_AR_DO)); deleteData(AramConstTest.AID_REF_DO); sendGetAll(new byte[]{}, 0x9000, AramConstTest.GET_DATA_EMPTY_RESPONSE); } @Test public void deleteMultipleSameAid() throws CardException { storeData(AramConstTest.VALID_REF_AR_DO); storeData(AramConstTest.VALID_REF_AR_DO_CLONE); sendGetAll(new byte[]{}, 0x9000, TestUtils.checkList(0, TestUtils.concatByteArray(AramConstTest.VALID_REF_AR_DO_CLONE, AramConstTest.VALID_REF_AR_DO))); deleteData(AramConstTest.AID_REF_DO); sendGetAll(new byte[]{}, 0x9000, AramConstTest.GET_DATA_EMPTY_RESPONSE); } @Test public void deleteByAidHash() throws CardException { storeData(AramConstTest.VALID_REF_AR_DO); sendGetAll(new byte[]{}, 0x9000, TestUtils.checkList(0, AramConstTest.VALID_REF_AR_DO)); deleteData(AramConstTest.REF_DO); sendGetAll(new byte[]{}, 0x9000, AramConstTest.GET_DATA_EMPTY_RESPONSE); } @Test public void deleteByAidHashRule() throws CardException { storeData(AramConstTest.VALID_REF_AR_DO); sendGetAll(new byte[]{}, 0x9000, TestUtils.checkList(0, AramConstTest.VALID_REF_AR_DO)); deleteData(AramConstTest.VALID_REF_AR_DO); sendGetAll(new byte[]{}, 0x9000, AramConstTest.GET_DATA_EMPTY_RESPONSE); } @Test public void deleteByAidHashRuleEmpty() throws CardException { storeData(AramConstTest.VALID_REF_AR_DO); sendGetAll(new byte[]{}, 0x9000, TestUtils.checkList(0, AramConstTest.VALID_REF_AR_DO)); deleteData(AramConstTest.VALID_REF_AR_DO_EMPTY); sendGetAll(new byte[]{}, 0x9000, AramConstTest.GET_DATA_EMPTY_RESPONSE); } @Test public void refreshTag() throws CardException { byte[] req1 = sendGetRefreshTag(new byte[]{}, 0x9000).getData(); assertEquals(11, req1.length); assertArrayEquals(new byte[]{(byte) 0xDF,0x20}, new byte[]{req1[0],req1[1]}); assertEquals(8, req1[2]); byte[] req2 = sendGetRefreshTag(new byte[]{}, 0x9000).getData(); assertArrayEquals(req1, req2); updateRefreshTag(); byte[] req3 = sendGetRefreshTag(new byte[]{}, 0x9000).getData(); assertNotEquals(req3, req2); } @Test public void getSpecificArDo() throws CardException { storeData(AramConstTest.VALID_REF_AR_DO); sendGetAll(new byte[]{}, 0x9000, TestUtils.checkList(0, AramConstTest.VALID_REF_AR_DO)); getSpecific(AramConstTest.REF_DO, TestUtils.concatByteArray(new byte[]{(byte) 0xFF, (byte) 0x50, (byte) AramConstTest.VALID_REF_AR_DO.length}, AramConstTest.VALID_REF_AR_DO)); } }