From 50244cd3ff01ad997b5900883ffbc95dbba1154f Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 4 Jul 2018 17:00:05 +0200 Subject: Add supersingular curves, do some tests over supersingular and Barreto-Naehrig curves. --- .../crcs/ectester/reader/test/CardMiscSuite.java | 54 ++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/cz/crcs/ectester/reader/test/CardMiscSuite.java (limited to 'src/cz/crcs/ectester/reader/test/CardMiscSuite.java') diff --git a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java new file mode 100644 index 0000000..d969cf9 --- /dev/null +++ b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java @@ -0,0 +1,54 @@ +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.common.util.CardUtil; +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 java.util.Map; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class CardMiscSuite extends CardTestSuite { + + public CardMiscSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { + super(writer, cfg, cardManager, "miscellaneous", "Some miscellaneous tests, tries ECDH and ECDSA over supersingular curves and some Barreto-Naehrig curves with small embedding degree and CM discriminant."); + } + + @Override + protected void runTests() throws Exception { + Map ssCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "supersingular"); + Map bnCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "Barreto-Naehrig"); + + testCurves(ssCurves, "supersingular"); + + testCurves(bnCurves, "Barreto-Naehrig"); + } + + private void testCurves(Map curves, String catName) throws Exception { + for (EC_Curve curve : curves.values()) { + Test allocateFirst = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS)); + if (!allocateFirst.ok()) { + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocateFirst)); + continue; + } + + Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS); + Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.SUCCESS); + Test ka = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.SUCCESS); + Test sig = CommandTest.expect(new Command.ECDSA(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, ECTesterApplet.EXPORT_FALSE, null), Result.ExpectedValue.SUCCESS); + + doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + " " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, ka, sig)); + new Command.Cleanup(this.card).send(); + } + } +} -- cgit v1.2.3-70-g09d2 From 1bfa90811a0b4ea02d98ea7dedcfc07bec89d19c Mon Sep 17 00:00:00 2001 From: J08nY Date: Thu, 5 Jul 2018 19:30:16 +0200 Subject: Add ability to skip tests/run only a part of a test suite. --- .../ectester/common/output/BaseTextTestWriter.java | 19 ++++++----- .../ectester/common/output/BaseXMLTestWriter.java | 4 +-- .../ectester/common/output/BaseYAMLTestWriter.java | 4 +-- .../crcs/ectester/common/output/TeeTestWriter.java | 8 ++--- src/cz/crcs/ectester/common/output/TestWriter.java | 9 +++--- src/cz/crcs/ectester/common/test/TestSuite.java | 22 +++++++++++-- src/cz/crcs/ectester/reader/CardMngr.java | 1 - src/cz/crcs/ectester/reader/ECTesterReader.java | 37 +++++++++++++++++++--- .../ectester/reader/test/CardCofactorSuite.java | 4 +-- .../ectester/reader/test/CardCompositeSuite.java | 5 +-- .../ectester/reader/test/CardCompressionSuite.java | 2 +- .../ectester/reader/test/CardDefaultSuite.java | 4 +-- .../ectester/reader/test/CardDegenerateSuite.java | 4 +-- .../ectester/reader/test/CardInvalidSuite.java | 4 +-- .../crcs/ectester/reader/test/CardMiscSuite.java | 4 +-- .../ectester/reader/test/CardTestVectorSuite.java | 2 +- .../crcs/ectester/reader/test/CardTwistSuite.java | 4 +-- .../crcs/ectester/reader/test/CardWrongSuite.java | 1 - 18 files changed, 91 insertions(+), 47 deletions(-) (limited to 'src/cz/crcs/ectester/reader/test/CardMiscSuite.java') diff --git a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java index c3ce640..eef767b 100644 --- a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java +++ b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java @@ -38,20 +38,18 @@ public abstract class BaseTextTestWriter implements TestWriter { } /** - * * @param t * @return */ protected abstract String testableString(Testable t); /** - * * @param suite * @return */ protected abstract String deviceString(TestSuite suite); - private String testString(Test t, String prefix) { + private String testString(Test t, String prefix, int index) { boolean compound = t instanceof CompoundTest; Result result = t.getResult(); @@ -61,7 +59,8 @@ public abstract class BaseTextTestWriter implements TestWriter { out.append(compound ? "┳ " : "━ "); int width = BASE_WIDTH - (prefix.length() + out.length()); String widthSpec = "%-" + String.valueOf(width) + "s"; - out.append(String.format(widthSpec, t.getDescription())); + String desc = ((prefix.equals("")) ? "(" + index + ") " : "") + t.getDescription(); + out.append(String.format(widthSpec, desc)); out.append(" ┃ "); Colors.Foreground valueColor; if (result.getValue().ok()) { @@ -82,10 +81,10 @@ public abstract class BaseTextTestWriter implements TestWriter { for (int i = 0; i < tests.length; ++i) { if (i == tests.length - 1) { out.append(prefix).append(" ┗ "); - out.append(testString(tests[i], prefix + " ")); + out.append(testString(tests[i], prefix + " ", index)); } else { out.append(prefix).append(" ┣ "); - out.append(testString(tests[i], prefix + " ┃ ")); + out.append(testString(tests[i], prefix + " ┃ ", index)); } if (i != tests.length - 1) { @@ -100,10 +99,10 @@ public abstract class BaseTextTestWriter implements TestWriter { } @Override - public void outputTest(Test t) { + public void outputTest(Test t, int index) { if (!t.hasRun()) return; - output.println(testString(t, "")); + output.println(testString(t, "", index)); output.flush(); } @@ -122,8 +121,8 @@ public abstract class BaseTextTestWriter implements TestWriter { } @Override - public void outputError(Test t, Throwable cause) { - output.println(testString(t, "")); + public void outputError(Test t, Throwable cause, int index) { + output.println(testString(t, "", index)); output.print(errorString(cause)); output.flush(); } diff --git a/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java b/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java index 4e0c236..b666e08 100644 --- a/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java +++ b/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java @@ -112,14 +112,14 @@ public abstract class BaseXMLTestWriter implements TestWriter { } @Override - public void outputTest(Test t) { + public void outputTest(Test t, int index) { if (!t.hasRun()) return; tests.appendChild(testElement(t)); } @Override - public void outputError(Test t, Throwable cause) { + public void outputError(Test t, Throwable cause, int index) { tests.appendChild(testElement(t)); } diff --git a/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java b/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java index cab2632..e3c7952 100644 --- a/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java +++ b/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java @@ -89,14 +89,14 @@ public abstract class BaseYAMLTestWriter implements TestWriter { } @Override - public void outputTest(Test t) { + public void outputTest(Test t, int index) { if (!t.hasRun()) return; tests.add(testObject(t)); } @Override - public void outputError(Test t, Throwable cause) { + public void outputError(Test t, Throwable cause, int index) { tests.add(testObject(t)); } diff --git a/src/cz/crcs/ectester/common/output/TeeTestWriter.java b/src/cz/crcs/ectester/common/output/TeeTestWriter.java index 35912fa..58a0a15 100644 --- a/src/cz/crcs/ectester/common/output/TeeTestWriter.java +++ b/src/cz/crcs/ectester/common/output/TeeTestWriter.java @@ -21,16 +21,16 @@ public class TeeTestWriter implements TestWriter { } @Override - public void outputTest(Test t) { + public void outputTest(Test t, int index) { for (TestWriter writer : writers) { - writer.outputTest(t); + writer.outputTest(t, index); } } @Override - public void outputError(Test t, Throwable cause) { + public void outputError(Test t, Throwable cause, int index) { for (TestWriter writer : writers) { - writer.outputError(t, cause); + writer.outputError(t, cause, index); } } diff --git a/src/cz/crcs/ectester/common/output/TestWriter.java b/src/cz/crcs/ectester/common/output/TestWriter.java index 7de23a5..eb95804 100644 --- a/src/cz/crcs/ectester/common/output/TestWriter.java +++ b/src/cz/crcs/ectester/common/output/TestWriter.java @@ -21,15 +21,16 @@ public interface TestWriter { /** * * @param t + * @param index */ - void outputTest(Test t); + void outputTest(Test t, int index); /** - * - * @param t + * @param t * @param cause + * @param index */ - void outputError(Test t, Throwable cause); + void outputError(Test t, Throwable cause, int index); /** * diff --git a/src/cz/crcs/ectester/common/test/TestSuite.java b/src/cz/crcs/ectester/common/test/TestSuite.java index 5f26f52..b12680a 100644 --- a/src/cz/crcs/ectester/common/test/TestSuite.java +++ b/src/cz/crcs/ectester/common/test/TestSuite.java @@ -10,6 +10,9 @@ public abstract class TestSuite { protected String[] description; private TestWriter writer; private Test running; + private int ran = 0; + private int runFrom = 0; + private int runTo = -1; public TestSuite(TestWriter writer, String name, String... description) { this.writer = writer; @@ -21,11 +24,21 @@ public abstract class TestSuite { * Run the TestSuite. */ public void run() { + run(0); + } + + public void run(int from) { + run(from, -1); + } + + public void run(int from, int to) { + this.runFrom = from; + this.runTo = to; writer.begin(this); try { runTests(); } catch (TestException e) { - writer.outputError(running, e); + writer.outputError(running, e, ran); } catch (Exception e) { writer.end(); throw new TestSuiteException(e); @@ -55,8 +68,11 @@ public abstract class TestSuite { * @throws TestException */ protected T doTest(T t) { - runTest(t); - writer.outputTest(t); + if (ran >= runFrom && (runTo < 0 || ran <= runTo)) { + runTest(t); + writer.outputTest(t, ran); + } + ran++; return t; } diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java index 637be56..921a9c8 100644 --- a/src/cz/crcs/ectester/reader/CardMngr.java +++ b/src/cz/crcs/ectester/reader/CardMngr.java @@ -1,6 +1,5 @@ package cz.crcs.ectester.reader; -import com.licel.jcardsim.io.CAD; import com.licel.jcardsim.io.JavaxSmartCardInterface; import cz.crcs.ectester.common.util.ByteUtil; import javacard.framework.AID; diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 89cfca1..2b78cb0 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -272,8 +272,8 @@ public class ECTesterReader { actions.addOption(Option.builder("h").longOpt("help").desc("Print help.").build()); actions.addOption(Option.builder("ln").longOpt("list-named").desc("Print the list of supported named curves and keys.").hasArg().argName("what").optionalArg(true).build()); actions.addOption(Option.builder("e").longOpt("export").desc("Export the defaut curve parameters of the card(if any).").build()); - actions.addOption(Option.builder("g").longOpt("generate").desc("Generate [amount] of EC keys.").hasArg().argName("amount").optionalArg(true).build()); - actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. [test_suite]:\n- default:\n- compression:\n- invalid:\n- twist:\n- degenerate:\n- cofactor:\n- wrong:\n- composite:\n- test-vectors:\n- edge-cases:\n- miscellaneous:").hasArg().argName("test_suite").optionalArg(true).build()); + actions.addOption(Option.builder("g").longOpt("generate").desc("Generate of EC keys.").hasArg().argName("amount").optionalArg(true).build()); + actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. Optionally specify a test number to run only a part of a test suite. :\n- default:\n- compression:\n- invalid:\n- twist:\n- degenerate:\n- cofactor:\n- wrong:\n- composite:\n- test-vectors:\n- edge-cases:\n- miscellaneous:").hasArg().argName("test_suite[:from[:to]]").optionalArg(true).build()); actions.addOption(Option.builder("dh").longOpt("ecdh").desc("Do EC KeyAgreement (ECDH...), [count] times.").hasArg().argName("count").optionalArg(true).build()); actions.addOption(Option.builder("dsa").longOpt("ecdsa").desc("Sign data with ECDSA, [count] times.").hasArg().argName("count").optionalArg(true).build()); actions.addOption(Option.builder("ls").longOpt("list-suites").desc("List supported test suites.").build()); @@ -503,7 +503,7 @@ public class ECTesterReader { break; } - suite.run(); + suite.run(cfg.testFrom, cfg.testTo); } /** @@ -702,6 +702,8 @@ public class ECTesterReader { //Action-related options public String listNamed; public String testSuite; + public int testFrom; + public int testTo; public int generateAmount; public int ECKACount; public byte ECKAType = KeyAgreement_ALG_EC_SVDP_DH; @@ -827,7 +829,34 @@ public class ECTesterReader { primeField = true; } - testSuite = cli.getOptionValue("test", "default").toLowerCase(); + String suiteOpt = cli.getOptionValue("test", "default").toLowerCase(); + if (suiteOpt.contains(":")) { + String[] parts = suiteOpt.split(":"); + testSuite = parts[0]; + try { + testFrom = Integer.parseInt(parts[1]); + } catch (NumberFormatException nfe) { + System.err.println("Invalid test from number: " + parts[1] + "."); + return false; + } + if (parts.length == 3) { + try { + testTo = Integer.parseInt(parts[2]); + } catch (NumberFormatException nfe) { + System.err.println("Invalid test to number: " + parts[2] + "."); + return false; + } + } else if (parts.length != 2) { + System.err.println("Invalid test suite selection."); + return false; + } else { + testTo = -1; + } + } else { + testSuite = suiteOpt; + testFrom = 0; + testTo = -1; + } String[] tests = new String[]{"default", "composite", "compression", "invalid", "degenerate", "test-vectors", "wrong", "twist", "cofactor", "edge-cases", "miscellaneous"}; if (!Arrays.asList(tests).contains(testSuite)) { System.err.println(Colors.error("Unknown test suite " + testSuite + ". Should be one of: " + Arrays.toString(tests))); diff --git a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java index 2ecf4a2..762dc88 100644 --- a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java @@ -65,9 +65,9 @@ public class CardCofactorSuite extends CardTestSuite { Test ecdsa = CompoundTest.all(ExpectedValue.SUCCESS, "Verify random ECDSA signature by public points on non-generator subgroup.", ecdsaTests.toArray(new Test[0])); Test tests = CompoundTest.all(ExpectedValue.SUCCESS, "Perform ECDH and ECDSA tests.", ecdh, ecdsa); + Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.SUCCESS); - doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Cofactor test of " + curve.getId() + ".", prepare, tests)); - new Command.Cleanup(this.card).send(); + doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Cofactor test of " + curve.getId() + ".", prepare, tests, cleanup)); } } } diff --git a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java index a693ac7..b80a0e3 100644 --- a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java @@ -96,8 +96,9 @@ public class CardCompositeSuite extends CardTestSuite { } else { description = testName + " test of " + curve.getId() + "."; } - doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, description, allocate, set, generate, ecdh)); - new Command.Cleanup(this.card).send(); + Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.SUCCESS); + + doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, description, allocate, set, generate, ecdh, cleanup)); } } diff --git a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java index 35cfd1d..19c452c 100644 --- a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java @@ -112,9 +112,9 @@ public class CardCompressionSuite extends CardTestSuite { } } compressionTests.addAll(kaTests); + compressionTests.add(CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS)); doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Compression test of " + spec + ".", compressionTests.toArray(new Test[0]))); - 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 index 4480962..554003b 100644 --- a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java @@ -126,10 +126,10 @@ public class CardDefaultSuite extends CardTestSuite { } Test signTest = runTest(CompoundTest.any(ExpectedValue.SUCCESS, "Signature tests.", signTests.toArray(new Test[0]))); supportTests.add(signTest); + supportTests.add(CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS)); - ExpectedValue[] testExpects = {ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS}; + ExpectedValue[] testExpects = {ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.ANY}; doTest(CompoundTest.mask(testExpects, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(field) + " support.", supportTests.toArray(new Test[0]))); - new Command.Cleanup(this.card).send(); } } } diff --git a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java index 7483b2b..c3cf51c 100644 --- a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java @@ -47,9 +47,9 @@ public class CardDegenerateSuite extends CardTestSuite { ecdhTests.add(CommandTest.expect(ecdhCommand, Result.ExpectedValue.FAILURE, "Card correctly rejected point on degenerate curve.", "Card incorrectly accepted point on degenerate curve.")); } Test ecdh = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH with degenerate public points", ecdhTests.toArray(new Test[0])); + Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS); - doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId(), prepare, ecdh)); - new Command.Cleanup(this.card).send(); + doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId(), prepare, ecdh, cleanup)); } } } diff --git a/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java b/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java index 2543027..60afe75 100644 --- a/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java @@ -67,9 +67,9 @@ public class CardInvalidSuite extends CardTestSuite { Test ecdsa = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Verify random ECDSA signature by invalid public points", ecdsaTests.toArray(new Test[0])); Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Test ECDH and ECDSA with points on invalid curves.", ecdh, ecdsa); + Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.SUCCESS); - doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), prepare, tests)); - new Command.Cleanup(this.card).send(); + doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), prepare, tests, cleanup)); } } } diff --git a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java index d969cf9..5dcf727 100644 --- a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java @@ -46,9 +46,9 @@ public class CardMiscSuite extends CardTestSuite { Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.SUCCESS); Test ka = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.SUCCESS); Test sig = CommandTest.expect(new Command.ECDSA(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, ECTesterApplet.EXPORT_FALSE, null), Result.ExpectedValue.SUCCESS); + Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS); - doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + " " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, ka, sig)); - new Command.Cleanup(this.card).send(); + doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + " " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, ka, sig, cleanup)); } } } diff --git a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java index 9d39525..9a39a72 100644 --- a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java @@ -69,8 +69,8 @@ public class CardTestVectorSuite extends CardTestSuite { return new Result(Value.SUCCESS); } })); + testVector.add(CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.SUCCESS)); doTest(CompoundTest.greedyAll(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/CardTwistSuite.java b/src/cz/crcs/ectester/reader/test/CardTwistSuite.java index 46da415..e7ea436 100644 --- a/src/cz/crcs/ectester/reader/test/CardTwistSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardTwistSuite.java @@ -61,9 +61,9 @@ public class CardTwistSuite extends CardTestSuite { Test ecdsa = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Verify random ECDSA signature by public points on twist", ecdsaTests.toArray(new Test[0])); Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, ecdh, ecdsa); + Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS); - doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId(), prepare, tests)); - new Command.Cleanup(this.card).send(); + doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId(), prepare, tests, cleanup)); } } } diff --git a/src/cz/crcs/ectester/reader/test/CardWrongSuite.java b/src/cz/crcs/ectester/reader/test/CardWrongSuite.java index 6c0d5f5..2057093 100644 --- a/src/cz/crcs/ectester/reader/test/CardWrongSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardWrongSuite.java @@ -129,7 +129,6 @@ public class CardWrongSuite extends CardTestSuite { Test wrongR = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted R parameter.", primeWrongR, nonprimeWrongR); - doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(KeyPair.ALG_EC_FP), setup, wrongPrime, resetSetup, wrongG, resetSetup.clone(), wrongR, resetSetup.clone())); } -- cgit v1.2.3-70-g09d2 From ed484c16c74f8d4f1e7c211f9583d2e675abae79 Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 18 Jul 2018 15:48:37 +0200 Subject: Test anomalous curves as well in misc test suite. --- docs/LIBS.md | 62 +++++++++++----------- .../crcs/ectester/reader/test/CardMiscSuite.java | 22 ++++---- .../ectester/standalone/libs/NativeECLibrary.java | 3 +- 3 files changed, 45 insertions(+), 42 deletions(-) (limited to 'src/cz/crcs/ectester/reader/test/CardMiscSuite.java') diff --git a/docs/LIBS.md b/docs/LIBS.md index 903aef4..bfe20cd 100644 --- a/docs/LIBS.md +++ b/docs/LIBS.md @@ -9,50 +9,50 @@ Popular libraries with at least some ECC support: - [OpenSSL (FIPS mode)](https://www.openssl.org/docs/fipsnotes.html) - [Microsoft CNG](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376210(v=vs.85).aspx) - [Microsoft .NET crypto](https://docs.microsoft.com/en-us/dotnet/standard/security/cryptography-model) - + # Supported libraries - [BouncyCastle](https://bouncycastle.org/java.html) - Java - Works with the short Weierstrass curve model. - Works with coordinates: - - Affine - - Projective(Homogenous) - - Jacobian - - Jacobian-Chudnovsky - - Jacobian-Modified - - Lambda-Affine? - - Lambda-Projective? - - Skewed? + - Affine + - Projective(Homogenous) + - Jacobian + - Jacobian-Chudnovsky + - Jacobian-Modified + - Lambda-Affine? + - Lambda-Projective? + - Skewed? - Multiple scalar multiplication algorithms implemented and used: - - Double-and-add always (DoubleAddMultiplier) - - Fixed point comb (FixedPointCombMultiplier) - - GLV (Gallant-Lambert-Vanstone) using endomorphisms (GLVMultiplier): Faster point multiplication on elliptic curves with efficient endomorphisms. <-- default, if available - - Binary NAF right-to-left multiplication(mixed coordinates) (MixedNafR2LMultiplier) - - Montgomery ladder (MontgomeryLadderMultiplier) - - Binary NAF right-to-left multiplication (NafR2LMultiplier) - - Binary NAF left-to-right multiplication (NafL2RMultiplier) - - Double-and-add reference implementation (ReferenceMultiplier) - - Window NAF left-to-right multiplication (WNafL2RMultiplier) <-- default - - Window Tau-NAF multiplication (WTauNafMultiplier): Improved Algorithms for Arithmetic on Anomalous Binary Curves - - Zeroless signed digit binary right-to-left multiplication (ZSignedDigitR2LMultiplier) - - Zeroless signed digit binary left-to-right multiplication (ZSignedDigitL2RMultiplier) + - Double-and-add always (DoubleAddMultiplier) + - Fixed point comb (FixedPointCombMultiplier) + - GLV (Gallant-Lambert-Vanstone) using endomorphisms (GLVMultiplier): Faster point multiplication on elliptic curves with efficient endomorphisms. <-- default, if available + - Binary NAF right-to-left multiplication(mixed coordinates) (MixedNafR2LMultiplier) + - Montgomery ladder (MontgomeryLadderMultiplier) + - Binary NAF right-to-left multiplication (NafR2LMultiplier) + - Binary NAF left-to-right multiplication (NafL2RMultiplier) + - Double-and-add reference implementation (ReferenceMultiplier) + - Window NAF left-to-right multiplication (WNafL2RMultiplier) <-- default + - Window Tau-NAF multiplication (WTauNafMultiplier): Improved Algorithms for Arithmetic on Anomalous Binary Curves + - Zeroless signed digit binary right-to-left multiplication (ZSignedDigitR2LMultiplier) + - Zeroless signed digit binary left-to-right multiplication (ZSignedDigitL2RMultiplier) - Has custom field and point arithmetic for: - - Curve25519 (transformed into short Weierstrass model) - - SMP2 curves - - SECG curves + - Curve25519 (transformed into short Weierstrass model) + - SMP2 curves + - SECG curves - [Sun EC](https://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html#SunEC) - Java + C - Uses the short Weierstrass curve model. - For prime field curves: - - Uses 5-bit window NAF, Uses mixed Modified-Jacobian coordinates + - Uses 5-bit window NAF, Uses mixed Modified-Jacobian coordinates for doubling and Chudnovsky Jacobian coordinates for additions (ecp_jm.c). From: Brown, Hankerson, Lopez, Menezes: Software Implementation of the NIST Elliptic Curves Over Prime Fields. - - Contains an implementation of scalar multiplication with 4-bit sliding window, using Jacobian coordinates (ecp_jac.c) - - Contains an implementation of IEEE P1363 algorithm A.10.3 using affine coordinates (ecp_aff.c) + - Contains an implementation of scalar multiplication with 4-bit sliding window, using Jacobian coordinates (ecp_jac.c) + - Contains an implementation of IEEE P1363 algorithm A.10.3 using affine coordinates (ecp_aff.c) - For binary field curves: - - Uses Lopez-Dahab (Montgomery) ladder, XZ coordinates (ec2_mont.c): Fast multiplication on elliptic curves over GF(2^m) without precomputation (Algorithm 2P) - - Contains an implementation of IEEE P1363 algorithm A.10.3 using affine coordinates (ec2_aff.c) + - Uses Lopez-Dahab (Montgomery) ladder, XZ coordinates (ec2_mont.c): Fast multiplication on elliptic curves over GF(2^m) without precomputation (Algorithm 2P) + - Contains an implementation of IEEE P1363 algorithm A.10.3 using affine coordinates (ec2_aff.c) - Has some custom arithmetic for some of the NIST primes. - [Botan](https://botan.randombit.net/) - C++ @@ -68,6 +68,6 @@ Popular libraries with at least some ECC support: - [Crypto++](https://cryptopp.com/) - C++ - For prime field curves: - - Uses projective coordinates and sliding window scalar multiplication algorithm. + - Uses projective coordinates and sliding window scalar multiplication algorithm. - For binary field curves: - - Uses affine coordinates and sliding window scalar multiplication algorithm. \ No newline at end of file + - Uses affine coordinates and sliding window scalar multiplication algorithm. \ No newline at end of file diff --git a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java index 5dcf727..487fc6a 100644 --- a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java @@ -21,34 +21,36 @@ import java.util.Map; public class CardMiscSuite extends CardTestSuite { public CardMiscSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { - super(writer, cfg, cardManager, "miscellaneous", "Some miscellaneous tests, tries ECDH and ECDSA over supersingular curves and some Barreto-Naehrig curves with small embedding degree and CM discriminant."); + super(writer, cfg, cardManager, "miscellaneous", "Some miscellaneous tests, tries ECDH and ECDSA over supersingular curves, anomalous curves and some Barreto-Naehrig curves with small embedding degree and CM discriminant."); } @Override protected void runTests() throws Exception { + Map anCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "anomalous"); Map ssCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "supersingular"); Map bnCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "Barreto-Naehrig"); - testCurves(ssCurves, "supersingular"); - - testCurves(bnCurves, "Barreto-Naehrig"); + testCurves(anCurves, "anomalous", Result.ExpectedValue.FAILURE); + testCurves(ssCurves, "supersingular", Result.ExpectedValue.FAILURE); + testCurves(bnCurves, "Barreto-Naehrig", Result.ExpectedValue.ANY); } - private void testCurves(Map curves, String catName) throws Exception { + private void testCurves(Map curves, String catName, Result.ExpectedValue expected) throws Exception { for (EC_Curve curve : curves.values()) { Test allocateFirst = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS)); if (!allocateFirst.ok()) { - doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocateFirst)); + doTest(CompoundTest.all(Result.ExpectedValue.FAILURE, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocateFirst)); continue; } Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS); - Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.SUCCESS); - Test ka = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.SUCCESS); - Test sig = CommandTest.expect(new Command.ECDSA(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, ECTesterApplet.EXPORT_FALSE, null), Result.ExpectedValue.SUCCESS); + Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.ANY); + Test ka = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), expected); + Test sig = CommandTest.expect(new Command.ECDSA(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, ECTesterApplet.EXPORT_FALSE, null), expected); + Test perform = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH and ECDSA", ka, sig); Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS); - doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + " " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, ka, sig, cleanup)); + doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + " " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform, cleanup)); } } } diff --git a/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java index 0a420a1..03a088b 100644 --- a/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java +++ b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java @@ -110,7 +110,8 @@ public abstract class NativeECLibrary extends ProviderECLibrary { provider = createProvider(); return super.initialize(); - } catch (IOException | UnsatisfiedLinkError ignored) { + } catch (IOException | UnsatisfiedLinkError ex) { + System.err.println(ex.getMessage()); } return false; } -- cgit v1.2.3-70-g09d2 From c04d4fdc26f7483beb4e56e838f9ba0c2e81560b Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 22 Jul 2018 13:15:21 +0200 Subject: Add option for cleanup. --- src/cz/crcs/ectester/reader/ECTesterReader.java | 33 +++++++--- .../ectester/reader/test/CardCofactorSuite.java | 8 ++- .../ectester/reader/test/CardCompositeSuite.java | 10 +-- .../ectester/reader/test/CardCompressionSuite.java | 4 +- .../ectester/reader/test/CardDefaultSuite.java | 12 +++- .../ectester/reader/test/CardDegenerateSuite.java | 8 ++- .../ectester/reader/test/CardEdgeCasesSuite.java | 73 +++++++++++++++++++++- .../ectester/reader/test/CardInvalidSuite.java | 14 +++-- .../crcs/ectester/reader/test/CardMiscSuite.java | 8 ++- .../ectester/reader/test/CardTestVectorSuite.java | 9 ++- .../crcs/ectester/reader/test/CardTwistSuite.java | 14 +++-- .../crcs/ectester/reader/test/CardWrongSuite.java | 19 +++++- .../ectester/standalone/output/TextTestWriter.java | 2 +- 13 files changed, 175 insertions(+), 39 deletions(-) (limited to 'src/cz/crcs/ectester/reader/test/CardMiscSuite.java') diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 325f3a8..e8863dc 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -89,10 +89,12 @@ public class ECTesterReader { Manifest manifest = new Manifest(url.openStream()); String commit = manifest.getMainAttributes().getValue("Git-Commit"); GIT_COMMIT = (commit == null) ? "" : "(git " + commit + ")"; - } catch (Exception ignored) { } + } catch (Exception ignored) { + } DESCRIPTION = "ECTesterReader " + VERSION + GIT_COMMIT + ", a javacard Elliptic Curve Cryptography support tester/utility."; - CLI_HEADER = "\n" + DESCRIPTION + "\n\n";; + CLI_HEADER = "\n" + DESCRIPTION + "\n\n"; + ; } private void run(String[] args) { @@ -260,6 +262,7 @@ public class ECTesterReader { * -l / --log [log_file] * * -f / --fresh + * --cleanup * -s / --simulate * -y / --yes * -ka/ --ka-type @@ -316,6 +319,7 @@ public class ECTesterReader { opts.addOption(Option.builder().longOpt("format").desc("Output format to use. One of: text,yml,xml.").hasArg().argName("format").build()); opts.addOption(Option.builder("f").longOpt("fresh").desc("Generate fresh keys (set domain parameters before every generation).").build()); + opts.addOption(Option.builder().longOpt("cleanup").desc("Send the cleanup command trigerring 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()); @@ -376,6 +380,10 @@ public class ECTesterReader { for (Response r : sent) { respWriter.outputResponse(r); } + if (cfg.cleanup) { + Response cleanup = new Command.Cleanup(cardManager).send(); + respWriter.outputResponse(cleanup); + } EC_Params exported = new EC_Params(domain, export.getParams()); @@ -432,8 +440,10 @@ public class ECTesterReader { keysFile.flush(); generated++; } - Response cleanup = new Command.Cleanup(cardManager).send(); - respWriter.outputResponse(cleanup); + if (cfg.cleanup) { + Response cleanup = new Command.Cleanup(cardManager).send(); + respWriter.outputResponse(cleanup); + } keysFile.close(); } @@ -573,8 +583,10 @@ public class ECTesterReader { ++done; } - Response cleanup = new Command.Cleanup(cardManager).send(); - respWriter.outputResponse(cleanup); + if (cfg.cleanup) { + Response cleanup = new Command.Cleanup(cardManager).send(); + respWriter.outputResponse(cleanup); + } if (out != null) out.close(); @@ -646,9 +658,10 @@ public class ECTesterReader { ++done; } - Response cleanup = new Command.Cleanup(cardManager).send(); - respWriter.outputResponse(cleanup); - + if (cfg.cleanup) { + Response cleanup = new Command.Cleanup(cardManager).send(); + respWriter.outputResponse(cleanup); + } if (out != null) out.close(); } @@ -691,6 +704,7 @@ public class ECTesterReader { public String input; public String[] outputs; public boolean fresh = false; + public boolean cleanup = false; public boolean simulate = false; public boolean yes = false; public String format; @@ -745,6 +759,7 @@ public class ECTesterReader { input = cli.getOptionValue("input"); outputs = cli.getOptionValues("output"); fresh = cli.hasOption("fresh"); + cleanup = cli.hasOption("cleanup"); simulate = cli.hasOption("simulate"); yes = cli.hasOption("yes"); color = cli.hasOption("color"); diff --git a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java index 762dc88..39024b8 100644 --- a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java @@ -65,9 +65,13 @@ public class CardCofactorSuite extends CardTestSuite { Test ecdsa = CompoundTest.all(ExpectedValue.SUCCESS, "Verify random ECDSA signature by public points on non-generator subgroup.", ecdsaTests.toArray(new Test[0])); Test tests = CompoundTest.all(ExpectedValue.SUCCESS, "Perform ECDH and ECDSA tests.", ecdh, ecdsa); - Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.SUCCESS); - doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Cofactor test of " + curve.getId() + ".", prepare, tests, cleanup)); + if (cfg.cleanup) { + Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.SUCCESS); + doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Cofactor test of " + curve.getId() + ".", prepare, tests, cleanup)); + } else { + doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Cofactor test of " + curve.getId() + ".", prepare, tests)); + } } } } diff --git a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java index 5de8608..ec56901 100644 --- a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java @@ -55,7 +55,6 @@ public class CardCompositeSuite extends CardTestSuite { tests.add(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ", " + key.getDesc(), ecdh)); } doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ".", tests.toArray(new Test[0]))); - new Command.Cleanup(this.card).send(); } @@ -105,9 +104,12 @@ public class CardCompositeSuite extends CardTestSuite { } else { description = testName + " test of " + curve.getId() + "."; } - Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.SUCCESS); - - doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, description, allocate, set, generate, ecdh, cleanup)); + if (cfg.cleanup) { + Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.SUCCESS); + doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, description, allocate, set, generate, ecdh, cleanup)); + } else { + doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, description, allocate, set, generate, ecdh)); + } } } diff --git a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java index 19c452c..5e8f600 100644 --- a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java @@ -112,7 +112,9 @@ public class CardCompressionSuite extends CardTestSuite { } } compressionTests.addAll(kaTests); - compressionTests.add(CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS)); + if (cfg.cleanup) { + compressionTests.add(CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS)); + } doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Compression test of " + spec + ".", compressionTests.toArray(new Test[0]))); } diff --git a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java index 554003b..fa9bfd0 100644 --- a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java @@ -16,6 +16,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Random; import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static cz.crcs.ectester.common.test.Result.ExpectedValue; import static cz.crcs.ectester.common.test.Result.Value; @@ -126,10 +128,14 @@ public class CardDefaultSuite extends CardTestSuite { } Test signTest = runTest(CompoundTest.any(ExpectedValue.SUCCESS, "Signature tests.", signTests.toArray(new Test[0]))); supportTests.add(signTest); - supportTests.add(CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS)); + ExpectedValue[] testExpects = {ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS}; + List expects = Stream.of(testExpects).collect(Collectors.toList()); + if (cfg.cleanup) { + supportTests.add(CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS)); + expects.add(ExpectedValue.ANY); + } - ExpectedValue[] testExpects = {ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.ANY}; - doTest(CompoundTest.mask(testExpects, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(field) + " support.", supportTests.toArray(new Test[0]))); + doTest(CompoundTest.mask(expects.toArray(new ExpectedValue[0]), "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(field) + " support.", supportTests.toArray(new Test[0]))); } } } diff --git a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java index c3cf51c..064c6cb 100644 --- a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java @@ -47,9 +47,13 @@ public class CardDegenerateSuite extends CardTestSuite { ecdhTests.add(CommandTest.expect(ecdhCommand, Result.ExpectedValue.FAILURE, "Card correctly rejected point on degenerate curve.", "Card incorrectly accepted point on degenerate curve.")); } Test ecdh = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH with degenerate public points", ecdhTests.toArray(new Test[0])); - Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS); + if (cfg.cleanup) { + Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS); + doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId(), prepare, ecdh, cleanup)); + } else { + doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId(), prepare, ecdh)); + } - doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId(), prepare, ecdh, cleanup)); } } } diff --git a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java index 211dc58..efc79a9 100644 --- a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java @@ -5,30 +5,37 @@ import cz.crcs.ectester.applet.EC_Consts; import cz.crcs.ectester.common.ec.EC_Curve; import cz.crcs.ectester.common.ec.EC_KAResult; import cz.crcs.ectester.common.ec.EC_Key; +import cz.crcs.ectester.common.ec.EC_Params; 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.test.TestCallback; import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.common.util.ECUtil; 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.CryptoException; +import javacard.security.KeyPair; +import java.math.BigInteger; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Random; +import java.util.stream.Collectors; /** * @author Jan Jancar johny@neuromancer.sk */ public class CardEdgeCasesSuite extends CardTestSuite { public CardEdgeCasesSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { - 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 ECDH.", - "Some of the data is from the google/Wycheproof project. Tests include CVE-2017-10176 and CVE-2017-8932."); + 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.", + "Various edge private key values are also tested."); } @Override @@ -104,5 +111,67 @@ public class CardEdgeCasesSuite extends CardTestSuite { } doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, description, groupTests.toArray(new Test[0]))); } + + // test: + // - s = 0, s = 1 + // - s < r, s = r, s > r + // - s = r - 1, s = r + 1 + // - s = kr + 1, s = kr, s = kr - 1 + Map curveMap = EC_Store.getInstance().getObjects(EC_Curve.class, "secg"); + List curves = curveMap.entrySet().stream().filter((e) -> e.getKey().endsWith("r1")).map(Map.Entry::getValue).collect(Collectors.toList()); + Random rand = new Random(); + for (EC_Curve curve : curves) { + Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, KeyPair.ALG_EC_FP), Result.ExpectedValue.SUCCESS)); + if (!key.ok()) { + doTest(CompoundTest.all(Result.ExpectedValue.FAILURE, "No support for " + curve.getBits() + "b ALG_EC_FP.", key)); + continue; + } + Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS); + Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS); + Test setup = CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set, generate); + + Test zeroS = CommandTest.expect(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, EC_Consts.TRANSFORMATION_ZERO), Result.ExpectedValue.FAILURE); + Test oneS = CommandTest.expect(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, EC_Consts.TRANSFORMATION_ONE), Result.ExpectedValue.FAILURE); + + byte[] r = curve.getParam(EC_Consts.PARAMETER_R)[0]; + BigInteger R = new BigInteger(1, r); + BigInteger smaller = new BigInteger(curve.getBits(), rand).mod(R); + BigInteger larger; + do { + larger = new BigInteger(curve.getBits(), rand); + } while (larger.compareTo(R) <= 0); + + EC_Params smallerParams = makeParams(smaller, curve.getBits()); + Test smallerS = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, smallerParams.getParams(), smallerParams.flatten()), Result.ExpectedValue.FAILURE); + + EC_Params exactParams = makeParams(R, curve.getBits()); + Test exactS = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, exactParams.getParams(), exactParams.flatten()), Result.ExpectedValue.FAILURE); + + EC_Params largerParams = makeParams(larger, curve.getBits()); + Test largerS = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, largerParams.getParams(), largerParams.flatten()), Result.ExpectedValue.FAILURE); + + BigInteger rm1 = R.subtract(BigInteger.ONE); + BigInteger rp1 = R.add(BigInteger.ONE); + + EC_Params rm1Params = makeParams(rm1, curve.getBits()); + Test rm1S = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, rm1Params.getParams(), rm1Params.flatten()), Result.ExpectedValue.FAILURE); + + EC_Params rp1Params = makeParams(rp1, curve.getBits()); + Test rp1S = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, rp1Params.getParams(), rp1Params.flatten()), Result.ExpectedValue.FAILURE); + + byte[] k = curve.getParam(EC_Consts.PARAMETER_K)[0]; + BigInteger K = new BigInteger(1, k); + BigInteger kr = K.multiply(R); + BigInteger krp1 = kr.add(BigInteger.ONE); + BigInteger krm1 = kr.subtract(BigInteger.ONE); + } + } + + private EC_Params makeParams(BigInteger s, int keylen) { + return makeParams(ECUtil.toByteArray(s, keylen)); + } + + private EC_Params makeParams(byte[] s) { + return new EC_Params(EC_Consts.PARAMETER_S, new byte[][]{s}); } } diff --git a/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java b/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java index 60afe75..59a427f 100644 --- a/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java @@ -13,7 +13,10 @@ import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.command.Command; -import java.util.*; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; import static cz.crcs.ectester.common.test.Result.ExpectedValue; @@ -67,9 +70,12 @@ public class CardInvalidSuite extends CardTestSuite { Test ecdsa = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Verify random ECDSA signature by invalid public points", ecdsaTests.toArray(new Test[0])); Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Test ECDH and ECDSA with points on invalid curves.", ecdh, ecdsa); - Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.SUCCESS); - - doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), prepare, tests, cleanup)); + if (cfg.cleanup) { + Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.SUCCESS); + doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), prepare, tests, cleanup)); + } else { + doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), prepare, tests)); + } } } } diff --git a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java index 487fc6a..e568f67 100644 --- a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java @@ -48,9 +48,13 @@ public class CardMiscSuite extends CardTestSuite { Test ka = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), expected); Test sig = CommandTest.expect(new Command.ECDSA(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, ECTesterApplet.EXPORT_FALSE, null), expected); Test perform = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH and ECDSA", ka, sig); - Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS); - doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + " " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform, cleanup)); + if (cfg.cleanup) { + Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS); + doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + " " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform, cleanup)); + } else { + doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + " " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform)); + } } } } diff --git a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java index 9a39a72..052e480 100644 --- a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java @@ -4,7 +4,10 @@ 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.test.CompoundTest; +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.common.test.TestCallback; import cz.crcs.ectester.common.util.ByteUtil; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.CardMngr; @@ -69,7 +72,9 @@ public class CardTestVectorSuite extends CardTestSuite { return new Result(Value.SUCCESS); } })); - testVector.add(CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.SUCCESS)); + if (cfg.cleanup) { + testVector.add(CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.SUCCESS)); + } doTest(CompoundTest.greedyAll(ExpectedValue.SUCCESS, "Test vector " + result.getId(), testVector.toArray(new Test[0]))); } } diff --git a/src/cz/crcs/ectester/reader/test/CardTwistSuite.java b/src/cz/crcs/ectester/reader/test/CardTwistSuite.java index e7ea436..1e1f5f3 100644 --- a/src/cz/crcs/ectester/reader/test/CardTwistSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardTwistSuite.java @@ -13,7 +13,10 @@ import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.command.Command; -import java.util.*; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; /** * @author Jan Jancar johny@neuromancer.sk @@ -61,9 +64,12 @@ public class CardTwistSuite extends CardTestSuite { Test ecdsa = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Verify random ECDSA signature by public points on twist", ecdsaTests.toArray(new Test[0])); Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, ecdh, ecdsa); - Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS); - - doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId(), prepare, tests, cleanup)); + if (cfg.cleanup) { + Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.SUCCESS); + doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId(), prepare, tests, cleanup)); + } else { + doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId(), prepare, tests)); + } } } } diff --git a/src/cz/crcs/ectester/reader/test/CardWrongSuite.java b/src/cz/crcs/ectester/reader/test/CardWrongSuite.java index 34d151b..8bc7c90 100644 --- a/src/cz/crcs/ectester/reader/test/CardWrongSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardWrongSuite.java @@ -121,9 +121,12 @@ public class CardWrongSuite extends CardTestSuite { EC_Consts.getCurveParameter(curve, EC_Consts.PARAMETER_R, originalR, (short) 0); BigInteger originalBigR = new BigInteger(1, originalR); + Test zeroR = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, EC_Consts.PARAMETER_R, EC_Consts.TRANSFORMATION_ZERO), "Set R = 0.", "ECDH with R = 0."); + Test oneR = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, EC_Consts.PARAMETER_R, EC_Consts.TRANSFORMATION_ONE), "Set R = 1.", "ECDH with R = 1."); + BigInteger prevPrimeR; do { - prevPrimeR = BigInteger.probablePrime(keyLength, r); + prevPrimeR = BigInteger.probablePrime(originalBigR.bitLength() - 1, r); } while (prevPrimeR.compareTo(originalBigR) >= 0); byte[] prevRBytes = ECUtil.toByteArray(prevPrimeR, keyLength); EC_Params prevRData = new EC_Params(EC_Consts.PARAMETER_R, new byte[][]{prevRBytes}); @@ -139,9 +142,19 @@ public class CardWrongSuite extends CardTestSuite { EC_Params nonprimeWrongRData = new EC_Params(EC_Consts.PARAMETER_R, new byte[][]{nonprimeRBytes}); Test nonprimeWrongR = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, nonprimeWrongRData.getParams(), nonprimeWrongRData.flatten()), "Set R = some composite (but [r]G != infinity).", "ECDH with wrong R, composite."); - Test wrongR = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted R parameter.", prevprimeWrongR, nextprimeWrongR, nonprimeWrongR); + Test wrongR = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted R parameter.", zeroR, oneR, prevprimeWrongR, nextprimeWrongR, nonprimeWrongR); + + byte[] kRaw = new byte[]{(byte) 0xff}; + EC_Params kData = new EC_Params(EC_Consts.PARAMETER_K, new byte[][]{kRaw}); + Test bigK = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, kData.getParams(), kData.flatten()), "", ""); + + byte[] kZero = new byte[]{(byte) 0}; + EC_Params kZeroData = new EC_Params(EC_Consts.PARAMETER_K, new byte[][]{kZero}); + Test zeroK = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, kZeroData.getParams(), kZeroData.flatten()), "", ""); + + Test wrongK = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted K parameter.", bigK, zeroK); - doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(KeyPair.ALG_EC_FP), setup, wrongPrime, resetSetup, wrongG, resetSetup.clone(), wrongR, resetSetup.clone())); + doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(KeyPair.ALG_EC_FP), setup, wrongPrime, resetSetup, wrongG, resetSetup.clone(), wrongR, resetSetup.clone(), wrongK, resetSetup.clone())); } /* diff --git a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java index 93be3a8..bf9ec7d 100644 --- a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java +++ b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java @@ -47,7 +47,7 @@ public class TextTestWriter extends BaseTextTestWriter { StandaloneTestSuite standaloneSuite = (StandaloneTestSuite) suite; StringBuilder sb = new StringBuilder(); sb.append("═══ ").append(Colors.underline("ECTester version:")).append(" ").append(ECTesterStandalone.VERSION).append(System.lineSeparator()); - sb.append("═══ ").append(Colors.underline("Library:")).append(standaloneSuite.getLibrary().name()).append(System.lineSeparator()); + sb.append("═══ ").append(Colors.underline("Library:")).append(" ").append(standaloneSuite.getLibrary().name()).append(System.lineSeparator()); return sb.toString(); } return ""; -- cgit v1.2.3-70-g09d2