summaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/reader/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/cz/crcs/ectester/reader/test')
-rw-r--r--src/cz/crcs/ectester/reader/test/CardCompositeCurvesSuite.java51
-rw-r--r--src/cz/crcs/ectester/reader/test/CardDefaultSuite.java94
-rw-r--r--src/cz/crcs/ectester/reader/test/CardInvalidCurvesSuite.java67
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTestSuite.java24
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java83
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTwistTestSuite.java62
-rw-r--r--src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java58
-rw-r--r--src/cz/crcs/ectester/reader/test/CommandTest.java76
-rw-r--r--src/cz/crcs/ectester/reader/test/CommandTestable.java44
-rw-r--r--src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java53
-rw-r--r--src/cz/crcs/ectester/reader/test/DefaultSuite.java69
-rw-r--r--src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java68
-rw-r--r--src/cz/crcs/ectester/reader/test/PerformanceTest.java103
-rw-r--r--src/cz/crcs/ectester/reader/test/Result.java94
-rw-r--r--src/cz/crcs/ectester/reader/test/Test.java217
-rw-r--r--src/cz/crcs/ectester/reader/test/TestRunner.java29
-rw-r--r--src/cz/crcs/ectester/reader/test/TestSuite.java135
-rw-r--r--src/cz/crcs/ectester/reader/test/TestVectorSuite.java83
-rw-r--r--src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java34
19 files changed, 662 insertions, 782 deletions
diff --git a/src/cz/crcs/ectester/reader/test/CardCompositeCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CardCompositeCurvesSuite.java
new file mode 100644
index 0000000..a53806c
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardCompositeCurvesSuite.java
@@ -0,0 +1,51 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
+import cz.crcs.ectester.common.output.TestWriter;
+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 javacard.security.KeyPair;
+
+import java.util.Map;
+
+import static cz.crcs.ectester.common.test.Result.ExpectedValue;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardCompositeCurvesSuite extends CardTestSuite {
+
+ public CardCompositeCurvesSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
+ super(writer, cfg, cardManager, "composite", "The composite suite run ECDH over curves with composite order. This should generally fail, as using such a curve is unsafe.");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ /* Do the default run with the public keys set to provided smallorder keys
+ * over composite order curves. Essentially small subgroup attacks.
+ * These should fail, the curves aren't safe so that if the computation with
+ * a small order public key succeeds the private key modulo the public key order
+ * is revealed.
+ */
+ Map<String, EC_Key> keys = EC_Store.getInstance().getObjects(EC_Key.class, "composite");
+ for (EC_Key key : keys.values()) {
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, key.getCurve());
+ if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
+ continue;
+ }
+ if ((curve.getBits() == cfg.bits || cfg.all)) {
+ doTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
+ doTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY));
+ doTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.ANY));
+ Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH, key.flatten());
+ doTest(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."));
+ new Command.Cleanup(this.card).send();
+ }
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java
new file mode 100644
index 0000000..c3bd9c8
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java
@@ -0,0 +1,94 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.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.reader.CardMngr;
+import cz.crcs.ectester.reader.ECTesterReader;
+import cz.crcs.ectester.reader.command.Command;
+import javacard.security.KeyPair;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static cz.crcs.ectester.common.test.Result.ExpectedValue;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardDefaultSuite extends CardTestSuite {
+
+ public CardDefaultSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
+ super(writer, cfg, cardManager, "default", "The default test suite run basic support of ECDH and ECDSA.");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ if (cfg.primeField) {
+ runDefault(KeyPair.ALG_EC_FP);
+ }
+ if (cfg.binaryField) {
+ runDefault(KeyPair.ALG_EC_F2M);
+ }
+ }
+
+ private void runDefault(byte field) throws Exception {
+ short[] keySizes = field == KeyPair.ALG_EC_FP ? EC_Consts.FP_SIZES : EC_Consts.F2M_SIZES;
+ for (short keyLength : keySizes) {
+ String description = "Tests of " + keyLength + "b " + (field == KeyPair.ALG_EC_FP ? "ALG_EC_FP" : "ALG_EC_F2M") + " support.";
+
+ List<Test> supportTests = new LinkedList<>();
+ Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, field), ExpectedValue.SUCCESS));
+ if (!key.ok()) {
+ doTest(CompoundTest.all(ExpectedValue.SUCCESS, description + " None.", key));
+ continue;
+ }
+ supportTests.add(key);
+
+ Test genDefault = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS));
+ Test setCustom = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.getCurve(keyLength, field), EC_Consts.PARAMETERS_DOMAIN_FP, null), ExpectedValue.SUCCESS));
+ Test genCustom = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS));
+ supportTests.add(genDefault);
+ supportTests.add(setCustom);
+ supportTests.add(genCustom);
+
+ 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, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, kaType);
+ Test ka = runTest(CommandTest.expect(ecdh, ExpectedValue.SUCCESS));
+ Test kaCompressed = runTest(CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_COMPRESS, kaType), ExpectedValue.SUCCESS));
+ Test perfTest = null;
+ if (ka.ok()) {
+ perfTest = runTest(PerformanceTest.repeat(ecdh, 10));
+ }
+ Test compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, "Test of the " + CardUtil.getKATypeString(kaType) + " KeyAgreement.", allocate, ka, kaCompressed, perfTest));
+ supportTests.add(compound);
+ } else {
+ runTest(allocate);
+ supportTests.add(allocate);
+ }
+ }
+ 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, ECTesterApplet.KEYPAIR_LOCAL, sigType, ECTesterApplet.EXPORT_FALSE, null);
+ Test expect = runTest(CommandTest.expect(ecdsa, ExpectedValue.SUCCESS));
+ Test perfTest = null;
+ if (expect.ok()) {
+ perfTest = runTest(PerformanceTest.repeat(ecdsa, 10));
+ }
+ Test compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, "Test of the " + CardUtil.getSigTypeString(sigType) + " signature.", allocate, expect, perfTest));
+ supportTests.add(compound);
+ } else {
+ supportTests.add(allocate);
+ }
+ }
+ doTest(CompoundTest.all(ExpectedValue.SUCCESS, description + " Some.", supportTests.toArray(new Test[0])));
+ new Command.Cleanup(this.card).send();
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CardInvalidCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CardInvalidCurvesSuite.java
new file mode 100644
index 0000000..8424d45
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardInvalidCurvesSuite.java
@@ -0,0 +1,67 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
+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.data.EC_Store;
+import cz.crcs.ectester.reader.CardMngr;
+import cz.crcs.ectester.reader.ECTesterReader;
+import cz.crcs.ectester.reader.command.Command;
+import javacard.security.KeyPair;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static cz.crcs.ectester.common.test.Result.ExpectedValue;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardInvalidCurvesSuite extends CardTestSuite {
+
+ public CardInvalidCurvesSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
+ super(writer, cfg, cardManager, "invalid", "The invalid curve suite tests whether the card rejects points outside of the curve during ECDH.");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ /* Set original curves (secg/nist/brainpool). Generate local.
+ * Try ECDH with invalid public keys of increasing (or decreasing) order.
+ */
+ Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "invalid");
+ Map<EC_Curve, List<EC_Key.Public>> curves = new HashMap<>();
+ for (EC_Key.Public key : pubkeys.values()) {
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, key.getCurve());
+ if (curve.getBits() != cfg.bits && !cfg.all) {
+ continue;
+ }
+ if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
+ continue;
+ }
+ List<EC_Key.Public> keys = curves.getOrDefault(curve, new LinkedList<>());
+ keys.add(key);
+ curves.putIfAbsent(curve, keys);
+ }
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curves.entrySet()) {
+ EC_Curve curve = e.getKey();
+ List<EC_Key.Public> keys = e.getValue();
+
+ doTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
+ doTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
+ doTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS));
+ List<Test> ecdhTests = new LinkedList<>();
+ for (EC_Key.Public pub : keys) {
+ Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
+ ecdhTests.add(CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on invalid curve.", "Card incorrectly accepted point on invalid curve."));
+ }
+ doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), ecdhTests.toArray(new Test[0])));
+ new Command.Cleanup(this.card).send();
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CardTestSuite.java b/src/cz/crcs/ectester/reader/test/CardTestSuite.java
new file mode 100644
index 0000000..0eccd16
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardTestSuite.java
@@ -0,0 +1,24 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.TestSuite;
+import cz.crcs.ectester.reader.CardMngr;
+import cz.crcs.ectester.reader.ECTesterReader;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class CardTestSuite extends TestSuite {
+ ECTesterReader.Config cfg;
+ CardMngr card;
+
+ CardTestSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager, String name, String description) {
+ super(writer, name, description);
+ this.card = cardManager;
+ this.cfg = cfg;
+ }
+
+ public CardMngr getCard() {
+ return card;
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
new file mode 100644
index 0000000..73c6621
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
@@ -0,0 +1,83 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.ec.*;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.*;
+import cz.crcs.ectester.common.util.ByteUtil;
+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 javacard.security.KeyPair;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static cz.crcs.ectester.common.test.Result.ExpectedValue;
+import static cz.crcs.ectester.common.test.Result.Value;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardTestVectorSuite extends CardTestSuite {
+
+ public CardTestVectorSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
+ super(writer, cfg, cardManager, "test", "The test-vectors suite contains a collection of test vectors which test basic ECDH correctness.");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ /* Set original curves (secg/nist/brainpool). Set keypairs from test vectors.
+ * Do ECDH both ways, export and verify that the result is correct.
+ */
+ Map<String, EC_KAResult> results = EC_Store.getInstance().getObjects(EC_KAResult.class, "test");
+ for (EC_KAResult result : results.values()) {
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, result.getCurve());
+ if (curve.getBits() != cfg.bits && !cfg.all) {
+ continue;
+ }
+ if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
+ continue;
+ }
+ EC_Params onekey = EC_Store.getInstance().getObject(EC_Keypair.class, result.getOneKey());
+ if (onekey == null) {
+ onekey = EC_Store.getInstance().getObject(EC_Key.Private.class, result.getOneKey());
+ }
+ EC_Params otherkey = EC_Store.getInstance().getObject(EC_Keypair.class, result.getOtherKey());
+ if (otherkey == null) {
+ otherkey = EC_Store.getInstance().getObject(EC_Key.Public.class, result.getOtherKey());
+ }
+ if (onekey == null || otherkey == null) {
+ throw new IOException("Test vector keys couldn't be located.");
+ }
+ List<Test> testVector = new LinkedList<>();
+
+ testVector.add(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
+ testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
+ testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.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, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W)), ExpectedValue.SUCCESS));
+ testVector.add(CommandTest.function(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, result.getJavaCardKA()), new TestCallback<CommandTestable>() {
+ @Override
+ public Result apply(CommandTestable testable) {
+ Response.ECDH dh = (Response.ECDH) testable.getResponse();
+ if (!dh.successful())
+ return new Result(Value.FAILURE, "ECDH was unsuccessful.");
+ if (!dh.hasSecret())
+ return new Result(Value.FAILURE, "ECDH response did not contain the derived secret.");
+ if (!ByteUtil.compareBytes(dh.getSecret(), 0, result.getData(0), 0, dh.secretLength())) {
+ int firstDiff = ByteUtil.diffBytes(dh.getSecret(), 0, result.getData(0), 0, dh.secretLength());
+ return new Result(Value.FAILURE, "ECDH derived secret does not match the test-vector, first difference was at byte " + String.valueOf(firstDiff) + ".");
+ }
+ return new Result(Value.SUCCESS);
+ }
+ }));
+ doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Test vector " + result.getId(), testVector.toArray(new Test[0])));
+ new Command.Cleanup(this.card).send();
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CardTwistTestSuite.java b/src/cz/crcs/ectester/reader/test/CardTwistTestSuite.java
new file mode 100644
index 0000000..c43b234
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardTwistTestSuite.java
@@ -0,0 +1,62 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
+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.data.EC_Store;
+import cz.crcs.ectester.reader.CardMngr;
+import cz.crcs.ectester.reader.ECTesterReader;
+import cz.crcs.ectester.reader.command.Command;
+import javacard.security.KeyPair;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardTwistTestSuite extends CardTestSuite {
+ public CardTwistTestSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
+ 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
+ protected void runTests() throws Exception {
+ Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "twist");
+ Map<EC_Curve, List<EC_Key.Public>> curves = new HashMap<>();
+ for (EC_Key.Public key : pubkeys.values()) {
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, key.getCurve());
+ if (curve.getBits() != cfg.bits && !cfg.all) {
+ continue;
+ }
+ if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
+ continue;
+ }
+ List<EC_Key.Public> keys = curves.getOrDefault(curve, new LinkedList<>());
+ keys.add(key);
+ curves.putIfAbsent(curve, keys);
+ }
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curves.entrySet()) {
+ EC_Curve curve = e.getKey();
+ List<EC_Key.Public> keys = e.getValue();
+
+ doTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
+ doTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS));
+ doTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS));
+ List<Test> ecdhTests = new LinkedList<>();
+ for (EC_Key.Public pub : keys) {
+ Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
+ ecdhTests.add(CommandTest.expect(ecdhCommand, Result.ExpectedValue.FAILURE, "Card correctly rejected point on twist.", "Card incorrectly accepted point on twist."));
+ }
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId(), ecdhTests.toArray(new Test[0])));
+ new Command.Cleanup(this.card).send();
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java
new file mode 100644
index 0000000..cac8fab
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java
@@ -0,0 +1,58 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.ec.EC_Curve;
+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.data.EC_Store;
+import cz.crcs.ectester.reader.CardMngr;
+import cz.crcs.ectester.reader.ECTesterReader;
+import cz.crcs.ectester.reader.command.Command;
+import javacard.security.KeyPair;
+
+import java.util.Map;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardWrongCurvesSuite extends CardTestSuite {
+
+ public CardWrongCurvesSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
+ super(writer, cfg, cardManager, "wrong", "The wrong curve suite run whether the card rejects domain parameters which are not curves.");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ /* Just do the default run on the wrong curves.
+ * These should generally fail, the curves aren't curves.
+ */
+ Map<String, EC_Curve> curves = EC_Store.getInstance().getObjects(EC_Curve.class, "wrong");
+ for (Map.Entry<String, EC_Curve> e : curves.entrySet()) {
+ EC_Curve curve = e.getValue();
+ if (curve.getBits() != cfg.bits && !cfg.all) {
+ continue;
+ }
+ if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
+ continue;
+ }
+ Test key = doTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
+ if (!key.ok()) {
+ continue;
+ }
+ Test set = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS));
+ Test generate = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.SUCCESS));
+ doTest(CompoundTest.any(Result.ExpectedValue.FAILURE, "Set wrong curve and generate keypairs, should fail." ,set, generate));
+
+ for (byte kaType : EC_Consts.KA_TYPES) {
+ 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, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, kaType), Result.ExpectedValue.FAILURE));
+ doTest(CompoundTest.any(Result.ExpectedValue.FAILURE, "Allocate and perform KA, should fail.", allocate, ka));
+ }
+ }
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CommandTest.java b/src/cz/crcs/ectester/reader/test/CommandTest.java
new file mode 100644
index 0000000..a08d820
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CommandTest.java
@@ -0,0 +1,76 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.SimpleTest;
+import cz.crcs.ectester.common.test.TestCallback;
+import cz.crcs.ectester.common.test.TestException;
+import cz.crcs.ectester.reader.command.Command;
+import cz.crcs.ectester.reader.response.Response;
+
+/**
+ * A simple test that runs one Command to get and evaluate one Response
+ * to get a Result and compare it with the expected one.
+ */
+public class CommandTest extends SimpleTest<CommandTestable> {
+ private CommandTest(CommandTestable command, TestCallback<CommandTestable> callback) {
+ super(command, callback);
+ }
+
+ public static CommandTest function(CommandTestable command, TestCallback<CommandTestable> callback) {
+ return new CommandTest(command, callback);
+ }
+
+ public static CommandTest function(Command command, TestCallback<CommandTestable> callback) {
+ return function(new CommandTestable(command), callback);
+ }
+
+ public static CommandTest expect(CommandTestable command, Result.ExpectedValue expected, String ok, String nok) {
+ return new CommandTest(command, new TestCallback<CommandTestable>() {
+ @Override
+ public Result apply(CommandTestable commandTestable) {
+ Response resp = commandTestable.getResponse();
+ Result.Value resultValue = Result.Value.fromExpected(expected, resp.successful(), resp.error());
+ return new Result(resultValue, resultValue.ok() ? ok : nok);
+ }
+ });
+ }
+
+ public static CommandTest expect(Command command, Result.ExpectedValue expectedValue, String ok, String nok) {
+ return expect(new CommandTestable(command), expectedValue, ok, nok);
+ }
+
+ public static CommandTest expect(CommandTestable command, Result.ExpectedValue expected) {
+ return expect(command, expected, null, null);
+ }
+
+ public static CommandTest expect(Command command, Result.ExpectedValue expectedValue) {
+ return expect(command, expectedValue, null, null);
+ }
+
+ public Command getCommand() {
+ return testable.getCommand();
+ }
+
+ public Response getResponse() {
+ return testable.getResponse();
+ }
+
+ @Override
+ public void run() throws TestException {
+ if (hasRun)
+ return;
+
+ testable.run();
+ result = callback.apply(testable);
+ hasRun = true;
+ }
+
+ @Override
+ public String getDescription() {
+ if (hasRun) {
+ return testable.getResponse().getDescription();
+ } else {
+ return testable.getCommand().toString();
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CommandTestable.java b/src/cz/crcs/ectester/reader/test/CommandTestable.java
new file mode 100644
index 0000000..3bb55bf
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CommandTestable.java
@@ -0,0 +1,44 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.common.test.BaseTestable;
+import cz.crcs.ectester.common.test.TestException;
+import cz.crcs.ectester.reader.command.Command;
+import cz.crcs.ectester.reader.response.Response;
+
+import javax.smartcardio.CardException;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CommandTestable extends BaseTestable {
+ private Command command;
+ private Response response;
+
+ public CommandTestable(Command command) {
+ this.command = command;
+ }
+
+ public Command getCommand() {
+ return command;
+ }
+
+ public Response getResponse() {
+ return response;
+ }
+
+ @Override
+ public void run() throws TestException {
+ try {
+ response = command.send();
+ } catch (CardException e) {
+ throw new TestException(e);
+ }
+
+ hasRun = true;
+ if (response.error()) {
+ error = true;
+ } else if (response.successful()) {
+ ok = true;
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java
deleted file mode 100644
index 8e7ca31..0000000
--- a/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTester;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.ec.EC_Curve;
-import cz.crcs.ectester.reader.ec.EC_Key;
-import javacard.security.KeyPair;
-
-import java.util.Map;
-
-import static cz.crcs.ectester.reader.test.Result.ExpectedValue;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CompositeCurvesSuite extends TestSuite {
-
- public CompositeCurvesSuite(EC_Store dataStore, ECTester.Config cfg) {
- super(dataStore, cfg, "composite", "The composite suite tests ECDH over curves with composite order. This should generally fail, as using such a curve is unsafe.");
- }
-
- @Override
- public void setup(CardMngr cardManager) {
- /* Do the default tests with the public keys set to provided smallorder keys
- * over composite order curves. Essentially small subgroup attacks.
- * These should fail, the curves aren't safe so that if the computation with
- * a small order public key succeeds the private key modulo the public key order
- * is revealed.
- */
- Map<String, EC_Key> keys = dataStore.getObjects(EC_Key.class, "composite");
- for (EC_Key key : keys.values()) {
- EC_Curve curve = dataStore.getObject(EC_Curve.class, key.getCurve());
- if (cfg.namedCurve != null && !(key.getCurve().startsWith(cfg.namedCurve) || key.getCurve().equals(cfg.namedCurve))) {
- continue;
- }
- if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
- continue;
- }
- if ((curve.getBits() == cfg.bits || cfg.all)) {
- tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- tests.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY));
- tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.ANY));
- Command ecdhCommand = new Command.ECDH_direct(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH, key.flatten());
- tests.add(new Test.Simple(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(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY));
- }
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/DefaultSuite.java b/src/cz/crcs/ectester/reader/test/DefaultSuite.java
deleted file mode 100644
index 736b7c5..0000000
--- a/src/cz/crcs/ectester/reader/test/DefaultSuite.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTester;
-import cz.crcs.ectester.reader.command.Command;
-import javacard.security.KeyPair;
-
-import java.io.IOException;
-
-import static cz.crcs.ectester.reader.test.Result.ExpectedValue;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class DefaultSuite extends TestSuite {
-
- public DefaultSuite(EC_Store dataStore, ECTester.Config cfg) {
- super(dataStore, cfg, "default", "The default test suite tests basic support of ECDH and ECDSA.");
- }
-
- @Override
- public void setup(CardMngr cardManager) throws IOException {
- tests.add(new Test.Simple(new Command.Support(cardManager), ExpectedValue.ANY));
- if (cfg.namedCurve != null) {
- String desc = "Default tests over the " + cfg.namedCurve + " curve category.";
- if (cfg.primeField) {
- tests.addAll(defaultCategoryTests(cardManager, cfg.namedCurve, KeyPair.ALG_EC_FP, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, desc));
- }
- if (cfg.binaryField) {
- tests.addAll(defaultCategoryTests(cardManager, cfg.namedCurve, KeyPair.ALG_EC_F2M, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, desc));
- }
- } else {
- if (cfg.all) {
- if (cfg.primeField) {
- //iterate over prime curve sizes used: EC_Consts.FP_SIZES
- for (short keyLength : EC_Consts.FP_SIZES) {
- defaultTests(cardManager, keyLength, KeyPair.ALG_EC_FP);
- }
- }
- if (cfg.binaryField) {
- //iterate over binary curve sizes used: EC_Consts.F2M_SIZES
- for (short keyLength : EC_Consts.F2M_SIZES) {
- defaultTests(cardManager, keyLength, KeyPair.ALG_EC_F2M);
- }
- }
- } else {
- if (cfg.primeField) {
- defaultTests(cardManager, (short) cfg.bits, KeyPair.ALG_EC_FP);
- }
-
- if (cfg.binaryField) {
- defaultTests(cardManager, (short) cfg.bits, KeyPair.ALG_EC_F2M);
- }
- }
- }
- }
-
- private void defaultTests(CardMngr cardManager, short keyLength, byte keyType) throws IOException {
- tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, keyLength, keyType), ExpectedValue.SUCCESS));
- Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_BOTH, keyLength, keyType);
- if (curve != null)
- tests.add(new Test.Simple(curve, ExpectedValue.SUCCESS));
- tests.add(defaultCurveTests(cardManager, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, "Default tests."));
- tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY));
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java b/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java
deleted file mode 100644
index f61b695..0000000
--- a/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTester;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.ec.EC_Curve;
-import cz.crcs.ectester.reader.ec.EC_Key;
-import javacard.security.KeyPair;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import static cz.crcs.ectester.reader.test.Result.ExpectedValue;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class InvalidCurvesSuite extends TestSuite {
-
- public InvalidCurvesSuite(EC_Store dataStore, ECTester.Config cfg) {
- super(dataStore, cfg, "invalid", "The invalid curve suite tests whether the card rejects points outside of the curve during ECDH.");
- }
-
- @Override
- public void setup(CardMngr cardManager) throws IOException {
- /* Set original curves (secg/nist/brainpool). Generate local.
- * Try ECDH with invalid public keys of increasing (or decreasing) order.
- */
- Map<String, EC_Key.Public> pubkeys = dataStore.getObjects(EC_Key.Public.class, "invalid");
- Map<EC_Curve, List<EC_Key.Public>> curves = new HashMap<>();
- for (EC_Key.Public key : pubkeys.values()) {
- EC_Curve curve = dataStore.getObject(EC_Curve.class, key.getCurve());
- if (cfg.namedCurve != null && !(key.getCurve().startsWith(cfg.namedCurve) || key.getCurve().equals(cfg.namedCurve))) {
- continue;
- }
- if (curve.getBits() != cfg.bits && !cfg.all) {
- continue;
- }
- if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
- continue;
- }
- List<EC_Key.Public> keys = curves.getOrDefault(curve, new LinkedList<>());
- keys.add(key);
- curves.putIfAbsent(curve, keys);
- }
- for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curves.entrySet()) {
- EC_Curve curve = e.getKey();
- List<EC_Key.Public> keys = e.getValue();
-
- tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- tests.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
- tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS));
- List<Test> ecdhTests = new LinkedList<>();
- for (EC_Key.Public pub : keys) {
- Command ecdhCommand = new Command.ECDH_direct(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ANY, pub.flatten());
- ecdhTests.add(new Test.Simple(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on invalid curve." , "Card incorrectly accepted point on invalid curve."));
- }
- tests.add(Test.Compound.all(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), ecdhTests.toArray(new Test[0])));
- tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY));
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/PerformanceTest.java b/src/cz/crcs/ectester/reader/test/PerformanceTest.java
new file mode 100644
index 0000000..4a27bad
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/PerformanceTest.java
@@ -0,0 +1,103 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.SimpleTest;
+import cz.crcs.ectester.common.test.TestCallback;
+import cz.crcs.ectester.common.test.TestException;
+import cz.crcs.ectester.reader.command.Command;
+
+import java.util.Arrays;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class PerformanceTest extends SimpleTest<CommandTestable> {
+ private long[] times;
+ private long mean;
+ private long median;
+ private long mode;
+ private int count;
+
+ private PerformanceTest(CommandTestable testable, int count) {
+ super(testable, new TestCallback<CommandTestable>() {
+ @Override
+ public Result apply(CommandTestable testable) {
+ return new Result(Result.Value.SUCCESS);
+ }
+ });
+ this.count = count;
+ }
+
+ public static PerformanceTest repeat(Command cmd, int count) {
+ return new PerformanceTest(new CommandTestable(cmd), count);
+ }
+
+ @Override
+ public String getDescription() {
+ return String.format("Mean = %d ns, Median = %d ns, Mode = %d ns", mean, median, mode);
+ }
+
+ @Override
+ public void run() throws TestException {
+ if (hasRun)
+ return;
+
+ times = new long[count];
+ for (int i = 0; i < count; ++i) {
+ testable.run();
+ times[i] = testable.getResponse().getDuration();
+ testable.reset();
+ }
+
+ mean = Arrays.stream(times).sum() / count;
+
+ long[] sorted = times.clone();
+ Arrays.sort(sorted);
+ if (count % 2 == 0) {
+ median = (sorted[(count / 2) - 1] + sorted[count / 2]) / 2;
+ } else {
+ median = sorted[count / 2];
+ }
+
+ long max_occurences = 0;
+ int i = 0;
+ while (i < count) {
+ long current_value = sorted[i];
+ long current_occurences = 0;
+ while (i < count && sorted[i] == current_value) {
+ i++;
+ current_occurences++;
+ }
+ if (current_occurences > max_occurences) {
+ max_occurences = current_occurences;
+ mode = current_value;
+ }
+ }
+ hasRun = true;
+ result = callback.apply(testable);
+ }
+
+ public long getCount() {
+ return count;
+ }
+
+ public Command getCommand() {
+ return testable.getCommand();
+ }
+
+ public long[] getTimes() {
+ return times;
+ }
+
+ public long getMean() {
+ return mean;
+ }
+
+ public long getMedian() {
+ return median;
+ }
+
+ public long getMode() {
+ return mode;
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/Result.java b/src/cz/crcs/ectester/reader/test/Result.java
deleted file mode 100644
index 82f0f32..0000000
--- a/src/cz/crcs/ectester/reader/test/Result.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class Result {
-
- private Value value;
- private String cause;
-
- public Result(Value value) {
- this.value = value;
- }
-
- public Result(Value value, String cause) {
- this(value);
- this.cause = cause;
- }
-
- public Value getValue() {
- return value;
- }
-
- public String getCause() {
- return cause;
- }
-
- public boolean ok() {
- return value.ok();
- }
-
- public boolean compareTo(Result other) {
- if (other == null) {
- return false;
- }
- return value == other.value;
- }
-
- public boolean compareTo(Value other) {
- if (other == null) {
- return false;
- }
- return value == other;
- }
-
- /**
- *
- */
- public enum Value {
- SUCCESS(true),
- FAILURE(false),
- UXSUCCESS(false),
- XFAILURE(true),
- ERROR(false);
-
- private boolean ok;
-
- Value(boolean ok) {
- this.ok = ok;
- }
-
- public static Value fromExpected(ExpectedValue expected, boolean successful) {
- switch (expected) {
- case SUCCESS:
- return successful ? SUCCESS : FAILURE;
- case FAILURE:
- return successful ? UXSUCCESS : XFAILURE;
- case ANY:
- return SUCCESS;
- }
- return SUCCESS;
- }
-
- public static Value fromExpected(ExpectedValue expected, boolean successful, boolean error) {
- if (error) {
- return ERROR;
- }
- return fromExpected(expected, successful);
- }
-
- public boolean ok() {
- return ok;
- }
- }
-
- /**
- *
- */
- public enum ExpectedValue {
- SUCCESS,
- FAILURE,
- ANY
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/Test.java b/src/cz/crcs/ectester/reader/test/Test.java
deleted file mode 100644
index 022ad56..0000000
--- a/src/cz/crcs/ectester/reader/test/Test.java
+++ /dev/null
@@ -1,217 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.response.Response;
-
-import javax.smartcardio.CardException;
-import java.util.function.BiFunction;
-import java.util.function.Function;
-
-import static cz.crcs.ectester.reader.test.Result.ExpectedValue;
-import static cz.crcs.ectester.reader.test.Result.Value;
-
-/**
- * An abstract test that can be run and has a Result.
- *
- * @author Jan Jancar johny@neuromancer.sk
- */
-public abstract class Test {
- boolean hasRun = false;
- Result result;
-
- public Result getResult() {
- if (!hasRun) {
- return null;
- }
- return result;
- }
-
- public Value getResultValue() {
- if (!hasRun) {
- return null;
- }
- return result.getValue();
- }
-
- public String getResultCause() {
- if (!hasRun) {
- return null;
- }
- return result.getCause();
- }
-
- public boolean ok() {
- if (!hasRun) {
- return true;
- }
- return result.ok();
- }
-
- public abstract String getDescription();
-
- public boolean hasRun() {
- return hasRun;
- }
-
- public abstract void run() throws CardException;
-
- /**
- * A simple test that runs one Command to get and evaluate one Response
- * to get a Result and compare it with the expected one.
- */
- public static class Simple extends Test {
- private BiFunction<Command, Response, Result> callback;
- private Command command;
- private Response response;
-
- public Simple(Command command, BiFunction<Command, Response, Result> callback) {
- this.command = command;
- this.callback = callback;
- }
-
- public Simple(Command command, ExpectedValue expected, String ok, String nok) {
- this(command, (cmd, resp) -> {
- Value resultValue = Value.fromExpected(expected, resp.successful(), resp.error());
- return new Result(resultValue, resultValue.ok() ? ok : nok);
- });
- }
-
- public Simple(Command command, ExpectedValue expected) {
- this(command, expected, null, null);
- }
-
- public Command getCommand() {
- return command;
- }
-
- public Response getResponse() {
- return response;
- }
-
- @Override
- public void run() throws CardException {
- if (hasRun)
- return;
-
- response = command.send();
- if (callback != null) {
- result = callback.apply(command, response);
- } else {
- if (response.successful()) {
- result = new Result(Value.SUCCESS);
- } else {
- result = new Result(Value.FAILURE);
- }
- }
- hasRun = true;
- }
-
- @Override
- public String getDescription() {
- return response.getDescription();
- }
- }
-
- /**
- * A compound test that runs many Tests and has a Result dependent on all/some of their Results.
- */
- public static class Compound extends Test {
- private Function<Test[], Result> callback;
- private Test[] tests;
- private String description;
-
- private Compound(Function<Test[], Result> callback, Test... tests) {
- this.callback = callback;
- this.tests = tests;
- }
-
- private Compound(Function<Test[], Result> callback, String descripiton, Test... tests) {
- this(callback, tests);
- this.description = descripiton;
- }
-
- public static Compound function(Function<Test[], Result> callback, Test... tests) {
- return new Compound(callback, tests);
- }
-
- public static Compound function(Function<Test[], Result> callback, String description, Test... tests) {
- return new Compound(callback, description, tests);
- }
-
- public static Compound all(ExpectedValue what, Test... all) {
- return new Compound((tests) -> {
- for (Test test : tests) {
- if (!Value.fromExpected(what, test.ok()).ok()) {
- return new Result(Value.FAILURE, "At least one of the sub-tests did not have the expected result.");
- }
- }
- return new Result(Value.SUCCESS, "All sub-tests had the expected result.");
- }, all);
- }
-
- public static Compound all(ExpectedValue what, String description, Test... all) {
- Compound result = Compound.all(what, all);
- result.setDescription(description);
- return result;
- }
-
- public static Compound any(ExpectedValue what, Test... any) {
- return new Compound((tests) -> {
- for (Test test : tests) {
- if (Value.fromExpected(what, test.ok()).ok()) {
- return new Result(Value.SUCCESS, "At least one of the sub-tests did have the expected result.");
- }
- }
- return new Result(Value.FAILURE, "None of the sub-tests had the expected result.");
- }, any);
- }
-
- public static Compound any(ExpectedValue what, String description, Test... any) {
- Compound result = Compound.any(what, any);
- result.setDescription(description);
- return result;
- }
-
- public static Compound mask(ExpectedValue[] results, Test... masked) {
- return new Compound((tests) -> {
- for (int i = 0; i < results.length; ++i) {
- if (!Value.fromExpected(results[i], tests[i].ok()).ok()) {
- return new Result(Value.FAILURE, "At least one of the sub-tests did not match the result mask.");
- }
- }
- return new Result(Value.SUCCESS, "All sub-tests matched the expected mask.");
- }, masked);
- }
-
- public static Compound mask(ExpectedValue[] results, String description, Test... masked) {
- Compound result = Compound.mask(results, masked);
- result.setDescription(description);
- return result;
- }
-
- public Test[] getTests() {
- return tests;
- }
-
- @Override
- public void run() throws CardException {
- if (hasRun)
- return;
-
- for (Test test : tests) {
- test.run();
- }
- result = callback.apply(tests);
- this.hasRun = true;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-
- @Override
- public String getDescription() {
- return description;
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/TestRunner.java b/src/cz/crcs/ectester/reader/test/TestRunner.java
deleted file mode 100644
index baab6a8..0000000
--- a/src/cz/crcs/ectester/reader/test/TestRunner.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.reader.output.TestWriter;
-
-import javax.smartcardio.CardException;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class TestRunner {
- private TestSuite suite;
- private TestWriter writer;
-
- public TestRunner(TestSuite suite, TestWriter writer) {
- this.suite = suite;
- this.writer = writer;
- }
-
- public void run() throws CardException {
- writer.begin(suite);
- for (Test t : suite.getTests()) {
- if (!t.hasRun()) {
- t.run();
- writer.outputTest(t);
- }
- }
- writer.end();
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/TestSuite.java b/src/cz/crcs/ectester/reader/test/TestSuite.java
deleted file mode 100644
index f13317c..0000000
--- a/src/cz/crcs/ectester/reader/test/TestSuite.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTester;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.ec.EC_Curve;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-
-import static cz.crcs.ectester.reader.test.Result.ExpectedValue;
-import static cz.crcs.ectester.reader.test.Result.Value;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public abstract class TestSuite {
- EC_Store dataStore;
- ECTester.Config cfg;
- String name;
- String description;
- List<Test> tests = new LinkedList<>();
-
- TestSuite(EC_Store dataStore, ECTester.Config cfg, String name, String description) {
- this.dataStore = dataStore;
- this.cfg = cfg;
- this.name = name;
- this.description = description;
- }
-
- public abstract void setup(CardMngr cardManager) throws IOException;
-
- public List<Test> getTests() {
- return Collections.unmodifiableList(tests);
- }
-
- public String getName() {
- return name;
- }
-
- public String getDescription() {
- return description;
- }
-
- /**
- * @param cardManager cardManager to send APDU through
- * @param generateExpected expected result of the Generate command
- * @param ecdhExpected expected result of the ordinary ECDH command
- * @param ecdhCompressExpected expected result of ECDH with a compressed point
- * @param ecdsaExpected expected result of the ordinary ECDSA command
- * @param description compound test description
- * @return test to run
- */
- Test defaultCurveTests(CardMngr cardManager, ExpectedValue generateExpected, ExpectedValue ecdhExpected, ExpectedValue ecdhCompressExpected, ExpectedValue ecdsaExpected, String description) {
- List<Test> tests = new LinkedList<>();
-
- tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH), generateExpected));
- tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH), ecdhExpected));
- tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_COMPRESS, EC_Consts.KA_ECDH), ecdhExpected));
- tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_ONE, EC_Consts.KA_ECDH), ExpectedValue.FAILURE));
- tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_ZERO, EC_Consts.KA_ECDH), ExpectedValue.FAILURE));
- tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_MAX, EC_Consts.KA_ECDH), ExpectedValue.FAILURE));
- tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_FULLRANDOM, EC_Consts.KA_ECDH), ExpectedValue.FAILURE));
- tests.add(new Test.Simple(new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, null), ecdsaExpected));
-
- return Test.Compound.function((testArray) -> {
- Function<ExpectedValue, String> shouldHave = (expected) -> {
- switch (expected) {
- case SUCCESS:
- return "succeeded";
- case FAILURE:
- return "failed";
- case ANY:
- default:
- return "";
- }
- };
-
- for (int i = 0; i < testArray.length; ++i) {
- Test t = testArray[i];
- if (!t.ok()) {
- if (i == 0) { // generate
- return new Result(Value.FAILURE, "The generation of a key should have " + shouldHave.apply(generateExpected) + ", but it did not.");
- } else if (i == 2) { // ecdh compress
- return new Result(Value.FAILURE, "The ECDH should have " + shouldHave.apply(ecdhExpected) + ", but it did not.");
- } else if (i == 1) { // ecdh normal
- return new Result(Value.FAILURE, "The ECDH of a compressed point should have " + shouldHave.apply(ecdhCompressExpected) + ", but it did not.");
- } else if (i <= 6) { // ecdh wrong, should fail
- return new Result(Value.FAILURE, "The ECDH of a corrupted point should have failed, but it did not.");
- } else { // ecdsa
- return new Result(Value.FAILURE, "The ECDSA should have " + shouldHave.apply(ecdsaExpected) + ", but it did not.");
- }
- }
- }
- return new Result(Value.SUCCESS);
- }, description, tests.toArray(new Test[0]));
- }
-
- /**
- * @param cardManager cardManager to send APDU through
- * @param category category to test
- * @param field field to test (KeyPair.ALG_EC_FP || KeyPair.ALG_EC_F2M)
- * @param setExpected expected result of the Set (curve) command
- * @param generateExpected expected result of the Generate command
- * @param ecdhExpected expected result of the ordinary ECDH command
- * @param ecdhCompressedExpected expected result of the ECDH command with a compressed point.
- * @param ecdsaExpected expected result of the ordinary ECDSA command
- * @param description compound test description
- * @return tests to run
- */
- List<Test> defaultCategoryTests(CardMngr cardManager, String category, byte field, ExpectedValue setExpected, ExpectedValue generateExpected, ExpectedValue ecdhExpected, ExpectedValue ecdhCompressedExpected, ExpectedValue ecdsaExpected, String description) {
- List<Test> tests = new LinkedList<>();
- Map<String, EC_Curve> curves = dataStore.getObjects(EC_Curve.class, category);
- if (curves == null)
- return tests;
- for (Map.Entry<String, EC_Curve> entry : curves.entrySet()) {
- EC_Curve curve = entry.getValue();
- if (curve.getField() == field && (curve.getBits() == cfg.bits || cfg.all)) {
- tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), field), ExpectedValue.SUCCESS));
- tests.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), setExpected));
- tests.add(defaultCurveTests(cardManager, generateExpected, ecdhExpected, ecdhCompressedExpected, ecdsaExpected, description));
- tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY));
- }
- }
-
- return tests;
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java
deleted file mode 100644
index ff46feb..0000000
--- a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTester;
-import cz.crcs.ectester.reader.Util;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.ec.*;
-import cz.crcs.ectester.reader.response.Response;
-import javacard.security.KeyPair;
-
-import java.io.IOException;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import static cz.crcs.ectester.reader.test.Result.ExpectedValue;
-import static cz.crcs.ectester.reader.test.Result.Value;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class TestVectorSuite extends TestSuite {
-
- public TestVectorSuite(EC_Store dataStore, ECTester.Config cfg) {
- super(dataStore, cfg, "test", "The test-vectors suite contains a collection of test vectors which test basic ECDH correctness.");
- }
-
- @Override
- public void setup(CardMngr cardManager) throws IOException {
- /* Set original curves (secg/nist/brainpool). Set keypairs from test vectors.
- * Do ECDH both ways, export and verify that the result is correct.
- */
- Map<String, EC_KAResult> results = dataStore.getObjects(EC_KAResult.class, "test");
- for (EC_KAResult result : results.values()) {
- EC_Curve curve = dataStore.getObject(EC_Curve.class, result.getCurve());
- if (cfg.namedCurve != null && !(result.getCurve().startsWith(cfg.namedCurve) || result.getCurve().equals(cfg.namedCurve))) {
- continue;
- }
- if (curve.getBits() != cfg.bits && !cfg.all) {
- continue;
- }
- if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
- continue;
- }
- EC_Params onekey = dataStore.getObject(EC_Keypair.class, result.getOneKey());
- if (onekey == null) {
- onekey = dataStore.getObject(EC_Key.Private.class, result.getOneKey());
- }
- EC_Params otherkey = dataStore.getObject(EC_Keypair.class, result.getOtherKey());
- if (otherkey == null) {
- otherkey = dataStore.getObject(EC_Key.Public.class, result.getOtherKey());
- }
- if (onekey == null || otherkey == null) {
- throw new IOException("Test vector keys couldn't be located.");
- }
- List<Test> testVector = new LinkedList<>();
-
- testVector.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- testVector.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
- //tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS));
- testVector.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, onekey.flatten(EC_Consts.PARAMETER_S)), ExpectedValue.SUCCESS));
- testVector.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W)), ExpectedValue.SUCCESS));
- testVector.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, result.getKA()), (command, response) -> {
- Response.ECDH dh = (Response.ECDH) response;
- if (!dh.successful())
- return new Result(Value.FAILURE, "ECDH was unsuccessful.");
- if (!dh.hasSecret())
- return new Result(Value.FAILURE, "ECDH response did not contain the derived secret.");
- if (!Util.compareBytes(dh.getSecret(), 0, result.getParam(0), 0, dh.secretLength())) {
- int firstDiff = Util.diffBytes(dh.getSecret(), 0, result.getParam(0), 0, dh.secretLength());
- return new Result(Value.FAILURE, "ECDH derived secret does not match the test, first difference was at byte " + String.valueOf(firstDiff) + ".");
- }
- return new Result(Value.SUCCESS);
- }));
- tests.add(Test.Compound.all(ExpectedValue.SUCCESS, "Test vector " + result.getId(), testVector.toArray(new Test[0])));
- tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY));
-
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java b/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java
deleted file mode 100644
index e9389b4..0000000
--- a/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTester;
-import javacard.security.KeyPair;
-
-import java.io.IOException;
-
-import static cz.crcs.ectester.reader.test.Result.ExpectedValue;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class WrongCurvesSuite extends TestSuite {
-
- public WrongCurvesSuite(EC_Store dataStore, ECTester.Config cfg) {
- super(dataStore, cfg, "wrong", "The wrong curve suite tests whether the card rejects domain parameters which are not curves.");
- }
-
- @Override
- public void setup(CardMngr cardManager) throws IOException {
- /* Just do the default tests on the wrong curves.
- * These should generally fail, the curves aren't curves.
- */
- String desc = "Default tests over wrong curve params.";
- if (cfg.primeField) {
- tests.addAll(defaultCategoryTests(cardManager, cfg.testSuite, KeyPair.ALG_EC_FP, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, desc));
- }
- if (cfg.binaryField) {
- tests.addAll(defaultCategoryTests(cardManager, cfg.testSuite, KeyPair.ALG_EC_F2M, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, desc));
- }
- }
-}