-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #269 from crocs-muni/devel
Version 1.8.2 release
- Loading branch information
Showing
27 changed files
with
584 additions
and
404 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,6 +40,8 @@ may be distributed under the terms of the GNU General Public License (GPL), | |
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
import java.util.regex.PatternSyntaxException; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import javax.smartcardio.ATR; | ||
import javax.smartcardio.Card; | ||
import javax.smartcardio.CardException; | ||
|
@@ -51,12 +53,24 @@ may be distributed under the terms of the GNU General Public License (GPL), | |
* @author petr | ||
*/ | ||
public class AlgTestJClient { | ||
/** | ||
* Version 1.8.2 (17.11.2024) | ||
* - Update to match applet version with delayed allocation by default | ||
* - Add detailed info for submitting results at beginning | ||
* - Add testing of ECC 640b keys | ||
* - Fix display of help info | ||
* - Add always send Le=256 to support certain cards (like Gemalto) expecting it | ||
* - Add sanity check for returned algtest buffer | ||
* - Improved used and fixed issues with CLI parameters | ||
* - Fix missing JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT in results | ||
*/ | ||
public final static String ALGTEST_JCLIENT_VERSION = "1.8.2"; | ||
/** | ||
* Version 1.8.1 (27.10.2021) | ||
* + Add better CLI control, interactive and non-interactive mode | ||
* + Fixed incorrect names for measurements | ||
*/ | ||
public final static String ALGTEST_JCLIENT_VERSION = "1.8.1"; | ||
//public final static String ALGTEST_JCLIENT_VERSION = "1.8.1"; | ||
/** | ||
* Version 1.8.0 (19.12.2020) | ||
* + testing of modular Cipher and Signature .getInstance variants | ||
|
@@ -165,72 +179,115 @@ public class AlgTestJClient { | |
* + initial version of AlgTestJClient, clone of AlgTestCppClient | ||
*/ | ||
//public final static String ALGTEST_JCLIENT_VERSION_1_0 = "1.0"; | ||
|
||
|
||
|
||
public final static int STAT_OK = 0; | ||
|
||
// Unique start time in milisconds | ||
static long m_appStartTime = 0; | ||
|
||
static Map<String, Map<String, String>> allResultsMap = new HashMap<>(); | ||
|
||
|
||
/** | ||
* @param args the command line arguments | ||
*/ | ||
|
||
static DirtyLogger m_SystemOutLogger = null; | ||
public static void main(String[] args) throws IOException, Exception { | ||
Map<String, String> tempInfo = new HashMap<>(); | ||
|
||
Args cmdArgs = new Args(); | ||
if (args.length > 0) { | ||
// cli version of tool | ||
JCommander.newBuilder() | ||
.addObject(cmdArgs) | ||
.build() | ||
.parse(args); | ||
|
||
if (!cmdArgs.baseOutPath.isEmpty()) { | ||
char lastChar = cmdArgs.baseOutPath.charAt(cmdArgs.baseOutPath.length() - 1); | ||
if ((lastChar != '\\') && (lastChar != '/')) { | ||
cmdArgs.baseOutPath = cmdArgs.baseOutPath + "/"; // adding '/' if not present | ||
} | ||
} | ||
} | ||
System.out.print("Command line arguments: "); | ||
for (int i = 0; i < args.length; i++) { | ||
System.out.print(args[i] + " "); | ||
} | ||
System.out.println(); | ||
|
||
String logFileName = String.format(cmdArgs.baseOutPath + "ALGTEST_log_%s.log", AlgTestJClient.getStartTime()); | ||
FileOutputStream systemOutLogger = new FileOutputStream(logFileName); | ||
tempInfo.put("out_file_name", logFileName); | ||
allResultsMap.put("main", tempInfo); | ||
m_SystemOutLogger = new DirtyLogger(systemOutLogger, true); | ||
|
||
m_SystemOutLogger.println("\n----------------------------------------------------------------------- "); | ||
m_SystemOutLogger.println("JCAlgTest " + ALGTEST_JCLIENT_VERSION + " - comprehensive tool for JavaCard smart card testing."); | ||
m_SystemOutLogger.println("Visit jcalgtest.org for results from 100+ cards. CRoCS lab 2007-2021."); | ||
m_SystemOutLogger.println("Visit jcalgtest.org for results from 100+ cards. CRoCS lab 2007-2024."); | ||
m_SystemOutLogger.println("Please check if you use the latest version at\n https://github.com/crocs-muni/JCAlgTest/releases/latest."); | ||
m_SystemOutLogger.println("Type 'java -jar jcalgtestclient --help' to display help and available commands."); | ||
m_SystemOutLogger.println("-----------------------------------------------------------------------\n"); | ||
|
||
CardTerminal selectedTerminal = null; | ||
PerformanceTesting testingPerformance = new PerformanceTesting(m_SystemOutLogger); | ||
m_SystemOutLogger.println("NOTE: JCAlgTest applet (AlgTest.cap) must be already installed on tested card."); | ||
m_SystemOutLogger.println(" java -jar gp.jar --install AlgTest_***_jc***.cap"); | ||
m_SystemOutLogger.println("The results are stored in CSV files. Use JCAlgProcess for HTML conversion."); | ||
m_SystemOutLogger.println(); | ||
|
||
if (cmdArgs.help) { | ||
JCommander.newBuilder().addObject(cmdArgs).build().usage(); | ||
JCommander.newBuilder().addObject(cmdArgs).build().usage(); | ||
return; | ||
} | ||
|
||
if (args.length > 0) { | ||
m_SystemOutLogger.println("Running in non-interactive mode. Run without any parameter to enter interactive mode. Run 'java -jar AlgTestJClient.jar -help' to obtain list of supported arguments."); | ||
|
||
// If selftest is enabled, then prepare testing session with simulator, execute and check for results | ||
if (cmdArgs.selftest) { | ||
cmdArgs.simulator = true; | ||
cmdArgs.fresh = true; | ||
cmdArgs.cardName = Args.SELFTEST_CARD_NAME; | ||
cmdArgs.operations.clear(); | ||
cmdArgs.operations.add(Args.OP_ALG_SUPPORT_EXTENDED); | ||
cmdArgs.operations.add(Args.OP_ALG_ECC_PERFORMANCE); | ||
cmdArgs.operations.add(Args.OP_ALG_FINGERPRINT); | ||
cmdArgs.operations.add(Args.OP_ALG_PERFORMANCE_STATIC); | ||
cmdArgs.operations.add(Args.OP_ALG_PERFORMANCE_VARIABLE); | ||
} | ||
|
||
printSendRequest(); | ||
if (cmdArgs.operations.size() > 0) { | ||
m_SystemOutLogger.println("Running in non-interactive mode. Run without any parameter to enter interactive mode. Run 'java -jar AlgTestJClient.jar --help' to obtain list of supported arguments."); | ||
for (String operation : cmdArgs.operations) { | ||
if (operation.compareTo(Args.OP_ALG_SUPPORT_BASIC) == 0 || | ||
operation.compareTo(Args.OP_ALG_SUPPORT_EXTENDED) == 0) { | ||
selectedTerminal = selectTargetReader(cmdArgs); | ||
if (selectedTerminal != null) { | ||
SingleModeTest singleTest = new SingleModeTest(m_SystemOutLogger); | ||
singleTest.TestSingleAlg(operation, cmdArgs, selectedTerminal); | ||
Map<String, String> testResults = singleTest.TestSingleAlg(operation, cmdArgs, selectedTerminal); | ||
allResultsMap.put(operation, testResults); | ||
} | ||
} | ||
else if (operation.compareTo(Args.OP_ALG_PERFORMANCE_STATIC) == 0 || | ||
operation.compareTo(Args.OP_ALG_PERFORMANCE_VARIABLE) == 0) { | ||
selectedTerminal = selectTargetReader(cmdArgs); | ||
if (selectedTerminal != null) { | ||
testingPerformance.testPerformance(false, operation, selectedTerminal, cmdArgs); | ||
Map<String, String> testResults = testingPerformance.testPerformance(false, operation, selectedTerminal, cmdArgs); | ||
allResultsMap.put(operation, testResults); | ||
} | ||
} | ||
else if (operation.compareTo(Args.OP_ALG_ECC_PERFORMANCE) == 0) { | ||
selectedTerminal = selectTargetReader(cmdArgs); | ||
if (selectedTerminal != null) { | ||
Map<String, String> testResults = testingPerformance.testECCPerformance(args, true, selectedTerminal, cmdArgs); | ||
allResultsMap.put(operation, testResults); | ||
} | ||
} | ||
else if (operation.compareTo(Args.OP_ALG_FINGERPRINT) == 0) { | ||
selectedTerminal = selectTargetReader(cmdArgs); | ||
if (selectedTerminal != null) { | ||
Map<String, String> testResults = testingPerformance.testPerformanceFingerprint(args, selectedTerminal, cmdArgs); | ||
allResultsMap.put(operation, testResults); | ||
} | ||
} | ||
else { | ||
|
@@ -241,7 +298,7 @@ else if (operation.compareTo(Args.OP_ALG_PERFORMANCE_STATIC) == 0 || | |
} | ||
else { | ||
// Interactive mode of tool | ||
m_SystemOutLogger.println("Running in interactive mode. Run 'java -jar AlgTestJClient.jar -help' to obtain list of supported arguments."); | ||
m_SystemOutLogger.println("Running in interactive mode. Run 'java -jar AlgTestJClient.jar --help' to obtain list of supported arguments."); | ||
m_SystemOutLogger.println("CHOOSE test you want to run:"); | ||
m_SystemOutLogger.println("1 -> SUPPORTED ALGORITHMS\n List all supported JC API algorithms (2-10 minutes)\n" + | ||
"2 -> PERFORMANCE TEST\n Test all JC API methods with 256B data length (1-3 hours)\n" + | ||
|
@@ -297,6 +354,10 @@ else if (operation.compareTo(Args.OP_ALG_PERFORMANCE_STATIC) == 0 || | |
} | ||
} | ||
printSendRequest(); | ||
|
||
if (cmdArgs.selftest) { | ||
checkSelfTestResults(allResultsMap); | ||
} | ||
} | ||
|
||
static long getStartTime() { | ||
|
@@ -312,8 +373,9 @@ static void printSendRequest() { | |
System.out.println("available to all JavaCard enthusiasts at http://jcalgtest.org."); | ||
System.out.println("The results are important even if a card of same type is already in database."); | ||
System.out.println("Send *.log and *.csv files from the current directory to <[email protected]>."); | ||
System.out.println("Thank you very much!"); | ||
System.out.println("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"); | ||
System.out.println("ESPECIALLY if testing fails, please let us know so we can fix it for you and others."); | ||
System.out.println("Thank you very much."); | ||
System.out.println("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n"); | ||
} | ||
|
||
static void performKeyHarvest(Args cmdArgs) throws CardException { | ||
|
@@ -444,8 +506,10 @@ static CardTerminal selectTargetReader(Args cmdArgs) { | |
m_SystemOutLogger.println("\nAvailable readers:"); | ||
for (CardTerminal terminal : terminalList) { | ||
Card card; | ||
String protocol = System.getenv().getOrDefault("ALGTEST_PROTO", "*"); | ||
try { | ||
card = terminal.connect("*"); | ||
card = terminal.connect(protocol); | ||
//card = terminal.connect("*"); | ||
ATR atr = card.getATR(); | ||
m_SystemOutLogger.println(String.format("%d : [*] %s - %s", terminalIndex, terminal.getName(), CardMngr.bytesToHex(atr.getBytes()))); | ||
terminalIndex++; | ||
|
@@ -470,4 +534,73 @@ static CardTerminal selectTargetReader(Args cmdArgs) { | |
} | ||
} | ||
|
||
private static boolean checkFileExistence(String fileName) { | ||
File file = new File(fileName); | ||
if (file.exists()) { | ||
m_SystemOutLogger.println(String.format(" OK: the file '%s' exists.", fileName)); | ||
} else { | ||
m_SystemOutLogger.println(String.format(" ERROR: the file '%s' does not exist.", fileName)); | ||
} | ||
return file.exists(); | ||
} | ||
|
||
private static boolean checkExpectedValue(Map<String, Map<String, String>> allResults, String op, String key, String expectedValue) { | ||
if (allResults.get(op).get(key).equalsIgnoreCase(expectedValue)){ | ||
m_SystemOutLogger.println(String.format(" OK: %s->%s = %s matches.", op, key, expectedValue)); | ||
} else { | ||
m_SystemOutLogger.println(String.format(" ERROR: %s->%s = %s mismatch (expected=%s).", op, key, allResults.get(op).get(key), expectedValue)); | ||
} | ||
return allResults.get(op).get(key).equalsIgnoreCase(expectedValue); | ||
} | ||
|
||
public static boolean checkSelfTestResults(Map<String, Map<String, String>> allResults) { | ||
boolean bSelftestSuccess = true; | ||
// Print all collected info keys | ||
m_SystemOutLogger.println("###### SELFTEST ####################################"); | ||
m_SystemOutLogger.println("All collected selftest results:"); | ||
for (String operation : allResults.keySet()) { | ||
m_SystemOutLogger.println(String.format(" %s:", operation)); | ||
Map<String, String> oneOpResults = allResults.get(operation); | ||
for (String key : oneOpResults.keySet()) { | ||
m_SystemOutLogger.println(String.format(" %s = %s", key, oneOpResults.get(key))); | ||
} | ||
} | ||
|
||
// Check existence of output files for separate operations | ||
m_SystemOutLogger.println("\nSelftest tests finished, now checking results..."); | ||
for (String op : allResults.keySet()) { | ||
m_SystemOutLogger.println(String.format(" Checking operation '%s':", op)); | ||
// Always check existence of output file | ||
if (!checkFileExistence(allResults.get(op).get("out_file_name"))) { bSelftestSuccess = false; } | ||
// Check selected values for selected results | ||
if (op.equals(Args.OP_ALG_PERFORMANCE_STATIC)) { | ||
if (!checkExpectedValue(allResults, op, "NO_SUCH_ALGORITHM", "290")) { bSelftestSuccess = false; } | ||
if (!checkExpectedValue(allResults, op, "CANT_BE_MEASURED", "204")) { bSelftestSuccess = false; } | ||
if (!checkExpectedValue(allResults, op, "ILLEGAL_VALUE", "66")) { bSelftestSuccess = false; } | ||
if (!checkExpectedValue(allResults, op, "errors_observed", "560")) { bSelftestSuccess = false; } | ||
} | ||
if (op.equals(Args.OP_ALG_PERFORMANCE_VARIABLE)) { | ||
if (!checkExpectedValue(allResults, op, "NO_SUCH_ALGORITHM", "145")) { bSelftestSuccess = false; } | ||
if (!checkExpectedValue(allResults, op, "CANT_BE_MEASURED", "327")) { bSelftestSuccess = false; } | ||
if (!checkExpectedValue(allResults, op, "ILLEGAL_VALUE", "35")) { bSelftestSuccess = false; } | ||
if (!checkExpectedValue(allResults, op, "errors_observed", "507")) { bSelftestSuccess = false; } | ||
} | ||
if (op.equals(Args.OP_ALG_FINGERPRINT)) { | ||
if (!checkExpectedValue(allResults, op, "NO_SUCH_ALGORITHM", "1")) { bSelftestSuccess = false; } | ||
if (!checkExpectedValue(allResults, op, "CANT_BE_MEASURED", "18")) { bSelftestSuccess = false; } | ||
if (!checkExpectedValue(allResults, op, "ILLEGAL_VALUE", "8")) { bSelftestSuccess = false; } | ||
if (!checkExpectedValue(allResults, op, "errors_observed", "27")) { bSelftestSuccess = false; } | ||
} | ||
if (op.equals(Args.OP_ALG_ECC_PERFORMANCE)) { | ||
if (!checkExpectedValue(allResults, op, "errors_observed", "0")) { bSelftestSuccess = false; } | ||
} | ||
} | ||
if (!bSelftestSuccess) { | ||
m_SystemOutLogger.println("ERROR: some test(s) failed"); | ||
} | ||
m_SystemOutLogger.println("###### END SELFTEST ####################################"); | ||
|
||
return bSelftestSuccess; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.