From c241bf27a9afc5ac8cb69072f3d732ae1dbf413c Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 22 Oct 2018 00:00:42 +0200 Subject: Efficiently instantiate prngs in shims. --- nbproject/reader/project.properties | 4 ++-- nbproject/standalone/project.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'nbproject') diff --git a/nbproject/reader/project.properties b/nbproject/reader/project.properties index 8e11520..c00c309 100644 --- a/nbproject/reader/project.properties +++ b/nbproject/reader/project.properties @@ -6,7 +6,7 @@ annotation.processing.source.output=${build.generated.sources.dir}/ap-source-out application.title=ECTesterReader application.vendor=xsvenda build.classes.dir=${build.dir}/classes -build.classes.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/Makefile +build.classes.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/*.so,**/Makefile,**/Makefile.bat # This directory is removed when the project is cleaned: build.dir=build build.generated.dir=${build.dir}/generated @@ -22,7 +22,7 @@ debug.classpath=\ debug.test.classpath=\ ${run.test.classpath} # Files in build.classes.dir which should be excluded from distribution jar -dist.archive.excludes= +dist.archive.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/*.so,**/Makefile,**/Makefile.bat # This directory is removed when the project is cleaned: dist.dir=dist dist.jar=${dist.dir}/ECTesterReader.jar diff --git a/nbproject/standalone/project.properties b/nbproject/standalone/project.properties index 7ad08a1..6b6d440 100644 --- a/nbproject/standalone/project.properties +++ b/nbproject/standalone/project.properties @@ -6,7 +6,7 @@ annotation.processing.source.output=${build.generated.sources.dir}/ap-source-out application.title=ECTesterStandalone application.vendor=xsvenda build.classes.dir=${build.dir}/classes -build.classes.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/Makefile +build.classes.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/Makefile,**/Makefile.bat # This directory is removed when the project is cleaned: build.dir=build build.generated.dir=${build.dir}/generated @@ -22,7 +22,7 @@ debug.classpath=\ debug.test.classpath=\ ${run.test.classpath} # Files in build.classes.dir which should be excluded from distribution jar -dist.archive.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/Makefile +dist.archive.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/Makefile,**/Makefile.bat # This directory is removed when the project is cleaned: dist.dir=dist dist.jar=${dist.dir}/ECTesterStandalone.jar -- cgit v1.3.1 From f59aaf972a83330206e8b0d2e1819f45da38f74e Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 11 Nov 2018 17:51:53 +0100 Subject: Add WolfCrypt provider to testing. --- README.md | 1 + docs/LIBS.md | 2 ++ lib/wolfcrypt-jni.jar | Bin 0 -> 83453 bytes nbproject/standalone/manifest.mf | 2 +- nbproject/standalone/project.properties | 1 + .../crcs/ectester/standalone/ECTesterStandalone.java | 13 ++++++++++++- .../crcs/ectester/standalone/libs/WolfCryptLib.java | 18 ++++++++++++++++++ 7 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 lib/wolfcrypt-jni.jar create mode 100644 src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java (limited to 'nbproject') diff --git a/README.md b/README.md index d70ae9b..d23922d 100644 --- a/README.md +++ b/README.md @@ -270,6 +270,7 @@ Currently supported libraries include: - [Sun EC](https://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html#SunEC) - [OpenSSL](https://www.openssl.org/) - [BoringSSL](https://boringssl.googlesource.com/boringssl) + - [wolfSSL](https://www.wolfssl.com/) - [Crypto++](https://cryptopp.com/) - [libtomcrypt](http://www.libtom.net/LibTomCrypt/) - [libgcrypt](https://www.gnupg.org/related_software/libgcrypt/) diff --git a/docs/LIBS.md b/docs/LIBS.md index faab84d..d41f98a 100644 --- a/docs/LIBS.md +++ b/docs/LIBS.md @@ -55,6 +55,8 @@ Libraries that ECTester can test. - 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. + - [WolfCrypt](https://www.wolfssl.com) + - C + Java - [OpenSSL](https://www.openssl.org/) - C - For prime field curves: diff --git a/lib/wolfcrypt-jni.jar b/lib/wolfcrypt-jni.jar new file mode 100644 index 0000000..890ae14 Binary files /dev/null and b/lib/wolfcrypt-jni.jar differ diff --git a/nbproject/standalone/manifest.mf b/nbproject/standalone/manifest.mf index 5e8f5d9..ad7aacb 100644 --- a/nbproject/standalone/manifest.mf +++ b/nbproject/standalone/manifest.mf @@ -1,4 +1,4 @@ Manifest-Version: 1.0 -Class-Path: lib/bcprov-jdk15on-1.58.jar lib/jcardsim-3.0.4-SNAPSHOT.jar lib/commons-cli-1.4.jar lib/snakeyaml-1.19.jar +Class-Path: lib/bcprov-jdk15on-1.58.jar lib/wolfcrypt-jni.jar lib/jcardsim-3.0.4-SNAPSHOT.jar lib/commons-cli-1.4.jar lib/snakeyaml-1.19.jar Main-Class: cz.crcs.ectester.standalone.ECTesterStandalone diff --git a/nbproject/standalone/project.properties b/nbproject/standalone/project.properties index 6b6d440..29ad3cc 100644 --- a/nbproject/standalone/project.properties +++ b/nbproject/standalone/project.properties @@ -34,6 +34,7 @@ includes=**/common/**,**/standalone/**,**/data/**,**/applet/* jar.compress=true javac.classpath=\ lib/bcprov-jdk15on-1.58.jar:\ + lib/wolfcrypt-jni.jar:\ lib/jcardsim-3.0.4-SNAPSHOT.jar:\ lib/commons-cli-1.4.jar:\ lib/snakeyaml-1.19.jar diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 7480215..b6f5478 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -49,6 +49,7 @@ import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.reflect.Field; import java.nio.file.Files; import java.security.*; import java.security.interfaces.ECPrivateKey; @@ -66,7 +67,17 @@ import java.util.stream.Collectors; * @version v0.3.0 */ public class ECTesterStandalone { - private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib(), new CryptoppLib(), new OpensslLib(), new BoringsslLib(), new GcryptLib(), new MscngLib()}; + private ProviderECLibrary[] libs = new ProviderECLibrary[]{ + new SunECLib(), + new BouncyCastleLib(), + new TomcryptLib(), + new BotanLib(), + new CryptoppLib(), + new OpensslLib(), + new BoringsslLib(), + new GcryptLib(), + new MscngLib(), + new WolfCryptLib()}; private Config cfg; private Options opts = new Options(); diff --git a/src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java b/src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java new file mode 100644 index 0000000..b58eb91 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java @@ -0,0 +1,18 @@ +package cz.crcs.ectester.standalone.libs; + +import com.wolfssl.provider.jce.WolfCryptProvider; + +import java.util.HashSet; +import java.util.Set; + +public class WolfCryptLib extends ProviderECLibrary { + + public WolfCryptLib() { + super(new WolfCryptProvider()); + } + + @Override + public Set getCurves() { + return new HashSet<>(); + } +} -- cgit v1.3.1 From 25bd6fd367c067f9311cb04d5acb703d1e0bccc6 Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 14 Nov 2018 23:43:31 +0100 Subject: Add ECDH validation tests using BouncyCastle. --- nbproject/reader/manifest.mf | 2 +- src/cz/crcs/ectester/applet/AppletBase.java | 8 ++ .../ectester/common/output/BaseTextTestWriter.java | 3 + src/cz/crcs/ectester/reader/ECTesterReader.java | 30 ++++-- .../ectester/reader/output/TextTestWriter.java | 1 + .../crcs/ectester/reader/output/XMLTestWriter.java | 18 ++++ .../ectester/reader/output/YAMLTestWriter.java | 6 ++ src/cz/crcs/ectester/reader/response/Response.java | 28 ++++++ .../ectester/reader/test/CardCofactorSuite.java | 2 +- .../ectester/reader/test/CardTestVectorSuite.java | 103 ++++++++++++++++++++- 10 files changed, 187 insertions(+), 14 deletions(-) (limited to 'nbproject') diff --git a/nbproject/reader/manifest.mf b/nbproject/reader/manifest.mf index c2a00ee..4bb6334 100644 --- a/nbproject/reader/manifest.mf +++ b/nbproject/reader/manifest.mf @@ -1,4 +1,4 @@ Manifest-Version: 1.0 -Class-Path: lib/jcardsim-3.0.4-SNAPSHOT.jar lib/commons-cli-1.4.jar lib/snakeyaml-1.19.jar +Class-Path: lib/bcprov-jdk15on-1.58.jar lib/jcardsim-3.0.4-SNAPSHOT.jar lib/commons-cli-1.4.jar lib/snakeyaml-1.19.jar Main-Class: cz.crcs.ectester.reader.ECTesterReader diff --git a/src/cz/crcs/ectester/applet/AppletBase.java b/src/cz/crcs/ectester/applet/AppletBase.java index 24272c5..4e488b5 100644 --- a/src/cz/crcs/ectester/applet/AppletBase.java +++ b/src/cz/crcs/ectester/applet/AppletBase.java @@ -873,6 +873,14 @@ public abstract class AppletBase extends Applet { length += 2; Util.setShort(buffer, (short) (offset + length), (short) (JCSystem.isObjectDeletionSupported() ? 1 : 0)); length += 2; + Util.setShort(buffer, (short) (offset + length), (short) buffer.length); + length += 2; + Util.setShort(buffer, (short) (offset + length), (short) ramArray.length); + length += 2; + Util.setShort(buffer, (short) (offset + length), (short) ramArray2.length); + length += 2; + Util.setShort(buffer, (short) (offset + length), (short) apduArray.length); + length += 2; return length; } } diff --git a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java index f60f8bb..85b32a4 100644 --- a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java +++ b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java @@ -106,6 +106,9 @@ public abstract class BaseTextTestWriter implements TestWriter { } else { SimpleTest test = (SimpleTest) t; out.append(testableString(test.getTestable())); + if (t.getResult().getCause() != null) { + out.append(" ┃ ").append(t.getResult().getCause().toString()); + } } return line + out.toString(); } diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 2a74ea7..377e2ff 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -40,6 +40,7 @@ import cz.crcs.ectester.reader.test.*; import javacard.framework.ISO7816; import javacard.security.KeyPair; import org.apache.commons.cli.*; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import javax.smartcardio.CardException; import javax.smartcardio.ResponseAPDU; @@ -48,6 +49,7 @@ import java.io.*; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Files; +import java.security.Security; import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -145,9 +147,9 @@ public class ECTesterReader { } ResponseAPDU selectResp = cardManager.send(SELECT_ECTESTERAPPLET); if ((short) selectResp.getSW() != ISO7816.SW_NO_ERROR) { - System.err.println(Colors.error("Failed to select ECTester applet, is it installed?")); - cardManager.disconnectFromCard(); - System.exit(1); + System.err.println(Colors.error("Failed to select ECTester applet, is it installed?")); + cardManager.disconnectFromCard(); + System.exit(1); } } @@ -155,6 +157,12 @@ public class ECTesterReader { logger = new OutputLogger(true, cfg.log); respWriter = new ResponseWriter(logger.getPrintStream()); + // Try adding the BouncyCastleProvider, which might be used in some parts of ECTester. + try { + Security.addProvider(new BouncyCastleProvider()); + } catch (SecurityException | NoClassDefFoundError ignored) { + } + //do action if (cli.hasOption("export")) { export(); @@ -167,7 +175,7 @@ public class ECTesterReader { } else if (cli.hasOption("ecdsa")) { ecdsa(); } else if (cli.hasOption("info")) { - info(); + info(); } //disconnect @@ -282,7 +290,7 @@ public class ECTesterReader { actions.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build()); 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("ls").longOpt("list-suites").desc("List supported test suites.").build()); + actions.addOption(Option.builder("ls").longOpt("list-suites").desc("List supported test suites.").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 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- signature:\n- composite:\n- test-vectors:\n- edge-cases:\n- miscellaneous:").hasArg().argName("test_suite[:from[:to]]").optionalArg(true).build()); @@ -359,11 +367,12 @@ public class ECTesterReader { } private void info() throws CardException { - Response.GetInfo info = new Command.GetInfo(cardManager).send(); - System.out.println(String.format("ECTester applet version: %s", info.getVersion())); - System.out.println(String.format("ECTester applet APDU support: %s", (info.getBase() == ECTesterApplet.BASE_221) ? "basic" : "extended length")); - System.out.println(String.format("JavaCard API version: %.1f", info.getJavaCardVersion())); - System.out.println(String.format("JavaCard supports system cleanup: %s", info.getCleanupSupport())); + Response.GetInfo info = new Command.GetInfo(cardManager).send(); + System.out.println(String.format("ECTester applet version: %s", info.getVersion())); + System.out.println(String.format("ECTester applet APDU support: %s", (info.getBase() == ECTesterApplet.BASE_221) ? "basic" : "extended length")); + System.out.println(String.format("JavaCard API version: %.1f", info.getJavaCardVersion())); + System.out.println(String.format("JavaCard supports system cleanup: %s", info.getCleanupSupport())); + System.out.println(String.format("Array sizes (apduBuf, ram, ram2, apduArr): %d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength())); } /** @@ -446,6 +455,7 @@ public class ECTesterReader { respWriter.outputResponse(response); Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send(); + respWriter.outputResponse(export); if (!response.successful() || !export.successful()) { if (retry < 10) { diff --git a/src/cz/crcs/ectester/reader/output/TextTestWriter.java b/src/cz/crcs/ectester/reader/output/TextTestWriter.java index a755857..e89d403 100644 --- a/src/cz/crcs/ectester/reader/output/TextTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/TextTestWriter.java @@ -51,6 +51,7 @@ public class TextTestWriter extends BaseTextTestWriter { sb.append("═══ ").append(Colors.underline("ECTester applet version:")).append(" ").append(info.getVersion()).append(info.getBase() == ECTesterApplet.BASE_221 ? "" : " (extended length)").append(System.lineSeparator()); sb.append("═══ ").append(Colors.underline("Card ATR:")).append(" ").append(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)).append(System.lineSeparator()); sb.append("═══ ").append(Colors.underline("JavaCard version:")).append(" ").append(info.getJavaCardVersion()).append(System.lineSeparator()); + sb.append("═══ ").append(Colors.underline("Array sizes (apduBuf, ram, ram2, apduArr):")).append(" ").append(String.format("%d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength())).append(System.lineSeparator()); CardMngr.CPLC cplc = cardSuite.getCard().getCPLC(); if (!cplc.values().isEmpty()) { sb.append("═══ ").append(Colors.underline("Card CPLC data:")).append(System.lineSeparator()); diff --git a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java index 8abdea5..9add072 100644 --- a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java @@ -116,6 +116,24 @@ public class XMLTestWriter extends BaseXMLTestWriter { result.setAttribute("javacard", String.format("%.1f", info.getJavaCardVersion())); result.setAttribute("base", String.format("%#x",info.getBase())); result.setAttribute("cleanup", String.valueOf(info.getCleanupSupport())); + Element arrays = doc.createElement("arrays"); + Element apduBuf = doc.createElement("length"); + apduBuf.setAttribute("name", "apduBuf"); + apduBuf.setTextContent(String.valueOf(info.getApduBufferLength())); + Element ramArray = doc.createElement("length"); + ramArray.setAttribute("name", "ramArray"); + ramArray.setTextContent(String.valueOf(info.getRamArrayLength())); + Element ramArray2 = doc.createElement("length"); + ramArray2.setAttribute("name", "ramArray2"); + ramArray2.setTextContent(String.valueOf(info.getRamArray2Length())); + Element apduArray = doc.createElement("length"); + apduArray.setAttribute("name", "apduArray"); + apduArray.setTextContent(String.valueOf(info.getApduArrayLength())); + arrays.appendChild(apduBuf); + arrays.appendChild(ramArray); + arrays.appendChild(ramArray2); + arrays.appendChild(apduArray); + result.appendChild(arrays); } catch (CardException ignored) { } return result; diff --git a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java index 92de6c6..56ecb71 100644 --- a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java @@ -91,6 +91,12 @@ public class YAMLTestWriter extends BaseYAMLTestWriter { result.put("javacard", info.getJavaCardVersion()); result.put("base", info.getBase()); result.put("cleanup", info.getCleanupSupport()); + Map arrays = new LinkedHashMap<>(); + arrays.put("apduBuf", Short.toUnsignedInt(info.getApduBufferLength())); + arrays.put("ramArray", Short.toUnsignedInt(info.getRamArrayLength())); + arrays.put("ramArray2", Short.toUnsignedInt(info.getRamArray2Length())); + arrays.put("apduArray", Short.toUnsignedInt(info.getApduArrayLength())); + result.put("arrays", arrays); } catch (CardException ignored) { } return result; diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java index 6f42ba1..235564e 100644 --- a/src/cz/crcs/ectester/reader/response/Response.java +++ b/src/cz/crcs/ectester/reader/response/Response.java @@ -436,6 +436,10 @@ public abstract class Response { private short base; private short jcVersion; private short cleanupSupport; + private short apduBufferLength; + private short ramArrayLength; + private short ramArray2Length; + private short apduArrayLength; public GetInfo(ResponseAPDU response, String description, long time) { super(response, description, time); @@ -448,6 +452,14 @@ public abstract class Response { jcVersion = ByteUtil.getShort(data, offset); offset += 2; cleanupSupport = ByteUtil.getShort(data, offset); + offset += 2; + apduBufferLength = ByteUtil.getShort(data, offset); + offset += 2; + ramArrayLength = ByteUtil.getShort(data, offset); + offset += 2; + ramArray2Length = ByteUtil.getShort(data, offset); + offset += 2; + apduArrayLength = ByteUtil.getShort(data, offset); } public String getVersion() { @@ -473,5 +485,21 @@ public abstract class Response { public boolean getCleanupSupport() { return cleanupSupport == 1; } + + public short getApduBufferLength() { + return apduBufferLength; + } + + public short getRamArrayLength() { + return ramArrayLength; + } + + public short getRamArray2Length() { + return ramArray2Length; + } + + public short getApduArrayLength() { + return apduArrayLength; + } } } diff --git a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java index c8caa8b..172c8af 100644 --- a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java @@ -46,7 +46,7 @@ public class CardCofactorSuite extends CardTestSuite { for (EC_Key.Public pub : keys) { Test setPub = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten()), Result.ExpectedValue.FAILURE); Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE); - Test objectEcdh = CompoundTest.all(Result.ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with degenerate pubkey.", setPub, ecdh); + Test objectEcdh = CompoundTest.any(Result.ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with degenerate pubkey.", setPub, ecdh); Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten()); Test rawEcdh = CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on non-generator subgroup.", "Card incorrectly accepted point on non-generator subgroup."); ecdhTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " cofactor key test.", objectEcdh, rawEcdh)); diff --git a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java index fbdf103..3abcebb 100644 --- a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java @@ -9,16 +9,28 @@ 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.CardUtil; +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.KeyPair; +import javax.crypto.KeyAgreement; import java.io.IOException; +import java.math.BigInteger; +import java.security.*; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import static cz.crcs.ectester.common.test.Result.ExpectedValue; import static cz.crcs.ectester.common.test.Result.Value; @@ -52,8 +64,13 @@ public class CardTestVectorSuite extends CardTestSuite { throw new IOException("Test vector keys couldn't be located."); } List testVector = new LinkedList<>(); + Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); + if (!allocate.ok()) { + doTest(CompoundTest.all(ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocate)); + continue; + } - testVector.add(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); + testVector.add(allocate); 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)); @@ -75,7 +92,89 @@ public class CardTestVectorSuite extends CardTestSuite { if (cfg.cleanup) { testVector.add(CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.ANY)); } - doTest(CompoundTest.greedyAll(ExpectedValue.SUCCESS, "Test vector " + result.getId(), testVector.toArray(new Test[0]))); + doTest(CompoundTest.greedyAll(ExpectedValue.SUCCESS, "Test vector " + result.getId() + ".", testVector.toArray(new Test[0]))); + } + + KeyAgreement ka; + KeyFactory kf; + MessageDigest md; + try { + ka = KeyAgreement.getInstance("ECDH", "BC"); + kf = KeyFactory.getInstance("ECDH", "BC"); + md = MessageDigest.getInstance("SHA1", "BC"); + } catch (NoSuchAlgorithmException | NoSuchProviderException ex) { + return; + } + + List testCurves = new ArrayList<>(); + testCurves.addAll(EC_Store.getInstance().getObjects(EC_Curve.class, "secg").values().stream().filter((curve) -> curve.getField() == KeyPair.ALG_EC_FP).collect(Collectors.toList())); + testCurves.addAll(EC_Store.getInstance().getObjects(EC_Curve.class, "brainpool").values().stream().filter((curve) -> curve.getField() == KeyPair.ALG_EC_FP).collect(Collectors.toList())); + for (EC_Curve curve : testCurves) { + List testVector = new LinkedList<>(); + Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); + if (!allocate.ok()) { + doTest(CompoundTest.all(ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocate)); + continue; + } + testVector.add(allocate); + testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS)); + testVector.add(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS)); + CommandTest export = CommandTest.expect(new Command.Export(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR), ExpectedValue.ANY); + testVector.add(export); + TestCallback kaCallback = new TestCallback() { + @Override + public Result apply(CommandTestable testable) { + Response.ECDH ecdhData = (Response.ECDH) testable.getResponse(); + if (!ecdhData.successful()) + return new Result(Value.FAILURE, "ECDH was unsuccessful."); + if (!ecdhData.hasSecret()) { + return new Result(Value.FAILURE, "ECDH response did not contain the derived secret."); + } + byte[] secret = ecdhData.getSecret(); + Response.Export keyData = (Response.Export) export.getResponse(); + byte[] pkey = keyData.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W); + byte[] skey = keyData.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_S); + ECParameterSpec spec = curve.toSpec(); + ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(new BigInteger(1, skey), spec); + ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(ECUtil.fromX962(pkey, curve.toCurve()), spec); + PrivateKey privKey; + PublicKey pubkey; + try { + privKey = kf.generatePrivate(privKeySpec); + pubkey = kf.generatePublic(pubKeySpec); + ka.init(privKey); + ka.doPhase(pubkey, true); + byte[] rawDerived = ka.generateSecret(); + int fieldSize = (curve.getBits() + 7) / 8; + if (rawDerived.length < fieldSize) { + byte[] padded = new byte[fieldSize]; + System.arraycopy(rawDerived, 0, padded, fieldSize - rawDerived.length, rawDerived.length); + rawDerived = padded; + } + byte[] derived = md.digest(rawDerived); + 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)); + } 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, secret.length); + if (diff == secret.length) { + return new Result(Value.SUCCESS, "Derived secret matched expected value."); + } else { + return new Result(Value.FAILURE, "Derived secret does not match expected value, first difference was at byte " + String.valueOf(diff) + "."); + } + } catch (InvalidKeySpecException | InvalidKeyException ex) { + return new Result(Value.SUCCESS, "Result could not be verified. " + ex.getMessage()); + } + } + }; + testVector.add(CommandTest.function(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), kaCallback)); + if (cfg.cleanup) { + testVector.add(CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.ANY)); + } + doTest(CompoundTest.greedyAll(ExpectedValue.SUCCESS, "Validation test on " + curve.getId() + ".", testVector.toArray(new Test[0]))); } } } -- cgit v1.3.1