aboutsummaryrefslogtreecommitdiff
path: root/reader
diff options
context:
space:
mode:
authorJán Jančár2024-08-09 20:33:18 +0200
committerGitHub2024-08-09 20:33:18 +0200
commita5a6ef2b5776573d5bd55d6c75f806d752b957c5 (patch)
treede46d4ccd6baea24133b5d39c218158079a40d70 /reader
parent91b425798be6cbc918a9b892d7e76eababc08d6b (diff)
parent65ddb496e2090581e40bce003f6c14490e6cf5fb (diff)
downloadECTester-a5a6ef2b5776573d5bd55d6c75f806d752b957c5.tar.gz
ECTester-a5a6ef2b5776573d5bd55d6c75f806d752b957c5.tar.zst
ECTester-a5a6ef2b5776573d5bd55d6c75f806d752b957c5.zip
Merge branch 'master' into build-with-nix
Diffstat (limited to 'reader')
-rw-r--r--reader/build.gradle.kts10
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/ECTesterReader.java62
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/command/Command.java1
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/output/TextTestWriter.java3
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/CardCofactorSuite.java11
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/CardCompositeSuite.java27
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/CardCompressionSuite.java66
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/CardDefaultSuite.java121
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/CardDegenerateSuite.java12
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java22
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/CardInvalidSuite.java10
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/CardMiscSuite.java34
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/CardSignatureSuite.java2
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/CardTestSuite.java74
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/CardTestVectorSuite.java17
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/CardTwistSuite.java10
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/CardWrongSuite.java41
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/CommandTestable.java20
-rw-r--r--reader/src/main/java/cz/crcs/ectester/reader/test/PerformanceTest.java22
-rw-r--r--reader/src/test/java/cz/crcs/ectester/reader/AppTests.java141
-rw-r--r--reader/src/test/java/cz/crcs/ectester/reader/OutputTests.java13
-rw-r--r--reader/src/test/java/cz/crcs/ectester/reader/XFail.java86
-rw-r--r--reader/src/test/java/cz/crcs/ectester/reader/XFaillExtension.java86
23 files changed, 602 insertions, 289 deletions
diff --git a/reader/build.gradle.kts b/reader/build.gradle.kts
index 0386ea5..1abecdc 100644
--- a/reader/build.gradle.kts
+++ b/reader/build.gradle.kts
@@ -1,6 +1,7 @@
plugins {
application
jacoco
+ id("jacoco-report-aggregation")
id("com.adarshr.test-logger") version "4.0.0"
}
@@ -35,18 +36,21 @@ application {
tasks.named<Test>("test") {
useJUnitPlatform()
// Report is always generated after tests run
- finalizedBy(tasks.jacocoTestReport)
+ finalizedBy(tasks.named<JacocoReport>("testCodeCoverageReport"))
}
-tasks.jacocoTestReport {
+tasks.named<JacocoReport>("testCodeCoverageReport") {
reports {
+ html.required = true
+ html.outputLocation.set(layout.buildDirectory.dir("reports/jacoco/test/html"))
xml.required = true
+ xml.outputLocation.set(layout.buildDirectory.file("reports/jacoco/test/jacocoTestReport.xml"))
}
}
testlogger {
theme = com.adarshr.gradle.testlogger.theme.ThemeType.MOCHA
- showStandardStreams = true
+ showStandardStreams = false
}
tasks.register<Jar>("uberJar") {
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/ECTesterReader.java b/reader/src/main/java/cz/crcs/ectester/reader/ECTesterReader.java
index 91f4653..6f624a0 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/ECTesterReader.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/ECTesterReader.java
@@ -69,7 +69,7 @@ public class ECTesterReader {
public static final String VERSION = "v0.3.3";
public static String GIT_COMMIT = "";
private static String DESCRIPTION;
- private static String LICENSE = "MIT Licensed\nCopyright © 2016-2019 Petr Svenda <petr@svenda.com>\nCopyright © 2016-2019 Jan Jancar <johny@neuromancer.sk>";
+ private static String LICENSE = "MIT Licensed\nCopyright © 2016-2024 Petr Svenda <petr@svenda.com>\nCopyright © 2016-2024 Jan Jancar <johny@neuromancer.sk>";
private static String CLI_HEADER;
private static String CLI_FOOTER = "\n" + LICENSE;
@@ -86,13 +86,15 @@ public class ECTesterReader {
ClassLoader cl = ECTesterReader.class.getClassLoader();
try {
URL url = cl.getResource("META-INF/MANIFEST.MF");
- Manifest manifest = new Manifest(url.openStream());
- String commit = manifest.getMainAttributes().getValue("Git-Commit");
- GIT_COMMIT = (commit == null) ? "" : "(git " + commit + ")";
+ if (url != null) {
+ Manifest manifest = new Manifest(url.openStream());
+ String commit = manifest.getMainAttributes().getValue("Git-Commit");
+ GIT_COMMIT = (commit == null) ? "" : "(git " + commit + ")";
+ }
} catch (Exception ignored) {
}
- DESCRIPTION = "ECTesterReader " + VERSION + GIT_COMMIT + ", a javacard Elliptic Curve Cryptography support tester/utility.";
+ DESCRIPTION = "ECTesterReader " + VERSION + GIT_COMMIT + ", a JavaCard Elliptic Curve Cryptography tester/utility.";
CLI_HEADER = "\n" + DESCRIPTION + "\n\n";
}
@@ -338,10 +340,11 @@ public class ECTesterReader {
opts.addOption(Option.builder("f").longOpt("fresh").desc("Generate fresh keys (set domain parameters before every generation).").build());
opts.addOption(Option.builder().longOpt("time").desc("Output better timing values, by running command in dry run mode and normal mode, and subtracting the two.").build());
opts.addOption(Option.builder().longOpt("time-unit").desc("Use given time unit in measurement, one of: milli, micro, nano.").hasArg().argName("unit").build());
- opts.addOption(Option.builder().longOpt("cleanup").desc("Send the cleanup command trigerring JCSystem.requestObjectDeletion() after some operations.").build());
+ opts.addOption(Option.builder().longOpt("cleanup").desc("Send the cleanup command triggering JCSystem.requestObjectDeletion() after some operations.").build());
opts.addOption(Option.builder("s").longOpt("simulate").desc("Simulate a card with jcardsim instead of using a terminal.").build());
opts.addOption(Option.builder("y").longOpt("yes").desc("Accept all warnings and prompts.").build());
- opts.addOption(Option.builder("to").longOpt("test-options").desc("Test options to use:\n- preset: Use preset semi-random private keys (derived from curve) instead of generating keypairs on the cards when the test needs one.\n- random: Use fully random private keys instead of generating keypairs.").hasArg().argName("options").build());
+ opts.addOption(Option.builder("tk").longOpt("test-key").desc("Key setup technique to use in test suites:\n- generate (default): Generate keypairs on the card.\n- deterministic: Prepare keypairs deterministically off-card.\n- random: Prepare keypairs randomly off-card.").hasArg().argName("option").build());
+ opts.addOption(Option.builder("td").longOpt("test-data").desc("Data setup technique to use in test suites:\n- random (default): Prepare data randomly off-card.\n- deterministic: Prepare data deterministically off-card.").hasArg().argName("option").build());
opts.addOption(Option.builder("ka").longOpt("ka-type").desc("Set KeyAgreement object [type], corresponds to JC.KeyAgreement constants.").hasArg().argName("type").optionalArg(true).build());
opts.addOption(Option.builder("sig").longOpt("sig-type").desc("Set Signature object [type], corresponds to JC.Signature constants.").hasArg().argName("type").optionalArg(true).build());
@@ -370,9 +373,6 @@ public class ECTesterReader {
for (String line : suite.getDescription()) {
System.out.println("\t" + line);
}
- if (suite.getOptions() != null) {
- System.out.println("\t" + Colors.underline("Options:") + " " + Arrays.toString(suite.getOptions()));
- }
}
System.out.println();
System.out.println("For more information, look at the documentation at https://github.com/crocs-muni/ECTester.");
@@ -380,13 +380,13 @@ public class ECTesterReader {
private void info() throws CardException {
Response.GetInfo info = new Command.GetInfo(cardManager).send();
- System.out.println(String.format("Card ATR:\t\t\t\t%s", ByteUtil.bytesToHex(cardManager.getATR().getBytes(), false)));
- System.out.println(String.format("Card protocol:\t\t\t\t%s", cardManager.getProtocol()));
- System.out.println(String.format("ECTester applet version:\t\t%s", info.getVersion()));
- System.out.println(String.format("ECTester applet APDU support:\t\t%s", (info.getBase() == CardConsts.BASE_221) ? "basic" : "extended length"));
- System.out.println(String.format("JavaCard API version:\t\t\t%.1f", info.getJavaCardVersion()));
- System.out.println(String.format("JavaCard supports system cleanup:\t%s", info.getCleanupSupport()));
- System.out.println(String.format("Array sizes (apduBuf,ram,ram2,apduArr):\t%d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength()));
+ System.out.printf("Card ATR:\t\t\t\t%s%n", ByteUtil.bytesToHex(cardManager.getATR().getBytes(), false));
+ System.out.printf("Card protocol:\t\t\t\t%s%n", cardManager.getProtocol());
+ System.out.printf("ECTester applet version:\t\t%s%n", info.getVersion());
+ System.out.printf("ECTester applet APDU support:\t\t%s%n", (info.getBase() == CardConsts.BASE_221) ? "basic" : "extended length");
+ System.out.printf("JavaCard API version:\t\t\t%.1f%n", info.getJavaCardVersion());
+ System.out.printf("JavaCard supports system cleanup:\t%s%n", info.getCleanupSupport());
+ System.out.printf("Array sizes (apduBuf,ram,ram2,apduArr):\t%d %d %d %d%n", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength());
}
/**
@@ -866,7 +866,8 @@ public class ECTesterReader {
public byte ECKAType = EC_Consts.KeyAgreement_ALG_EC_SVDP_DH;
public int ECDSACount;
public byte ECDSAType = EC_Consts.Signature_ALG_ECDSA_SHA;
- public Set<String> testOptions;
+ public String testKeySetup;
+ public String testDataSetup;
/**
* Reads and validates options, also sets defaults.
@@ -1044,25 +1045,20 @@ public class ECTesterReader {
testSuite = selected;
}
- String[] opts = cli.getOptionValue("test-options", "").split(",");
- List<String> validOpts = Arrays.asList("preset", "random");
- testOptions = new HashSet<>();
- for (String opt : opts) {
- if (opt.equals("")) {
- continue;
- }
- if (!validOpts.contains(opt)) {
- System.err.println(Colors.error("Unknown test option " + opt + ". Should be one of: " + Arrays.toString(validOpts.toArray())));
- return false;
- } else {
- testOptions.add(opt);
- }
+ testKeySetup = cli.getOptionValue("test-key", "generate");
+ List<String> testKeyOpts = Arrays.asList("generate", "deterministic", "random");
+ if (!testKeyOpts.contains(testKeySetup)) {
+ System.err.println(Colors.error("Unknown test option " + testKeySetup + ". Should be one of: " + Arrays.toString(testKeyOpts.toArray())));
+ return false;
}
- if (testOptions.contains("preset") && testOptions.contains("random")) {
- System.err.println("Cannot have both preset and random option enabled.");
+ testDataSetup = cli.getOptionValue("test-data", "random");
+ List<String> testDataOpts = Arrays.asList("deterministic", "random");
+ if (!testDataOpts.contains(testDataSetup)) {
+ System.err.println(Colors.error("Unknown test option " + testDataSetup + ". Should be one of: " + Arrays.toString(testDataOpts.toArray())));
return false;
}
+
} else if (cli.hasOption("ecdh")) {
if (primeField == binaryField) {
System.err.print(Colors.error("Need to specify field with -fp or -f2m. (not both)"));
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/command/Command.java b/reader/src/main/java/cz/crcs/ectester/reader/command/Command.java
index 892a481..2bd4c77 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/command/Command.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/command/Command.java
@@ -19,6 +19,7 @@ import javax.smartcardio.ResponseAPDU;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/output/TextTestWriter.java b/reader/src/main/java/cz/crcs/ectester/reader/output/TextTestWriter.java
index 532ace5..3ba5431 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/output/TextTestWriter.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/output/TextTestWriter.java
@@ -52,7 +52,8 @@ public class TextTestWriter extends BaseTextTestWriter {
sb.append("═══ ").append(Colors.underline("Card ATR:")).append(" ").append(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)).append(System.lineSeparator());
sb.append("═══ ").append(Colors.underline("JavaCard version:")).append(" ").append(info.getJavaCardVersion()).append(System.lineSeparator());
sb.append("═══ ").append(Colors.underline("Array sizes (apduBuf, ram, ram2, apduArr):")).append(" ").append(String.format("%d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength())).append(System.lineSeparator());
- sb.append("═══ ").append(Colors.underline("Test options:")).append(" ").append(String.join(",", cardSuite.getCfg().testOptions)).append(System.lineSeparator());
+ sb.append("═══ ").append(Colors.underline("Test key setup:")).append(" ").append(cardSuite.getCfg().testKeySetup).append(System.lineSeparator());
+ sb.append("═══ ").append(Colors.underline("Test data setup:")).append(" ").append(cardSuite.getCfg().testDataSetup).append(System.lineSeparator());
CardMngr.CPLC cplc = cardSuite.getCard().getCPLC();
if (!cplc.values().isEmpty()) {
sb.append("═══ ").append(Colors.underline("Card CPLC data:")).append(System.lineSeparator());
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CardCofactorSuite.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CardCofactorSuite.java
index 01e9d02..b0ad2d3 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/CardCofactorSuite.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CardCofactorSuite.java
@@ -5,7 +5,6 @@ import cz.crcs.ectester.common.ec.EC_Key;
import cz.crcs.ectester.common.ec.EC_Consts;
import cz.crcs.ectester.common.output.TestWriter;
import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Result;
import cz.crcs.ectester.common.test.Test;
import cz.crcs.ectester.common.util.CardUtil;
import cz.crcs.ectester.common.util.CardConsts;
@@ -25,7 +24,7 @@ import static cz.crcs.ectester.common.test.Result.ExpectedValue;
*/
public class CardCofactorSuite extends CardTestSuite {
public CardCofactorSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "cofactor", new String[]{"preset", "random"}, "The cofactor test suite tests whether the card correctly rejects points on the curve",
+ super(writer, cfg, cardManager, "cofactor", "The cofactor test suite tests whether the card correctly rejects points on the curve",
"but not in the subgroup generated by the generator(so of small order, dividing the cofactor) during ECDH.");
}
@@ -45,12 +44,12 @@ public class CardCofactorSuite extends CardTestSuite {
List<Test> ecdhTests = new LinkedList<>();
for (EC_Key.Public pub : keys) {
- Test setPub = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten()), Result.ExpectedValue.FAILURE);
- Test ecdh = CommandTest.expect(new Command.ECDH(this.card, CardConsts.KEYPAIR_REMOTE, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE);
- Test objectEcdh = CompoundTest.any(Result.ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with cofactor pubkey.", setPub, ecdh);
+ Test setPub = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten()), ExpectedValue.FAILURE);
+ Test ecdh = CommandTest.expect(new Command.ECDH(this.card, CardConsts.KEYPAIR_REMOTE, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), ExpectedValue.FAILURE);
+ Test objectEcdh = CompoundTest.any(ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with cofactor pubkey.", setPub, ecdh);
Command ecdhCommand = new Command.ECDH_direct(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
Test rawEcdh = CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on non-generator subgroup.", "Card incorrectly accepted point on non-generator subgroup.");
- ecdhTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " cofactor key test.", objectEcdh, rawEcdh));
+ ecdhTests.add(CompoundTest.all(ExpectedValue.SUCCESS, pub.getId() + " cofactor key test.", objectEcdh, rawEcdh));
}
Test ecdh = CompoundTest.all(ExpectedValue.SUCCESS, "Perform ECDH with public points on non-generator subgroup.", ecdhTests.toArray(new Test[0]));
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CardCompositeSuite.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CardCompositeSuite.java
index a28c2a7..71890e1 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/CardCompositeSuite.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CardCompositeSuite.java
@@ -6,7 +6,6 @@ import cz.crcs.ectester.common.ec.EC_Consts;
import cz.crcs.ectester.common.output.TestWriter;
import cz.crcs.ectester.common.test.CompoundTest;
import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.common.util.CardUtil;
import cz.crcs.ectester.common.util.CardConsts;
import cz.crcs.ectester.data.EC_Store;
import cz.crcs.ectester.reader.CardMngr;
@@ -25,7 +24,7 @@ import static cz.crcs.ectester.common.test.Result.ExpectedValue;
public class CardCompositeSuite extends CardTestSuite {
public CardCompositeSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "composite", new String[]{"preset", "random"}, "The composite suite runs ECDH over curves with composite order.",
+ super(writer, cfg, cardManager, "composite", "The composite suite runs ECDH over curves with composite order.",
"Various types of compositeness is tested: smooth numbers, Carmichael pseudo-prime, prime square, product of two large primes.");
}
@@ -36,27 +35,19 @@ public class CardCompositeSuite extends CardTestSuite {
for (Map.Entry<EC_Curve, List<EC_Key>> curveKeys : mappedKeys.entrySet()) {
EC_Curve curve = curveKeys.getKey();
List<Test> tests = new LinkedList<>();
- Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_LOCAL, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- if (!allocate.ok()) {
- doTest(CompoundTest.all(ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocate));
- continue;
- }
- tests.add(allocate);
- tests.add(CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_LOCAL, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY));
+ Test allocate = CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_LOCAL, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS);
+ Test set = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_LOCAL, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY);
+
+ Test setKeypair = setupKeypairs(curve, ExpectedValue.ANY, CardConsts.KEYPAIR_LOCAL);
+ Test prepare = CompoundTest.all(ExpectedValue.SUCCESS, "Prepare keypair on " + curve.getId() + ".", allocate, set, setKeypair);
- String name;
- if (cfg.testOptions.contains("preset")) {
- name = "preset semi-random private key";
- } else {
- name = "generated private key";
- }
- tests.add(setupKeypairs(curve, ExpectedValue.ANY, CardConsts.KEYPAIR_LOCAL));
for (EC_Key key : curveKeys.getValue()) {
Command ecdhCommand = new Command.ECDH_direct(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, key.flatten());
Test ecdh = CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a composite order curve.", "Card incorrectly does ECDH over a composite order curve, leaks bits of private key.");
- tests.add(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ", with " + name + ", " + key.getDesc(), ecdh));
+ tests.add(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ", with " + key.getDesc(), ecdh));
}
- doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ".", tests.toArray(new Test[0])));
+ Test ecdhTest = CompoundTest.all(ExpectedValue.SUCCESS, "Do ECDH.", tests.toArray(new Test[0]));
+ doTest(CompoundTest.greedyAll(ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ".", prepare, ecdhTest));
}
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CardCompressionSuite.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CardCompressionSuite.java
index 8390cd3..3598224 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/CardCompressionSuite.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CardCompressionSuite.java
@@ -15,7 +15,6 @@ import cz.crcs.ectester.data.EC_Store;
import cz.crcs.ectester.reader.CardMngr;
import cz.crcs.ectester.reader.ECTesterReader;
import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.response.Response;
import java.security.spec.ECPoint;
import java.util.LinkedList;
@@ -70,56 +69,40 @@ public class CardCompressionSuite extends CardTestSuite {
String spec = keyLength + "b " + CardUtil.getKeyTypeString(field);
byte curveId = EC_Consts.getCurve(keyLength, field);
- Test allocateFirst = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, keyLength, field), Result.ExpectedValue.SUCCESS));
- if (!allocateFirst.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for compression test on " + spec + ".", allocateFirst));
- continue;
- }
-
List<Test> compressionTests = new LinkedList<>();
+ Test allocateFirst = CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, keyLength, field), Result.ExpectedValue.SUCCESS);
+ Test setCustom = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, curveId, domain, null), Result.ExpectedValue.SUCCESS);
+ Test genCustom = CommandTest.expect(new Command.Generate(this.card, CardConsts.KEYPAIR_BOTH), Result.ExpectedValue.SUCCESS);
compressionTests.add(allocateFirst);
- Test setCustom = runTest(CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, curveId, domain, null), Result.ExpectedValue.SUCCESS));
- Test genCustom = runTest(CommandTest.expect(new Command.Generate(this.card, CardConsts.KEYPAIR_BOTH), Result.ExpectedValue.SUCCESS));
compressionTests.add(setCustom);
compressionTests.add(genCustom);
- Response.Export key = new Command.Export(this.card, CardConsts.KEYPAIR_REMOTE, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W).send();
- byte[] pubkey = key.getParameter(CardConsts.KEYPAIR_REMOTE, EC_Consts.KEY_PUBLIC);
EC_Curve secgCurve = EC_Store.getInstance().getObject(EC_Curve.class, "secg", CardUtil.getCurveName(curveId));
- ECPoint pub;
- try {
- pub = ECUtil.fromX962(pubkey, secgCurve.toCurve());
- } catch (IllegalArgumentException iae) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "", compressionTests.toArray(new Test[0])));
- continue;
- }
+ ECPoint pub = ECUtil.toPoint(preparePubkey(secgCurve));
List<Test> kaTests = new LinkedList<>();
for (byte kaType : EC_Consts.KA_TYPES) {
List<Test> thisTests = new LinkedList<>();
- Test allocate = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), Result.ExpectedValue.SUCCESS));
- if (allocate.ok()) {
- Test ka = runTest(CommandTest.expect(new Command.ECDH(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.KEYPAIR_REMOTE, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType), Result.ExpectedValue.SUCCESS));
+ Test allocate = CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), Result.ExpectedValue.SUCCESS);
+ Test ka = CommandTest.expect(new Command.ECDH(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.KEYPAIR_REMOTE, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType), Result.ExpectedValue.SUCCESS);
- thisTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyAgreement setup and basic test.", allocate, ka));
- if (ka.ok()) {
- // tests of the good stuff
- Test kaCompressed = CommandTest.expect(new Command.ECDH(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.KEYPAIR_REMOTE, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_COMPRESS, kaType), Result.ExpectedValue.SUCCESS);
- Test kaHybrid = CommandTest.expect(new Command.ECDH(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.KEYPAIR_REMOTE, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_COMPRESS_HYBRID, kaType), Result.ExpectedValue.SUCCESS);
- thisTests.add(CompoundTest.any(Result.ExpectedValue.SUCCESS, "Tests of compressed and hybrid form.", kaCompressed, kaHybrid));
+ thisTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyAgreement setup and basic test.", allocate, ka));
+ // tests of the good stuff
+ Test kaCompressed = CommandTest.expect(new Command.ECDH(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.KEYPAIR_REMOTE, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_COMPRESS, kaType), Result.ExpectedValue.SUCCESS);
+ Test kaHybrid = CommandTest.expect(new Command.ECDH(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.KEYPAIR_REMOTE, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_COMPRESS_HYBRID, kaType), Result.ExpectedValue.SUCCESS);
+ thisTests.add(CompoundTest.any(Result.ExpectedValue.SUCCESS, "Tests of compressed and hybrid form.", kaCompressed, kaHybrid));
- // tests the bad stuff here
- byte[] pubHybrid = ECUtil.toX962Hybrid(pub, keyLength);
- pubHybrid[pubHybrid.length - 1] ^= 1;
- byte[] pubHybridEncoded = ByteUtil.prependLength(pubHybrid);
- Test kaBadHybrid = CommandTest.expect(new Command.ECDH_direct(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType, pubHybridEncoded), Result.ExpectedValue.FAILURE);
+ // tests the bad stuff here
+ byte[] pubHybrid = ECUtil.toX962Hybrid(pub, keyLength);
+ pubHybrid[pubHybrid.length - 1] ^= 1;
+ byte[] pubHybridEncoded = ByteUtil.prependLength(pubHybrid);
+ Test kaBadHybrid = CommandTest.expect(new Command.ECDH_direct(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType, pubHybridEncoded), Result.ExpectedValue.FAILURE);
- byte[] pubInfinityEncoded = {0x01, 0x00};
- Test kaBadInfinity = CommandTest.expect(new Command.ECDH_direct(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType, pubInfinityEncoded), Result.ExpectedValue.FAILURE);
- thisTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests of corrupted hybrid form and infinity.", kaBadHybrid, kaBadInfinity));
- }
- kaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyAgreement tests of " + CardUtil.getKATypeString(kaType) + ".", thisTests.toArray(new Test[0])));
- }
+ byte[] pubInfinityEncoded = {0x00};
+ Test kaBadInfinity = CommandTest.expect(new Command.ECDH_direct(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_INFINITY, kaType, pubInfinityEncoded), Result.ExpectedValue.FAILURE);
+ thisTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests of corrupted hybrid form and infinity.", kaBadHybrid, kaBadInfinity));
+
+ kaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyAgreement tests of " + CardUtil.getKATypeString(kaType) + ".", thisTests.toArray(new Test[0])));
}
compressionTests.addAll(kaTests);
if (cfg.cleanup) {
@@ -137,12 +120,7 @@ public class CardCompressionSuite extends CardTestSuite {
for (EC_Key.Public key : compressionKeys) {
EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, key.getCurve());
List<Test> tests = new LinkedList<>();
- Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_LOCAL, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
- if (!allocate.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for non-residue test on " + curve.getBits() + "b " + curve.getId() + ".", allocate));
- continue;
- }
- tests.add(allocate);
+ tests.add(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_LOCAL, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
tests.add(CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_LOCAL, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS));
tests.add(CommandTest.expect(new Command.Generate(this.card, CardConsts.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS));
byte[] pointData = ECUtil.toX962Compressed(key.getParam(EC_Consts.PARAMETER_W));
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CardDefaultSuite.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CardDefaultSuite.java
index ebb1d3f..5ac8f1a 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/CardDefaultSuite.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CardDefaultSuite.java
@@ -13,7 +13,7 @@ import cz.crcs.ectester.reader.command.Command;
import java.util.LinkedList;
import java.util.List;
-import java.util.Random;
+import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -27,7 +27,7 @@ import static cz.crcs.ectester.common.test.Result.Value;
public class CardDefaultSuite extends CardTestSuite {
public CardDefaultSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "default", null, "The default test suite tests basic support and performance of ECDH and ECDSA.");
+ super(writer, cfg, cardManager, "default", "The default test suite tests basic support and performance of ECDH and ECDSA.");
}
@Override
@@ -44,19 +44,13 @@ public class CardDefaultSuite extends CardTestSuite {
short[] keySizes = field == EC_Consts.ALG_EC_FP ? EC_Consts.FP_SIZES : EC_Consts.F2M_SIZES;
short domain = field == EC_Consts.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M;
for (short keyLength : keySizes) {
-
List<Test> supportTests = new LinkedList<>();
- Test allocateFirst = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, keyLength, field), ExpectedValue.SUCCESS));
- if (!allocateFirst.ok()) {
- doTest(CompoundTest.all(ExpectedValue.SUCCESS, "No support for " + keyLength + "b " + CardUtil.getKeyTypeString(field) + ".", allocateFirst));
- continue;
- }
+ Test allocateFirst = CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, keyLength, field), ExpectedValue.SUCCESS);
+ Test genDefault = CommandTest.expect(new Command.Generate(this.card, CardConsts.KEYPAIR_BOTH), ExpectedValue.SUCCESS);
+ Test allocateSecond = CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, keyLength, field), ExpectedValue.SUCCESS);
+ Test setCustom = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.getCurve(keyLength, field), domain, null), ExpectedValue.SUCCESS);
+ Test genCustom = CommandTest.expect(new Command.Generate(this.card, CardConsts.KEYPAIR_BOTH), ExpectedValue.SUCCESS);
supportTests.add(allocateFirst);
-
- Test genDefault = runTest(CommandTest.expect(new Command.Generate(this.card, CardConsts.KEYPAIR_BOTH), ExpectedValue.SUCCESS));
- Test allocateSecond = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, keyLength, field), ExpectedValue.SUCCESS));
- Test setCustom = runTest(CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.getCurve(keyLength, field), domain, null), ExpectedValue.SUCCESS));
- Test genCustom = runTest(CommandTest.expect(new Command.Generate(this.card, CardConsts.KEYPAIR_BOTH), ExpectedValue.SUCCESS));
supportTests.add(genDefault);
supportTests.add(allocateSecond);
supportTests.add(setCustom);
@@ -64,68 +58,77 @@ public class CardDefaultSuite extends CardTestSuite {
List<Test> kaTests = new LinkedList<>();
for (byte kaType : EC_Consts.KA_TYPES) {
- Test allocate = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), ExpectedValue.SUCCESS));
- if (allocate.ok()) {
- Command ecdh = new Command.ECDH(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.KEYPAIR_REMOTE, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType);
- Test ka = runTest(CommandTest.expect(ecdh, ExpectedValue.SUCCESS));
- Test kaCompressed = runTest(CommandTest.expect(new Command.ECDH(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.KEYPAIR_REMOTE, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_COMPRESS, kaType), ExpectedValue.SUCCESS));
+ Test allocate = CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), ExpectedValue.SUCCESS);
+ Command ecdh = new Command.ECDH(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.KEYPAIR_REMOTE, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType);
+ Test ka = CommandTest.expect(ecdh, ExpectedValue.SUCCESS);
+ Test kaCompressed = CommandTest.expect(new Command.ECDH(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.KEYPAIR_REMOTE, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_COMPRESS, kaType), ExpectedValue.SUCCESS);
- String kaDesc = "Test of the " + CardUtil.getKATypeString(kaType) + " KeyAgreement.";
- Function<Test[], Result> kaCallback = (tests) -> {
- if (tests[1].ok() || tests[2].ok()) {
- return new Result(Value.SUCCESS, "Some ECDH is supported.");
+ String kaDesc = "Test of the " + CardUtil.getKATypeString(kaType) + " KeyAgreement.";
+ Function<Test[], Result> kaCallback = (tests) -> {
+ if (tests[1].ok() || tests[2].ok()) {
+ return new Result(Value.SUCCESS, "Some ECDH is supported.");
+ } else {
+ return new Result(Value.FAILURE, "ECDH failed.");
+ }
+ };
+
+ Consumer<Test[]> runCallback = tests -> {
+ for (Test t : tests) {
+ if (t instanceof PerformanceTest) {
+ if (tests[0].ok() && tests[1].ok()) {
+ t.run();
+ }
} else {
- return new Result(Value.FAILURE, "ECDH failed.");
+ t.run();
}
- };
-
- Test compound;
- if (ka.ok()) {
- Test perfTest = runTest(PerformanceTest.repeat(this.card, ecdh, 10));
- compound = runTest(CompoundTest.function(kaCallback, kaDesc, allocate, ka, kaCompressed, perfTest));
- } else {
- compound = runTest(CompoundTest.function(kaCallback, kaDesc, allocate, ka, kaCompressed));
}
+ };
- kaTests.add(compound);
- } else {
- runTest(allocate);
- kaTests.add(allocate);
- }
+ Test perfTest = PerformanceTest.repeat(this.card, ecdh, 10);
+ Test compound = CompoundTest.function(kaCallback, runCallback, kaDesc, allocate, ka, kaCompressed, perfTest);
+ kaTests.add(compound);
}
- Test kaTest = runTest(CompoundTest.any(ExpectedValue.SUCCESS, "KeyAgreement tests.", kaTests.toArray(new Test[0])));
+ Test kaTest = CompoundTest.any(ExpectedValue.SUCCESS, "KeyAgreement tests.", kaTests.toArray(new Test[0]));
supportTests.add(kaTest);
List<Test> signTests = new LinkedList<>();
for (byte sigType : EC_Consts.SIG_TYPES) {
- Test allocate = runTest(CommandTest.expect(new Command.AllocateSignature(this.card, sigType), ExpectedValue.SUCCESS));
- if (allocate.ok()) {
- Command ecdsa = new Command.ECDSA(this.card, CardConsts.KEYPAIR_LOCAL, sigType, CardConsts.EXPORT_FALSE, null);
- Test expect = runTest(CommandTest.expect(ecdsa, ExpectedValue.SUCCESS));
+ Test allocate = CommandTest.expect(new Command.AllocateSignature(this.card, sigType), ExpectedValue.SUCCESS);
+ Command ecdsa = new Command.ECDSA(this.card, CardConsts.KEYPAIR_LOCAL, sigType, CardConsts.EXPORT_FALSE, null);
+ Test sign = CommandTest.expect(ecdsa, ExpectedValue.SUCCESS);
- String signDesc = "Test of the " + CardUtil.getSigTypeString(sigType) + " signature.";
+ String signDesc = "Test of the " + CardUtil.getSigTypeString(sigType) + " signature.";
- Random rand = new Random();
- byte[] sigData = new byte[64];
- rand.nextBytes(sigData);
+ byte[] sigData = new byte[]{(byte) domain, sigType};
- Test compound;
- if (expect.ok()) {
- Command ecdsaSign = new Command.ECDSA_sign(this.card, CardConsts.KEYPAIR_LOCAL, sigType, CardConsts.EXPORT_TRUE, sigData);
- PerformanceTest signTest = runTest(PerformanceTest.repeat(this.card, "Sign", ecdsaSign, 10));
- byte[] signature = signTest.getResponses()[0].getParam(0);
- Command ecdsaVerify = new Command.ECDSA_verify(this.card, CardConsts.KEYPAIR_LOCAL, sigType, sigData, signature);
- PerformanceTest verifyTest = runTest(PerformanceTest.repeat(this.card, "Verify", ecdsaVerify, 10));
- compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, signDesc, allocate, expect, signTest, verifyTest));
+ Function<Test[], Result> sigCallback = (tests) -> {
+ if (tests[1].ok()) {
+ return new Result(Value.SUCCESS, "Some ECDSA is supported.");
} else {
- compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, signDesc, allocate, expect));
+ return new Result(Value.FAILURE, "ECDSA failed.");
+ }
+ };
+ Consumer<Test[]> runCallback = tests -> {
+ for (Test t : tests) {
+ if (t instanceof PerformanceTest) {
+ if (tests[0].ok() && tests[1].ok()) {
+ t.run();
+ }
+ } else {
+ t.run();
+ }
}
- signTests.add(compound);
- } else {
- signTests.add(allocate);
- }
+ };
+
+ Command ecdsaSign = new Command.ECDSA_sign(this.card, CardConsts.KEYPAIR_LOCAL, sigType, CardConsts.EXPORT_TRUE, sigData);
+ PerformanceTest signTest = PerformanceTest.repeat(this.card, "Sign", ecdsaSign, 10);
+
+ CommandTestable.FunctionCommandTestable verifyTestable = new CommandTestable.FunctionCommandTestable(() -> new Command.ECDSA_verify(this.card, CardConsts.KEYPAIR_LOCAL, sigType, sigData, signTest.getResponses()[0].getParam(0)));
+ PerformanceTest verifyTest = PerformanceTest.repeat(this.card, "Verify", verifyTestable, 10);
+ Test compound = CompoundTest.function(sigCallback, runCallback, signDesc, allocate, sign, signTest, verifyTest);
+ signTests.add(compound);
}
- Test signTest = runTest(CompoundTest.any(ExpectedValue.SUCCESS, "Signature tests.", signTests.toArray(new Test[0])));
+ Test signTest = CompoundTest.any(ExpectedValue.SUCCESS, "Signature tests.", signTests.toArray(new Test[0]));
supportTests.add(signTest);
ExpectedValue[] testExpects = {ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS};
List<ExpectedValue> expects = Stream.of(testExpects).collect(Collectors.toList());
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CardDegenerateSuite.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CardDegenerateSuite.java
index e2c07da..6817390 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/CardDegenerateSuite.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CardDegenerateSuite.java
@@ -24,7 +24,7 @@ import java.util.Map;
public class CardDegenerateSuite extends CardTestSuite {
public CardDegenerateSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "degenerate", null, "The degenerate suite tests whether the card rejects points outside of the curve during ECDH.",
+ super(writer, cfg, cardManager, "degenerate", "The degenerate suite tests whether the card rejects points outside of the curve during ECDH.",
"The tested points lie on a part of the plane for which some Edwards, Hessian and Huff form addition formulas degenerate into exponentiation in the base finite field.");
}
@@ -36,13 +36,9 @@ public class CardDegenerateSuite extends CardTestSuite {
EC_Curve curve = e.getKey();
List<EC_Key.Public> keys = e.getValue();
- Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
- if (!allocate.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getId() + ".", allocate));
- continue;
- }
+ Test allocate = CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS);
Test set = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
- Test generate = CommandTest.expect(new Command.Generate(this.card, CardConsts.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS);
+ Test generate = setupKeypairs(curve, Result.ExpectedValue.SUCCESS, CardConsts.KEYPAIR_LOCAL);
Test prepare = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate);
@@ -51,7 +47,7 @@ public class CardDegenerateSuite extends CardTestSuite {
Test setPub = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten()), Result.ExpectedValue.FAILURE);
Test ecdh = CommandTest.expect(new Command.ECDH(this.card, CardConsts.KEYPAIR_REMOTE, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE, "Card correctly rejected point on degenerate curve.", "Card incorrectly accepted point on degenerate curve.");
Test objectEcdh = CompoundTest.any(Result.ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with degenerate pubkey.", setPub, ecdh);
- Command ecdhCommand = new Command.ECDH_direct(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
+ Command ecdhCommand = new Command.ECDH_direct(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
Test rawEcdh = CommandTest.expect(ecdhCommand, Result.ExpectedValue.FAILURE, "Card correctly rejected point on degenerate curve.", "Card incorrectly accepted point on degenerate curve.");
ecdhTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " degenerate key test.", objectEcdh, rawEcdh));
//TODO: actually get the result of ECDH here, as well as export privkey and compare to exponentiation in Fp^*.
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java
index 0a82da3..00bc34e 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java
@@ -26,7 +26,7 @@ import java.util.stream.Collectors;
*/
public class CardEdgeCasesSuite extends CardTestSuite {
public CardEdgeCasesSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "edge-cases", null, "The edge-cases test suite tests various inputs to ECDH which may cause an implementation to achieve a certain edge-case state during it.",
+ super(writer, cfg, cardManager, "edge-cases", "The edge-cases test suite tests various inputs to ECDH which may cause an implementation to achieve a certain edge-case state during it.",
"Some of the data is from the google/Wycheproof project. Tests include CVE-2017-10176 and CVE-2017-8932.",
"Also tests values of the private key and public key that would trigger the OpenSSL modular multiplication bug on the P-256 curve.",
"Various edge private key values are also tested.");
@@ -141,17 +141,14 @@ public class CardEdgeCasesSuite extends CardTestSuite {
List<EC_Curve> curves = curveMap.entrySet().stream().filter((e) -> e.getKey().endsWith("r1") && e.getValue().getField() == EC_Consts.ALG_EC_FP).map(Map.Entry::getValue).collect(Collectors.toList());
curves.add(EC_Store.getInstance().getObject(EC_Curve.class, "cofactor/cofactor128p2"));
curves.add(EC_Store.getInstance().getObject(EC_Curve.class, "cofactor/cofactor160p4"));
- Random rand = new Random();
+
for (EC_Curve curve : curves) {
- Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), EC_Consts.ALG_EC_FP), Result.ExpectedValue.SUCCESS));
- if (!key.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.FAILURE, "No support for " + curve.getBits() + "b " + curve.getId() + ".", key));
- continue;
- }
+ Random rand = setupRandom(curve);
+ Test key = CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), EC_Consts.ALG_EC_FP), Result.ExpectedValue.SUCCESS);
Test set = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
- Test generate = CommandTest.expect(new Command.Generate(this.card, CardConsts.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS);
+ Test generate = setupKeypairs(curve, Result.ExpectedValue.SUCCESS, CardConsts.KEYPAIR_LOCAL);
CommandTest export = CommandTest.expect(new Command.Export(this.card, CardConsts.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W), Result.ExpectedValue.SUCCESS);
- Test setup = runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set, generate, export));
+ Test setup = CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set, generate, export);
/*
byte[] pParam = curve.getParam(EC_Consts.PARAMETER_FP)[0];
@@ -241,6 +238,7 @@ public class CardEdgeCasesSuite extends CardTestSuite {
}
EC_Curve secp160r1 = EC_Store.getInstance().getObject(EC_Curve.class, "secg/secp160r1");
+ Random rand = setupRandom(secp160r1);
byte[] pData = secp160r1.getParam(EC_Consts.PARAMETER_FP)[0];
BigInteger p = new BigInteger(1, pData);
byte[] rData = secp160r1.getParam(EC_Consts.PARAMETER_R)[0];
@@ -268,11 +266,7 @@ public class CardEdgeCasesSuite extends CardTestSuite {
Arrays.sort(ps);
Arrays.sort(zeros);
- Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, secp160r1.getBits(), EC_Consts.ALG_EC_FP), Result.ExpectedValue.SUCCESS));
- if (!key.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.FAILURE, "No support for " + secp160r1.getBits() + "b secp160r1.", key));
- return;
- }
+ Test key = CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, secp160r1.getBits(), EC_Consts.ALG_EC_FP), Result.ExpectedValue.SUCCESS);
Test set = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.CURVE_external, secp160r1.getParams(), secp160r1.flatten()), Result.ExpectedValue.SUCCESS);
Test generate = CommandTest.expect(new Command.Generate(this.card, CardConsts.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS);
Test setup = CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set, generate);
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CardInvalidSuite.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CardInvalidSuite.java
index 4657de0..cacfba9 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/CardInvalidSuite.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CardInvalidSuite.java
@@ -26,7 +26,7 @@ import static cz.crcs.ectester.common.test.Result.ExpectedValue;
public class CardInvalidSuite extends CardTestSuite {
public CardInvalidSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "invalid", null, "The invalid curve suite tests whether the card rejects points outside of the curve during ECDH.");
+ super(writer, cfg, cardManager, "invalid", "The invalid curve suite tests whether the card rejects points outside of the curve during ECDH.");
}
@Override
@@ -40,13 +40,9 @@ public class CardInvalidSuite extends CardTestSuite {
EC_Curve curve = e.getKey();
List<EC_Key.Public> keys = e.getValue();
- Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- if (!allocate.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getId() + ".", allocate));
- continue;
- }
+ Test allocate = CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS);
Test set = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS);
- Test generate = CommandTest.expect(new Command.Generate(this.card, CardConsts.KEYPAIR_LOCAL), ExpectedValue.SUCCESS);
+ Test generate = setupKeypairs(curve, Result.ExpectedValue.SUCCESS, CardConsts.KEYPAIR_LOCAL);
Test prepare = CompoundTest.all(ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate);
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CardMiscSuite.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CardMiscSuite.java
index da4c0b5..38dcf80 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/CardMiscSuite.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CardMiscSuite.java
@@ -16,6 +16,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.function.Function;
/**
* @author Jan Jancar johny@neuromancer.sk
@@ -23,7 +24,7 @@ import java.util.Map;
public class CardMiscSuite extends CardTestSuite {
public CardMiscSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "miscellaneous", new String[]{"preset", "random"}, "Some miscellaneous tests, tries ECDH and ECDSA over supersingular curves, anomalous curves,",
+ super(writer, cfg, cardManager, "miscellaneous", "Some miscellaneous tests, tries ECDH and ECDSA over supersingular curves, anomalous curves,",
"Barreto-Naehrig curves with small embedding degree and CM discriminant, MNT curves,",
"some Montgomery curves transformed to short Weierstrass form and Curve25519 transformed to short Weierstrass form.");
}
@@ -49,23 +50,36 @@ public class CardMiscSuite extends CardTestSuite {
}
private void testCurve(EC_Curve curve, String catName, Result.ExpectedValue expected) {
- Test allocateFirst = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
- if (!allocateFirst.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", allocateFirst));
- return;
- }
-
+ Test allocateFirst = CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS);
Test set = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
- Test generate = setupKeypairs(curve, Result.ExpectedValue.ANY, CardConsts.KEYPAIR_BOTH);
+ Test generate = setupKeypairs(curve, Result.ExpectedValue.SUCCESS, CardConsts.KEYPAIR_BOTH);
Test ka = CommandTest.expect(new Command.ECDH(this.card, CardConsts.KEYPAIR_REMOTE, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), expected);
Test sig = CommandTest.expect(new Command.ECDSA_sign(this.card, CardConsts.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, CardConsts.EXPORT_FALSE, null), expected);
Test perform = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH and ECDSA.", ka, sig);
+ Function<Test[], Result> callback = (tests) -> {
+ if (!tests[0].ok()) {
+ return new Result(Result.Value.FAILURE, "Could not allocate keypairs.");
+ }
+ if (!tests[1].ok()) {
+ return new Result(Result.Value.FAILURE, "Could not set curve data.");
+ }
+ if (!tests[2].ok()) {
+ return new Result(Result.Value.FAILURE, "Could not generate keypairs.");
+ }
+ for (int i = 3; i < tests.length; i++) {
+ if (!tests[i].ok() && !(tests[i] instanceof CompoundTest)) {
+ return new Result(Result.Value.FAILURE, "ECDH or ECDSA did not work.");
+ }
+ }
+ return new Result(Result.Value.SUCCESS, "OK");
+ };
+
if (cfg.cleanup) {
Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY);
- doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform, cleanup));
+ doTest(CompoundTest.function(callback, "Tests over " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform, cleanup));
} else {
- doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform));
+ doTest(CompoundTest.function(callback, "Tests over " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform));
}
}
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CardSignatureSuite.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CardSignatureSuite.java
index 086654a..0bf897a 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/CardSignatureSuite.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CardSignatureSuite.java
@@ -22,7 +22,7 @@ import java.util.Map;
*/
public class CardSignatureSuite extends CardTestSuite {
public CardSignatureSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "signature", null, "The signature test suite tests verifying various malformed and well-formed but invalid ECDSA signatures.");
+ super(writer, cfg, cardManager, "signature", "The signature test suite tests verifying various malformed and well-formed but invalid ECDSA signatures.");
}
@Override
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CardTestSuite.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CardTestSuite.java
index 15c4469..e2d9dd1 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/CardTestSuite.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CardTestSuite.java
@@ -10,11 +10,13 @@ import cz.crcs.ectester.common.test.Test;
import cz.crcs.ectester.common.test.TestSuite;
import cz.crcs.ectester.common.util.CardConsts;
import cz.crcs.ectester.common.util.ECUtil;
+import cz.crcs.ectester.common.util.Util;
import cz.crcs.ectester.reader.CardMngr;
import cz.crcs.ectester.reader.ECTesterReader;
import cz.crcs.ectester.reader.command.Command;
-import java.util.Arrays;
+import java.nio.ByteBuffer;
+import java.security.SecureRandom;
/**
* @author Jan Jancar johny@neuromancer.sk
@@ -22,13 +24,11 @@ import java.util.Arrays;
public abstract class CardTestSuite extends TestSuite {
ECTesterReader.Config cfg;
CardMngr card;
- String[] options;
- CardTestSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager, String name, String[] options, String... description) {
+ CardTestSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager, String name, String... description) {
super(writer, name, description);
this.card = cardManager;
this.cfg = cfg;
- this.options = options;
}
public CardMngr getCard() {
@@ -39,34 +39,16 @@ public abstract class CardTestSuite extends TestSuite {
return cfg;
}
- public String[] getOptions() {
- if (options != null) {
- return options.clone();
- } else {
- return options;
- }
- }
-
- public Test setupKeypairs(EC_Curve curve, Result.ExpectedValue expected, byte keyPair) {
- if ((Arrays.asList(options).contains("preset") && cfg.testOptions.contains("preset")) || (Arrays.asList(options).contains("random") && cfg.testOptions.contains("random"))) {
+ protected Test setupKeypairs(EC_Curve curve, Result.ExpectedValue expected, byte keyPair) {
+ if (cfg.testKeySetup.equals("deterministic") || cfg.testKeySetup.equals("random")) {
Test setLocal = null;
if ((keyPair & CardConsts.KEYPAIR_LOCAL) != 0) {
- EC_Params priv;
- if (cfg.testOptions.contains("preset")) {
- priv = ECUtil.fixedRandomKey(curve);
- } else {
- priv = ECUtil.fullRandomKey(curve);
- }
+ EC_Params priv = preparePrivkey(curve);
setLocal = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_LOCAL, EC_Consts.CURVE_external, priv.getParams(), priv.flatten()), expected);
}
Test setRemote = null;
if ((keyPair & CardConsts.KEYPAIR_REMOTE) != 0) {
- EC_Params pub;
- if (cfg.testOptions.contains("preset")) {
- pub = ECUtil.fixedRandomPoint(curve);
- } else {
- pub = ECUtil.fullRandomPoint(curve);
- }
+ EC_Params pub = preparePubkey(curve);
if (pub == null) {
setRemote = CommandTest.expect(new Command.Generate(this.card, CardConsts.KEYPAIR_REMOTE), expected);
} else {
@@ -80,15 +62,49 @@ public abstract class CardTestSuite extends TestSuite {
return setRemote;
} else {
String desc;
- if (cfg.testOptions.contains("preset")) {
- desc = "Set semi-random parameters.";
+ if (cfg.testKeySetup.equals("deterministic")) {
+ desc = "Set deterministic parameters.";
} else {
desc = "Set fully-random parameters.";
}
- return CompoundTest.all(expected, desc, setLocal, setRemote);
+ return CompoundTest.all(Result.ExpectedValue.SUCCESS, desc, setLocal, setRemote);
}
} else {
return CommandTest.expect(new Command.Generate(this.card, keyPair), expected);
}
}
+
+ protected EC_Params preparePrivkey(EC_Curve curve) {
+ if (cfg.testKeySetup.equals("deterministic")) {
+ return ECUtil.fixedRandomKey(curve);
+ } else {
+ return ECUtil.fullRandomKey(curve);
+ }
+ }
+
+ protected EC_Params preparePubkey(EC_Curve curve) {
+ if (cfg.testKeySetup.equals("deterministic")) {
+ return ECUtil.fixedRandomPoint(curve);
+ } else {
+ return ECUtil.fullRandomPoint(curve);
+ }
+ }
+
+ protected SecureRandom setupRandom(EC_Curve curve) {
+ if (cfg.testDataSetup.equals("random")) {
+ return new SecureRandom();
+ } else {
+ return Util.getRandom(ECUtil.hashCurve(curve));
+ }
+ }
+
+ protected SecureRandom setupRandom(int seed) {
+ if (cfg.testDataSetup.equals("random")) {
+ return new SecureRandom();
+ } else {
+ ByteBuffer b = ByteBuffer.allocate(4);
+ b.putInt(seed);
+ return Util.getRandom(b.array());
+ }
+ }
}
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CardTestVectorSuite.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
index 07b38d0..28c5e12 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
@@ -40,7 +40,7 @@ import static cz.crcs.ectester.common.test.Result.Value;
public class CardTestVectorSuite extends CardTestSuite {
public CardTestVectorSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "test-vectors", null, "The test-vectors suite contains a collection of test vectors which test basic ECDH correctness.");
+ super(writer, cfg, cardManager, "test-vectors", "The test-vectors suite contains a collection of test vectors which test basic ECDH correctness.");
}
@Override
@@ -63,13 +63,7 @@ public class CardTestVectorSuite extends CardTestSuite {
throw new IOException("Test vector keys couldn't be located.");
}
List<Test> testVector = new LinkedList<>();
- Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- if (!allocate.ok()) {
- doTest(CompoundTest.all(ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocate));
- continue;
- }
-
- testVector.add(allocate);
+ testVector.add(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
testVector.add(CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
testVector.add(CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, onekey.flatten(EC_Consts.PARAMETER_S)), ExpectedValue.SUCCESS));
testVector.add(CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W)), ExpectedValue.SUCCESS));
@@ -112,12 +106,7 @@ public class CardTestVectorSuite extends CardTestSuite {
testCurves.addAll(EC_Store.getInstance().getObjects(EC_Curve.class, "brainpool").values().stream().filter((curve) -> curve.getField() == EC_Consts.ALG_EC_FP).collect(Collectors.toList()));
for (EC_Curve curve : testCurves) {
List<Test> testVector = new LinkedList<>();
- Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- if (!allocate.ok()) {
- doTest(CompoundTest.all(ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocate));
- continue;
- }
- testVector.add(allocate);
+ testVector.add(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
testVector.add(CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
testVector.add(CommandTest.expect(new Command.Generate(this.card, CardConsts.KEYPAIR_BOTH), ExpectedValue.SUCCESS));
CommandTest exportLocal = CommandTest.expect(new Command.Export(this.card, CardConsts.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W), ExpectedValue.ANY);
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CardTwistSuite.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CardTwistSuite.java
index 5c35be7..6679f60 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/CardTwistSuite.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CardTwistSuite.java
@@ -23,7 +23,7 @@ import java.util.Map;
*/
public class CardTwistSuite extends CardTestSuite {
public CardTwistSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "twist", null, "The twist test suite tests whether the card correctly rejects points on the quadratic twist of the curve during ECDH.");
+ super(writer, cfg, cardManager, "twist", "The twist test suite tests whether the card correctly rejects points on the quadratic twist of the curve during ECDH.");
}
@Override
@@ -34,13 +34,9 @@ public class CardTwistSuite extends CardTestSuite {
EC_Curve curve = e.getKey();
List<EC_Key.Public> keys = e.getValue();
- Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
- if (!allocate.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getId() + ".", allocate));
- continue;
- }
+ Test allocate = CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS);
Test set = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
- Test generate = CommandTest.expect(new Command.Generate(this.card, CardConsts.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS);
+ Test generate = setupKeypairs(curve, Result.ExpectedValue.SUCCESS, CardConsts.KEYPAIR_LOCAL);
Test prepare = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate);
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CardWrongSuite.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CardWrongSuite.java
index 0b030b8..f24dabd 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/CardWrongSuite.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CardWrongSuite.java
@@ -30,7 +30,7 @@ import static cz.crcs.ectester.common.test.Result.ExpectedValue;
public class CardWrongSuite extends CardTestSuite {
public CardWrongSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "wrong", new String[]{"preset", "random"}, "The wrong curve suite tests whether the card rejects domain parameters which are not curves.");
+ super(writer, cfg, cardManager, "wrong", "The wrong curve suite tests whether the card rejects domain parameters which are not curves.");
}
@Override
@@ -42,24 +42,17 @@ public class CardWrongSuite extends CardTestSuite {
for (Map.Entry<String, EC_Curve> e : curves.entrySet()) {
EC_Curve curve = e.getValue();
List<Test> tests = new LinkedList<>();
- Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- if (!key.ok()) {
- doTest(CompoundTest.all(ExpectedValue.FAILURE, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()), key));
- continue;
- }
- tests.add(key);
- Test set = runTest(CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.FAILURE));
- Test generate = runTest(setupKeypairs(curve, ExpectedValue.SUCCESS, CardConsts.KEYPAIR_BOTH));
- Test setup = runTest(CompoundTest.any(ExpectedValue.SUCCESS, "Set wrong curve and generate keypairs.", set, generate));
+ Test key = CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS);
+ Test set = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.FAILURE);
+ Test generate = setupKeypairs(curve, ExpectedValue.SUCCESS, CardConsts.KEYPAIR_BOTH);
+ Test setup = CompoundTest.any(ExpectedValue.SUCCESS, "Set wrong curve and generate keypairs.", key, set, generate);
tests.add(setup);
for (byte kaType : EC_Consts.KA_TYPES) {
- Test allocate = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), ExpectedValue.SUCCESS));
- if (allocate.ok()) {
- Test ka = runTest(CommandTest.expect(new Command.ECDH(this.card, CardConsts.KEYPAIR_REMOTE, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType), ExpectedValue.FAILURE));
- Test kaTest = runTest(CompoundTest.all(ExpectedValue.SUCCESS, "Allocate and perform KA.", allocate, ka));
- tests.add(kaTest);
- }
+ Test allocate = CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), ExpectedValue.SUCCESS);
+ Test ka = CommandTest.expect(new Command.ECDH(this.card, CardConsts.KEYPAIR_REMOTE, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType), ExpectedValue.FAILURE);
+ Test kaTest = CompoundTest.all(ExpectedValue.SUCCESS, "Allocate and perform KA.", allocate, ka);
+ tests.add(kaTest);
}
doTest(CompoundTest.function((tsts) -> {
for (int i = 0; i < tsts.length; ++i) {
@@ -79,14 +72,10 @@ public class CardWrongSuite extends CardTestSuite {
* - p is a composite q * s with q, s primes
* - TODO: p divides discriminant
*/
- Random r = new Random();
for (short keyLength : EC_Consts.FP_SIZES) {
byte curve = EC_Consts.getCurve(keyLength, EC_Consts.ALG_EC_FP);
- Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, keyLength, EC_Consts.ALG_EC_FP), ExpectedValue.SUCCESS));
- if (!key.ok()) {
- doTest(CompoundTest.all(ExpectedValue.FAILURE, "No support for " + keyLength + "b ALG_EC_FP.", key));
- continue;
- }
+ Random r = setupRandom(curve);
+ Test key = CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, keyLength, EC_Consts.ALG_EC_FP), ExpectedValue.SUCCESS);
Test set = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, curve, EC_Consts.PARAMETERS_DOMAIN_FP, null), ExpectedValue.SUCCESS);
Test setup = CompoundTest.all(ExpectedValue.SUCCESS, "KeyPair setup.", key, set);
@@ -113,7 +102,7 @@ public class CardWrongSuite extends CardTestSuite {
Test randomG = ecdhTest(new Command.Transform(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_G, (short) (EC_Consts.TRANSFORMATION_FULLRANDOM | EC_Consts.TRANSFORMATION_04_MASK)), "Set G = random non-point/point-like.", "ECDH with non-point G.");
Test fullRandomG = ecdhTest(new Command.Transform(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_G, EC_Consts.TRANSFORMATION_FULLRANDOM), "Set G = random data.", "ECDH with G = random data.");
- Test zeroG = ecdhTest(new Command.Transform(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_G, EC_Consts.TRANSFORMATION_INFINITY), "Set G = inifnity.", "ECDH with G = infinity.");
+ Test zeroG = ecdhTest(new Command.Transform(this.card, CardConsts.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_G, EC_Consts.TRANSFORMATION_INFINITY), "Set G = infinity.", "ECDH with G = infinity.");
Test wrongG = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted G parameter.", randomG, fullRandomG, zeroG);
byte[] originalR = EC_Consts.getCurveParameter(curve, EC_Consts.PARAMETER_R);
@@ -162,11 +151,7 @@ public class CardWrongSuite extends CardTestSuite {
*/
for (short keyLength : EC_Consts.F2M_SIZES) {
byte curve = EC_Consts.getCurve(keyLength, EC_Consts.ALG_EC_F2M);
- Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, keyLength, EC_Consts.ALG_EC_F2M), ExpectedValue.SUCCESS));
- if (!key.ok()) {
- doTest(CompoundTest.all(ExpectedValue.FAILURE, "No support for " + keyLength + "b ALG_EC_F2M.", key));
- continue;
- }
+ Test key = CommandTest.expect(new Command.Allocate(this.card, CardConsts.KEYPAIR_BOTH, keyLength, EC_Consts.ALG_EC_F2M), ExpectedValue.SUCCESS);
Test set = CommandTest.expect(new Command.Set(this.card, CardConsts.KEYPAIR_BOTH, curve, EC_Consts.PARAMETERS_DOMAIN_F2M, null), ExpectedValue.SUCCESS);
Test setup = CompoundTest.all(ExpectedValue.SUCCESS, "KeyPair setup.", key, set);
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CommandTestable.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CommandTestable.java
index f670534..7733e11 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/CommandTestable.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CommandTestable.java
@@ -6,13 +6,14 @@ import cz.crcs.ectester.reader.command.Command;
import cz.crcs.ectester.reader.response.Response;
import javax.smartcardio.CardException;
+import java.util.function.Supplier;
/**
* @author Jan Jancar johny@neuromancer.sk
*/
public class CommandTestable extends BaseTestable {
- private Command command;
- private Response response;
+ protected Command command;
+ protected Response response;
public CommandTestable(Command command) {
this.command = command;
@@ -41,4 +42,19 @@ public class CommandTestable extends BaseTestable {
ok = true;
}
}
+
+ public static class FunctionCommandTestable extends CommandTestable {
+ private Supplier<Command> supplier;
+
+ public FunctionCommandTestable(Supplier<Command> supplier) {
+ super(null);
+ this.supplier = supplier;
+ }
+
+ @Override
+ public void run() {
+ this.command = supplier.get();
+ super.run();
+ }
+ }
}
diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/PerformanceTest.java b/reader/src/main/java/cz/crcs/ectester/reader/test/PerformanceTest.java
index a725dc2..1171154 100644
--- a/reader/src/main/java/cz/crcs/ectester/reader/test/PerformanceTest.java
+++ b/reader/src/main/java/cz/crcs/ectester/reader/test/PerformanceTest.java
@@ -26,26 +26,38 @@ public class PerformanceTest extends SimpleTest<CommandTestable> {
private int count;
private String desc;
+ private PerformanceTest(CardMngr cardManager, CommandTestable testable, TestCallback<CommandTestable> callback, int count, String desc) {
+ super(testable, callback);
+ this.cardManager = cardManager;
+ this.count = count;
+ this.desc = desc;
+ }
+
private PerformanceTest(CardMngr cardManager, CommandTestable testable, int count, String desc) {
- super(testable, new TestCallback<CommandTestable>() {
+ this(cardManager, testable, new TestCallback<CommandTestable>() {
@Override
public Result apply(CommandTestable testable) {
return new Result(Result.Value.SUCCESS);
}
- });
- this.cardManager = cardManager;
- this.count = count;
- this.desc = desc;
+ }, count, desc);
}
public static PerformanceTest repeat(CardMngr cardManager, Command cmd, int count) {
return new PerformanceTest(cardManager, new CommandTestable(cmd), count, null);
}
+ public static PerformanceTest repeat(CardMngr cardManager, CommandTestable testable, int count) {
+ return new PerformanceTest(cardManager, testable, count, null);
+ }
+
public static PerformanceTest repeat(CardMngr cardManager, String desc, Command cmd, int count) {
return new PerformanceTest(cardManager, new CommandTestable(cmd), count, desc);
}
+ public static PerformanceTest repeat(CardMngr cardManager, String desc, CommandTestable testable, int count) {
+ return new PerformanceTest(cardManager, testable, count, desc);
+ }
+
@Override
public String getDescription() {
String rest = String.format("Mean = %d ns, Median = %d ns, Mode = %d ns", mean, median, mode);
diff --git a/reader/src/test/java/cz/crcs/ectester/reader/AppTests.java b/reader/src/test/java/cz/crcs/ectester/reader/AppTests.java
new file mode 100644
index 0000000..173f7e2
--- /dev/null
+++ b/reader/src/test/java/cz/crcs/ectester/reader/AppTests.java
@@ -0,0 +1,141 @@
+package cz.crcs.ectester.reader;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junitpioneer.jupiter.StdIo;
+import org.junitpioneer.jupiter.StdOut;
+
+import java.time.Duration;
+
+import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class AppTests {
+
+ @Test
+ @StdIo()
+ public void help(StdOut out) {
+ ECTesterReader.main(new String[]{"-h"});
+ String s = out.capturedString();
+ assertTrue(s.contains("ECTesterReader"));
+ }
+
+ @Test
+ @StdIo()
+ public void listSuites(StdOut out) {
+ ECTesterReader.main(new String[]{"--list-suites"});
+ String s = out.capturedString();
+ assertTrue(s.contains("default test suite"));
+ }
+
+ @Test
+ @StdIo()
+ public void listData(StdOut out) {
+ ECTesterReader.main(new String[]{"--list-named"});
+ String s = out.capturedString();
+ assertTrue(s.contains("secg"));
+ }
+
+ // Add StdIo to all the suite tests when this is resolved: https://github.com/junit-pioneer/junit-pioneer/issues/822
+
+ @Test
+ @XFail(value = "JCardSim sometimes times-out.")
+ public void defaultSuite() {
+ assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "default", "-s"}));
+ }
+
+ @Test
+ @XFail(value = "JCardSim sometimes times-out.")
+ @Disabled
+ public void testVectorSuite() {
+ assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "test-vectors", "-s"}));
+ }
+
+ @Test
+ @XFail(value = "JCardSim sometimes times-out.")
+ public void compressionSuite() {
+ assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "compression", "-s"}));
+ }
+
+ @Test
+ @XFail(value = "JCardSim sometimes times-out.")
+ @Disabled
+ public void wrongSuite() {
+ assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "wrong", "-s", "-y"}));
+ }
+
+ @Test
+ @XFail(value = "JCardSim sometimes times-out.")
+ public void degenerateSuite() {
+ assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "degenerate", "-s", "-y"}));
+ }
+
+ @Test
+ @XFail(value = "JCardSim sometimes times-out.")
+ @Disabled
+ public void cofactorSuite() {
+ assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "cofactor", "-s", "-y"}));
+ }
+
+ @Test
+ @XFail(value = "JCardSim sometimes times-out.")
+ @Disabled
+ public void compositeSuite() {
+ assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "composite", "-s", "-y"}));
+ }
+
+ @Test
+ @XFail(value = "JCardSim sometimes times-out.")
+ public void invalidSuite() {
+ assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "invalid", "-s", "-y"}));
+ }
+
+ @Test
+ @XFail(value = "JCardSim sometimes times-out.")
+ public void edgeCasesSuite() {
+ assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "edge-cases", "-s", "-y"}));
+ }
+
+ @Test
+ @XFail(value = "JCardSim sometimes times-out.")
+ public void signatureSuite() {
+ assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "signature", "-s"}));
+ }
+
+ @Test
+ @XFail(value = "JCardSim sometimes times-out.")
+ public void twistSuite() {
+ assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "twist", "-s", "-y"}));
+ }
+
+ @Test
+ @XFail(value = "JCardSim sometimes times-out.")
+ public void miscellaneousSuite() {
+ assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "miscellaneous", "-s", "-y"}));
+ }
+
+ @Test
+ public void generate() {
+ ECTesterReader.main(new String[]{"-g", "10", "-s", "-fp", "-o", "/dev/null", "-b", "256"});
+ }
+
+ @Test
+ public void ecdh() {
+ ECTesterReader.main(new String[]{"-dh", "-fp", "-b", "256", "-s"});
+ }
+
+ @Test
+ public void ecdsa() {
+ ECTesterReader.main(new String[]{"-dsa", "-fp", "-b", "256", "-s"});
+ }
+
+ @Test
+ public void export() {
+ ECTesterReader.main(new String[]{"-e", "-fp", "-b", "256", "-s", "-o", "/dev/null"});
+ }
+
+ @Test
+ public void info() {
+ ECTesterReader.main(new String[]{"-nf", "-s"});
+ }
+}
diff --git a/reader/src/test/java/cz/crcs/ectester/reader/OutputTests.java b/reader/src/test/java/cz/crcs/ectester/reader/OutputTests.java
new file mode 100644
index 0000000..5300e98
--- /dev/null
+++ b/reader/src/test/java/cz/crcs/ectester/reader/OutputTests.java
@@ -0,0 +1,13 @@
+package cz.crcs.ectester.reader;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class OutputTests {
+
+ @ParameterizedTest
+ @ValueSource(strings = {"text", "xml", "yml"})
+ public void formats(String format) {
+ ECTesterReader.main(new String[]{"-t", "default", "-s", "-o", String.format("%s:out.%s", format, format),});
+ }
+}
diff --git a/reader/src/test/java/cz/crcs/ectester/reader/XFail.java b/reader/src/test/java/cz/crcs/ectester/reader/XFail.java
new file mode 100644
index 0000000..f42f530
--- /dev/null
+++ b/reader/src/test/java/cz/crcs/ectester/reader/XFail.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2016-2023 the original author or authors.
+ * Taken from https://github.com/junit-pioneer/junit-pioneer/blob/98cef28462c8b7ab66231cc5b7e8daef3b329f67/src/main/java/org/junitpioneer/jupiter/ExpectedToFail.java
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v2.0 which
+ * accompanies this distribution and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v20.html
+ */
+
+package cz.crcs.ectester.reader;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import org.junit.jupiter.api.extension.ExtendWith;
+
+/**
+ * {@code @ExpectedToFail} is a JUnit Jupiter extension to mark test methods as temporarily
+ * 'expected to fail'. Such test methods will still be executed but when they result in a test
+ * failure or error the test will be aborted. However, if the test method unexpectedly executes
+ * successfully, it is marked as failure to let the developer know that the test is now
+ * successful and that the {@code @ExpectedToFail} annotation can be removed.
+ *
+ * <p>The big difference compared to JUnit's {@link org.junit.jupiter.api.Disabled @Disabled}
+ * annotation is that the developer is informed as soon as a test is successful again.
+ * This helps to avoid creating duplicate tests by accident and counteracts the accumulation
+ * of disabled tests over time.</p>
+ *
+ * <p>Further, the {@link #withExceptions()} attribute can be used to restrict the extension's behavior
+ * to specific exceptions. That is, only if the test method ends up throwing one of the specified exceptions
+ * will the test be aborted. This can, for example, be used when the production code temporarily throws
+ * an {@link UnsupportedOperationException} because some feature has not been implemented yet, but the
+ * test method is already implemented and should not fail on a failing assertion.
+ * </p>
+ *
+ * <p>The annotation can only be used on methods and as meta-annotation on other annotation types.
+ * Similar to {@code @Disabled}, it has to be used in addition to a "testable" annotation, such
+ * as {@link org.junit.jupiter.api.Test @Test}. Otherwise the annotation has no effect.</p>
+ *
+ * <p><b>Important:</b> This annotation is <b>not</b> intended as a way to mark test methods
+ * which intentionally cause exceptions. Such test methods should use
+ * {@link org.junit.jupiter.api.Assertions#assertThrows(Class, org.junit.jupiter.api.function.Executable) assertThrows}
+ * or similar means to explicitly test for a specific exception class being thrown by a
+ * specific action.</p>
+ *
+ * <p>For more details and examples, see
+ * <a href="https://junit-pioneer.org/docs/expected-to-fail-tests/" target="_top">the documentation on <code>@ExpectedToFail</code></a>.</p>
+ *
+ * @since 1.8.0
+ * @see org.junit.jupiter.api.Disabled
+ */
+@Documented
+@Retention(RUNTIME)
+/*
+ * Only supports METHOD and ANNOTATION_TYPE as targets but not test classes because there
+ * it is not clear what the 'correct' behavior would be when only a few test methods
+ * execute successfully. Would the developer then have to remove the @ExpectedToFail annotation
+ * from the test class and annotate methods individually?
+ */
+@Target({ METHOD, ANNOTATION_TYPE })
+@ExtendWith(XFailExtension.class)
+public @interface XFail {
+
+ /**
+ * Defines the message to show when a test is aborted because it is failing.
+ * This can be used for example to briefly explain why the tested code is not working
+ * as intended at the moment.
+ * An empty string (the default) causes a generic default message to be used.
+ */
+ String value() default "";
+
+ /**
+ * Specifies which exceptions are expected to be thrown and will cause the test to be aborted rather than fail.
+ * An empty array is considered a configuration error and will cause the test to fail. Instead, consider leaving
+ * the attribute set to the default value when any exception should cause the test to be aborted.
+ */
+ Class<? extends Throwable>[] withExceptions() default { Throwable.class };
+
+} \ No newline at end of file
diff --git a/reader/src/test/java/cz/crcs/ectester/reader/XFaillExtension.java b/reader/src/test/java/cz/crcs/ectester/reader/XFaillExtension.java
new file mode 100644
index 0000000..b190e1a
--- /dev/null
+++ b/reader/src/test/java/cz/crcs/ectester/reader/XFaillExtension.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2016-2023 the original author or authors.
+ * Taken from https://github.com/junit-pioneer/junit-pioneer/blob/98cef28462c8b7ab66231cc5b7e8daef3b329f67/src/main/java/org/junitpioneer/jupiter/ExpectedToFailExtension.java
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v2.0 which
+ * accompanies this distribution and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v20.html
+ */
+
+package cz.crcs.ectester.reader;
+
+import java.lang.reflect.Method;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.extension.Extension;
+import org.junit.jupiter.api.extension.ExtensionConfigurationException;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.InvocationInterceptor;
+import org.junit.jupiter.api.extension.ReflectiveInvocationContext;
+import org.junit.platform.commons.support.AnnotationSupport;
+import org.opentest4j.AssertionFailedError;
+import org.opentest4j.TestAbortedException;
+
+class XFailExtension implements Extension, InvocationInterceptor {
+
+ @Override
+ public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext,
+ ExtensionContext extensionContext) throws Throwable {
+ invokeAndInvertResult(invocation, extensionContext);
+ }
+
+ private static void invokeAndInvertResult(Invocation<Void> invocation, ExtensionContext extensionContext)
+ throws Throwable {
+ XFail expectedToFail = getExpectedToFailAnnotation(extensionContext);
+ if (expectedToFail.withExceptions().length == 0) {
+ throw new ExtensionConfigurationException("@XFail withExceptions must not be empty");
+ }
+
+ try {
+ invocation.proceed();
+ // at this point, the invocation succeeded, so we'd want to call `fail(...)`,
+ // but that would get handled by the following `catch` and so it's easier
+ // to instead fall through to a `fail(...)` after the `catch` block
+ }
+ catch (Throwable t) {
+ if (shouldPreserveException(t)) {
+ throw t;
+ }
+
+ if (Stream.of(expectedToFail.withExceptions()).noneMatch(clazz -> clazz.isInstance(t))) {
+ throw new AssertionFailedError(
+ "Test marked as temporarily 'expected to fail' failed with an unexpected exception", t);
+ }
+
+ String message = expectedToFail.value();
+ if (message.isEmpty()) {
+ message = "Test marked as temporarily 'expected to fail' failed as expected";
+ }
+
+ throw new TestAbortedException(message, t);
+ }
+ }
+
+ /**
+ * Returns whether the exception should be preserved and reported as is instead
+ * of considering it an 'expected to fail' exception.
+ *
+ * <p>This method is used for exceptions that abort test execution and should
+ * have higher precedence than aborted exceptions thrown by this extension.</p>
+ */
+ private static boolean shouldPreserveException(Throwable t) {
+ // Note: Ideally would use the same logic JUnit uses to determine if exception is aborting
+ // execution, see its class OpenTest4JAndJUnit4AwareThrowableCollector
+ return t instanceof TestAbortedException;
+ }
+
+ private static XFail getExpectedToFailAnnotation(ExtensionContext context) {
+ return AnnotationSupport
+ .findAnnotation(context.getRequiredTestMethod(), XFail.class)
+ .orElseThrow(() -> new IllegalStateException("@XFail is missing."));
+
+ }
+
+} \ No newline at end of file