/* * openjavacard-tools: Development tools for JavaCard * Copyright (C) 2019 Ingo Albrecht <[email protected]> * * 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 3.0 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.openjavacard.tool.command.generic; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import org.openjavacard.generic.GenericCard; import org.openjavacard.generic.GenericContext; import org.openjavacard.iso.ISO7816; import org.openjavacard.iso.SW; import org.openjavacard.tool.converter.BytesConverter; import org.openjavacard.util.APDUUtil; import org.openjavacard.util.HexUtil; import javax.smartcardio.CardException; import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; import java.io.PrintStream; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; @Parameters( commandNames = "scan-name", commandDescription = "Scanning: Scan a card using SELECT BY NAME" ) public class ScanName extends GenericCommand { @Parameter( names = "--base", converter = BytesConverter.class, description = "AID to start scanning at" ) byte[] aidBase; @Parameter( names = "--count", description = "Number of sequential AIDs to try" ) int aidCount = 256; @Parameter( names = "--depth", description = "Hierarchical depth of AIDs to try" ) int aidDepth = 0; @Parameter( names = "--recurse", description = "Hierarchical depth to recurse into found AIDs" ) int aidRecurse = 0; @Parameter( names = "--verbose", description = "Display each AID while scanning" ) boolean verbose = false; public ScanName(GenericContext context) { super(context); } @Override protected void performOperation(GenericCard card) throws CardException { scanNames(card, aidBase, aidDepth, aidRecurse); } private void scanNames(GenericCard card, byte[] base, int depth, int recurse) throws CardException { PrintStream os = System.out; BigInteger bStart = new BigInteger(Arrays.copyOf(base, base.length + depth)); BigInteger bLimit; if(aidDepth != 0) { BigInteger bDepth = BigInteger.valueOf(1 << (depth * 8)); bLimit = bStart.add(bDepth); } else { BigInteger bCount = BigInteger.valueOf(aidCount); bLimit = bStart.add(bCount); } os.println("SCANNING NAMES FROM " + HexUtil.bytesToHex(bStart.toByteArray()) + " BELOW " + HexUtil.bytesToHex(bLimit.toByteArray())); ArrayList<byte[]> found = new ArrayList<>(); for(BigInteger index = bStart; index.compareTo(bLimit) < 0; index = index.add(BigInteger.ONE)) { byte[] name = index.toByteArray(); if(verbose || (name[name.length - 1] == (byte)0xFF)) { os.println(" PROGRESS " + HexUtil.bytesToHex(name)); } ResponseAPDU rapdu = performSelect(card, name, true); int sw = rapdu.getSW(); if(sw == 0x9000) { String foundLog = " FOUND " + HexUtil.bytesToHex(name); found.add(name); byte[] data = rapdu.getData(); if(data.length > 0) { foundLog += " DATA " + HexUtil.bytesToHex(data); } os.println(foundLog); card.reconnect(true); } else if(sw == ISO7816.SW_FILE_NOT_FOUND) { continue; } else { os.println(" ERROR " + HexUtil.bytesToHex(name) + " " + SW.toString(sw)); card.reconnect(true); } } if(found.isEmpty()) { os.println(" FOUND NOTHING"); } if(recurse > 0) { for(byte[] aid: found) { scanNames(card, aid, 1, recurse - 1); } } } private ResponseAPDU performSelect(GenericCard card, byte[] aid, boolean first) throws CardException { byte p1 = ISO7816.SELECT_P1_BY_NAME; byte p2 = first ? ISO7816.SELECT_P2_FIRST_OR_ONLY : ISO7816.SELECT_P2_NEXT; CommandAPDU scapdu = APDUUtil.buildCommand( ISO7816.CLA_ISO7816, ISO7816.INS_SELECT, p1, p2, aid); return card.transmit(scapdu); } }