diff options
Diffstat (limited to 'reader')
5 files changed, 127 insertions, 36 deletions
diff --git a/reader/build.gradle.kts b/reader/build.gradle.kts index 1abecdc..d1f3fa3 100644 --- a/reader/build.gradle.kts +++ b/reader/build.gradle.kts @@ -17,9 +17,9 @@ dependencies { implementation(project(":common")) implementation(project(":applet")) - testImplementation(platform("org.junit:junit-bom:5.10.2")) + testImplementation(platform("org.junit:junit-bom:5.11.2")) testImplementation("org.junit.jupiter:junit-jupiter") - testImplementation("org.junit-pioneer:junit-pioneer:2.2.0") + testImplementation("org.junit-pioneer:junit-pioneer:2.3.0") testRuntimeOnly("org.junit.platform:junit-platform-launcher") } diff --git a/reader/src/main/java/cz/crcs/ectester/reader/ECTesterReader.java b/reader/src/main/java/cz/crcs/ectester/reader/ECTesterReader.java index 1fa937e..6a52dc5 100644 --- a/reader/src/main/java/cz/crcs/ectester/reader/ECTesterReader.java +++ b/reader/src/main/java/cz/crcs/ectester/reader/ECTesterReader.java @@ -28,6 +28,7 @@ import cz.crcs.ectester.common.cli.CLITools; import cz.crcs.ectester.common.cli.Colors; import cz.crcs.ectester.common.ec.EC_Curve; import cz.crcs.ectester.common.ec.EC_Consts; +import cz.crcs.ectester.common.ec.EC_Params; import cz.crcs.ectester.common.output.OutputLogger; import cz.crcs.ectester.common.output.TestWriter; import cz.crcs.ectester.common.util.*; @@ -333,6 +334,7 @@ public class ECTesterReader { opts.addOption(Option.builder("v").longOpt("verbose").desc("Turn on verbose logging.").build()); opts.addOption(Option.builder().longOpt("format").desc("Output format to use. One of: text,yml,xml.").hasArg().argName("format").build()); + opts.addOption(Option.builder().longOpt("external").desc("Use external key in ECDH.").build()); opts.addOption(Option.builder().longOpt("alloc-keypair").desc("Use KeyPair allocation method, one of: keypair, keybuilder, any.").hasArg().argName("method").build()); opts.addOption(Option.builder().longOpt("fixed").desc("Generate key(s) only once, keep them for later operations.").build()); opts.addOption(Option.builder().longOpt("fixed-private").desc("Generate private key only once, keep it for later ECDH.").build()); @@ -600,10 +602,23 @@ public class ECTesterReader { Response gen = new Command.Generate(cardManager, CardConsts.KEYPAIR_BOTH).send(); respWriter.outputResponse(gen); - if (cfg.anyPublicKey || cfg.anyKey) { - Response prep = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, CardConsts.KEYPAIR_REMOTE, EC_Consts.PARAMETER_W).send(); - respWriter.outputResponse(prep); + EC_Params keypair = null; + if (!cfg.external) { + if (cfg.anyPublicKey || cfg.anyKey) { + Response prep = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, CardConsts.KEYPAIR_REMOTE, EC_Consts.PARAMETER_W).send(); + respWriter.outputResponse(prep); + } + } else { + if (cfg.key != null || cfg.namedKey != null) { + keypair = ECUtil.loadParams(EC_Consts.PARAMETERS_KEYPAIR, cfg.namedKey, cfg.key); + } else if (cfg.publicKey != null || cfg.namedPublicKey != null) { + keypair = ECUtil.loadParams(EC_Consts.PARAMETER_W, cfg.namedPublicKey, cfg.publicKey); + } else { + System.err.println(Colors.error("No key provided for external ECDH.")); + return; + } } + if (cfg.anyPrivateKey || cfg.anyKey) { Response prep = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, CardConsts.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S).send(); respWriter.outputResponse(prep); @@ -633,21 +648,34 @@ public class ECTesterReader { respWriter.outputResponse(regen); } - Response.Export exportRemote = new Command.Export(cardManager, CardConsts.KEYPAIR_REMOTE, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W).send(); - respWriter.outputResponse(exportRemote); - Response.Export exportLocal = new Command.Export(cardManager, CardConsts.KEYPAIR_LOCAL, EC_Consts.KEY_PRIVATE, EC_Consts.PARAMETER_S).send(); - respWriter.outputResponse(exportLocal); - byte[] pubkey_bytes = exportRemote.getParameter(CardConsts.KEYPAIR_REMOTE, EC_Consts.PARAMETER_W); - byte[] privkey_bytes = exportLocal.getParameter(CardConsts.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S); + byte[] privkey_bytes; + byte[] pubkey_bytes; + Command perform; + if (cfg.external) { + Response.Export exportLocal = new Command.Export(cardManager, CardConsts.KEYPAIR_LOCAL, EC_Consts.KEY_PRIVATE, EC_Consts.PARAMETER_S).send(); + respWriter.outputResponse(exportLocal); + privkey_bytes = exportLocal.getParameter(CardConsts.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S); + pubkey_bytes = keypair.flatten(EC_Consts.PARAMETER_W); + + perform = new Command.ECDH_direct(cardManager, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, cfg.ECKAType, pubkey_bytes); + } else { + Response.Export exportRemote = new Command.Export(cardManager, CardConsts.KEYPAIR_REMOTE, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W).send(); + respWriter.outputResponse(exportRemote); + Response.Export exportLocal = new Command.Export(cardManager, CardConsts.KEYPAIR_LOCAL, EC_Consts.KEY_PRIVATE, EC_Consts.PARAMETER_S).send(); + respWriter.outputResponse(exportLocal); + pubkey_bytes = exportRemote.getParameter(CardConsts.KEYPAIR_REMOTE, EC_Consts.PARAMETER_W); + privkey_bytes = exportLocal.getParameter(CardConsts.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S); + + perform = new Command.ECDH(cardManager, CardConsts.KEYPAIR_REMOTE, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, cfg.ECKAType); + } - Command.ECDH perform = new Command.ECDH(cardManager, CardConsts.KEYPAIR_REMOTE, CardConsts.KEYPAIR_LOCAL, CardConsts.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, cfg.ECKAType); long time = 0; if (cfg.time) { time = -Command.dryRunTime(cardManager, perform, 2, respWriter); } - Response.ECDH result = perform.send(); + Response.ECDH result = (Response.ECDH) perform.send(); respWriter.outputResponse(result); if (!result.successful() || !result.hasSecret()) { @@ -842,7 +870,7 @@ public class ECTesterReader { public boolean fixedKey = false; public boolean fixedPrivate = false; public boolean fixedPublic = false; - public byte keyBuilder; + public byte keyBuilder = CardConsts.BUILD_KEYBUILDER | CardConsts.BUILD_KEYPAIR; public String log; @@ -859,6 +887,7 @@ public class ECTesterReader { public boolean color; //Action-related options + public boolean external; public String listNamed; public String testSuite; public int testFrom; @@ -1080,6 +1109,12 @@ public class ECTesterReader { } } else if (cli.hasOption("ecdh")) { + external = cli.hasOption("external"); + if (external && !(anyPublicKey || anyKey)) { + System.err.print(Colors.error("Need to specify public key with -pub or -named-public (or key with -key or -named-key) when specifying --external.")); + return false; + } + if (primeField == binaryField) { System.err.print(Colors.error("Need to specify field with -fp or -f2m. (not both)")); return false; diff --git a/reader/src/main/java/cz/crcs/ectester/reader/test/CardTestVectorSuite.java b/reader/src/main/java/cz/crcs/ectester/reader/test/CardTestVectorSuite.java index 28c5e12..ebb71d9 100644 --- a/reader/src/main/java/cz/crcs/ectester/reader/test/CardTestVectorSuite.java +++ b/reader/src/main/java/cz/crcs/ectester/reader/test/CardTestVectorSuite.java @@ -162,9 +162,11 @@ public class CardTestVectorSuite extends CardTestSuite { } if (secret.length != derived.length) { if (secret.length < derived.length) { - return new Result(Value.FAILURE, String.format("Derived secret was shorter than expected: %d vs %d (expected).", secret.length, derived.length)); + int diff = ByteUtil.diffBytes(derived, 0, secret, 0, secret.length); + return new Result(Value.FAILURE, String.format("Derived secret was shorter than expected: %d vs %d (expected), matched up to byte %d.", secret.length, derived.length, diff)); } else { - return new Result(Value.FAILURE, String.format("Derived secret was longer than expected: %d vs %d (expected).", secret.length, derived.length)); + int diff = ByteUtil.diffBytes(derived, 0, secret, 0, derived.length); + return new Result(Value.FAILURE, String.format("Derived secret was longer than expected: %d vs %d (expected), matched up to byte %d.", secret.length, derived.length, diff)); } } int diff = ByteUtil.diffBytes(derived, 0, secret, 0, secret.length); @@ -178,8 +180,20 @@ public class CardTestVectorSuite extends CardTestSuite { } } }; + Test alloc = CommandTest.expect(new Command.AllocateKeyAgreement(this.card, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), ExpectedValue.SUCCESS); Test ecdhTest = CommandTest.function(new Command.ECDH(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.KEYPAIR_REMOTE, CardConsts.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), kaCallback); + Test ecdh = CompoundTest.greedyAll(ExpectedValue.SUCCESS, "Test DH", alloc, ecdhTest); + Test allocRaw = CommandTest.expect(new Command.AllocateKeyAgreement(this.card, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH_PLAIN), ExpectedValue.SUCCESS); Test ecdhRawTest = CommandTest.function(new Command.ECDH(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.KEYPAIR_REMOTE, CardConsts.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH_PLAIN), kaCallback); + Test ecdhRaw = CompoundTest.greedyAll(ExpectedValue.SUCCESS, "Test DH_PLAIN", allocRaw, ecdhRawTest); + + Test allocCofactor = CommandTest.expect(new Command.AllocateKeyAgreement(this.card, EC_Consts.KeyAgreement_ALG_EC_SVDP_DHC), ExpectedValue.SUCCESS); + Test ecdhTestCofactor = CommandTest.function(new Command.ECDH(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.KEYPAIR_REMOTE, CardConsts.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DHC), kaCallback); + Test ecdhCofactor = CompoundTest.greedyAll(ExpectedValue.SUCCESS, "Test DHC", allocCofactor, ecdhTestCofactor); + Test allocRawCofactor = CommandTest.expect(new Command.AllocateKeyAgreement(this.card, EC_Consts.KeyAgreement_ALG_EC_SVDP_DHC_PLAIN), ExpectedValue.SUCCESS); + Test ecdhRawTestCofactor = CommandTest.function(new Command.ECDH(this.card, CardConsts.KEYPAIR_LOCAL, CardConsts.KEYPAIR_REMOTE, CardConsts.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DHC_PLAIN), kaCallback); + Test ecdhRawCofactor = CompoundTest.greedyAll(ExpectedValue.SUCCESS, "Test DHC_PLAIN", allocRawCofactor, ecdhRawTestCofactor); + byte[] data = new byte[32]; TestCallback<CommandTestable> sigCallback = new TestCallback<CommandTestable>() { @Override @@ -212,7 +226,7 @@ public class CardTestVectorSuite extends CardTestSuite { } }; Test ecdsaTest = CommandTest.function(new Command.ECDSA_sign(this.card, CardConsts.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, CardConsts.EXPORT_TRUE, data), sigCallback); - testVector.add(CompoundTest.all(ExpectedValue.SUCCESS, "Test.", ecdhTest, ecdhRawTest, ecdsaTest)); + testVector.add(CompoundTest.all(ExpectedValue.SUCCESS, "Test.", ecdh, ecdhCofactor, ecdhRaw, ecdhRawCofactor, ecdsaTest)); // if (cfg.cleanup) { testVector.add(CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.ANY)); } diff --git a/reader/src/test/java/cz/crcs/ectester/reader/AppTests.java b/reader/src/test/java/cz/crcs/ectester/reader/AppTests.java index 173f7e2..17f43da 100644 --- a/reader/src/test/java/cz/crcs/ectester/reader/AppTests.java +++ b/reader/src/test/java/cz/crcs/ectester/reader/AppTests.java @@ -36,81 +36,98 @@ public class AppTests { assertTrue(s.contains("secg")); } - // Add StdIo to all the suite tests when this is resolved: https://github.com/junit-pioneer/junit-pioneer/issues/822 - @Test @XFail(value = "JCardSim sometimes times-out.") - public void defaultSuite() { + @StdIo() + public void defaultSuite(StdOut out) { assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "default", "-s"})); } @Test @XFail(value = "JCardSim sometimes times-out.") + @StdIo() + public void defaultSuitePart(StdOut out) { + assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "default:3:5", "-s"})); + } + + @Test + @XFail(value = "JCardSim sometimes times-out.") @Disabled - public void testVectorSuite() { + @StdIo() + public void testVectorSuite(StdOut out) { assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "test-vectors", "-s"})); } @Test @XFail(value = "JCardSim sometimes times-out.") - public void compressionSuite() { + @StdIo() + public void compressionSuite(StdOut out) { assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "compression", "-s"})); } @Test @XFail(value = "JCardSim sometimes times-out.") @Disabled - public void wrongSuite() { + @StdIo() + public void wrongSuite(StdOut out) { assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "wrong", "-s", "-y"})); } @Test @XFail(value = "JCardSim sometimes times-out.") - public void degenerateSuite() { + @StdIo() + public void degenerateSuite(StdOut out) { assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "degenerate", "-s", "-y"})); } @Test @XFail(value = "JCardSim sometimes times-out.") @Disabled - public void cofactorSuite() { + @StdIo() + public void cofactorSuite(StdOut out) { assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "cofactor", "-s", "-y"})); } @Test @XFail(value = "JCardSim sometimes times-out.") @Disabled - public void compositeSuite() { + @StdIo() + public void compositeSuite(StdOut out) { assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "composite", "-s", "-y"})); } @Test @XFail(value = "JCardSim sometimes times-out.") - public void invalidSuite() { + @StdIo() + public void invalidSuite(StdOut out) { assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "invalid", "-s", "-y"})); } @Test @XFail(value = "JCardSim sometimes times-out.") - public void edgeCasesSuite() { + @StdIo() + public void edgeCasesSuite(StdOut out) { assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "edge-cases", "-s", "-y"})); } @Test @XFail(value = "JCardSim sometimes times-out.") - public void signatureSuite() { + @StdIo() + public void signatureSuite(StdOut out) { assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "signature", "-s"})); } @Test @XFail(value = "JCardSim sometimes times-out.") - public void twistSuite() { + @StdIo() + public void twistSuite(StdOut out) { assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "twist", "-s", "-y"})); } @Test @XFail(value = "JCardSim sometimes times-out.") - public void miscellaneousSuite() { + @StdIo() + public void miscellaneousSuite(StdOut out) { assertTimeoutPreemptively(Duration.ofSeconds(60), () -> ECTesterReader.main(new String[]{"-t", "miscellaneous", "-s", "-y"})); } @@ -120,22 +137,40 @@ public class AppTests { } @Test - public void ecdh() { + @StdIo() + public void ecdh(StdOut out) { ECTesterReader.main(new String[]{"-dh", "-fp", "-b", "256", "-s"}); + String s = out.capturedString(); + assertTrue(s.contains("OK")); + assertTrue(s.contains("ALG_EC_SVDP_DH of remote pubkey and local privkey")); + } + + @Test + @StdIo() + public void ecdh_external(StdOut out) { + ECTesterReader.main(new String[]{"-dh", "-fp", "--external", "--named-curve", "secg/secp256r1", "--named-public", "invalid/secp256r1/0", "-b", "256", "-s"}); + String s = out.capturedString(); + assertTrue(s.contains("OK")); + assertTrue(s.contains("ALG_EC_SVDP_DH of external pubkey and local privkey")); } @Test - public void ecdsa() { + @StdIo() + public void ecdsa(StdOut out) { ECTesterReader.main(new String[]{"-dsa", "-fp", "-b", "256", "-s"}); + String s = out.capturedString(); + System.err.println(s); } @Test - public void export() { + @StdIo() + public void export(StdOut out) { ECTesterReader.main(new String[]{"-e", "-fp", "-b", "256", "-s", "-o", "/dev/null"}); } @Test - public void info() { + @StdIo() + public void info(StdOut out) { ECTesterReader.main(new String[]{"-nf", "-s"}); } } diff --git a/reader/src/test/java/cz/crcs/ectester/reader/OutputTests.java b/reader/src/test/java/cz/crcs/ectester/reader/OutputTests.java index 5300e98..5d7ba95 100644 --- a/reader/src/test/java/cz/crcs/ectester/reader/OutputTests.java +++ b/reader/src/test/java/cz/crcs/ectester/reader/OutputTests.java @@ -1,13 +1,20 @@ package cz.crcs.ectester.reader; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import java.nio.file.Path; + public class OutputTests { + @TempDir + static Path tempDir; + @ParameterizedTest @ValueSource(strings = {"text", "xml", "yml"}) public void formats(String format) { - ECTesterReader.main(new String[]{"-t", "default", "-s", "-o", String.format("%s:out.%s", format, format),}); + Path outputFile = tempDir.resolve(String.format("out.%s", format)); + ECTesterReader.main(new String[]{"-t", "default", "-s", "-o", String.format("%s:%s", format, outputFile),}); } } |
