aboutsummaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/reader
diff options
context:
space:
mode:
authorJ08nY2018-11-28 01:04:31 +0100
committerJ08nY2018-11-28 01:04:31 +0100
commitebe40e2fdd5e28cdabe05250422f3149e188641a (patch)
treefbf29423e8053c6a7267d600d1630fefb1bf1a1b /src/cz/crcs/ectester/reader
parent7e9917742785a9fd532a52231e95ddad5775555f (diff)
parent12845c8c41eff5f598dc8e843920f5bb4638775d (diff)
downloadECTester-ebe40e2fdd5e28cdabe05250422f3149e188641a.tar.gz
ECTester-ebe40e2fdd5e28cdabe05250422f3149e188641a.tar.zst
ECTester-ebe40e2fdd5e28cdabe05250422f3149e188641a.zip
Merge branch 'devel'
Diffstat (limited to 'src/cz/crcs/ectester/reader')
-rw-r--r--src/cz/crcs/ectester/reader/CardMngr.java2
-rw-r--r--src/cz/crcs/ectester/reader/ECTesterReader.java46
-rw-r--r--src/cz/crcs/ectester/reader/command/Command.java50
-rw-r--r--src/cz/crcs/ectester/reader/output/TextTestWriter.java10
-rw-r--r--src/cz/crcs/ectester/reader/output/XMLTestWriter.java32
-rw-r--r--src/cz/crcs/ectester/reader/output/YAMLTestWriter.java20
-rw-r--r--src/cz/crcs/ectester/reader/response/Response.java80
-rw-r--r--src/cz/crcs/ectester/reader/test/CardCofactorSuite.java6
-rw-r--r--src/cz/crcs/ectester/reader/test/CardCompositeSuite.java18
-rw-r--r--src/cz/crcs/ectester/reader/test/CardCompressionSuite.java39
-rw-r--r--src/cz/crcs/ectester/reader/test/CardDefaultSuite.java1
-rw-r--r--src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java4
-rw-r--r--src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java14
-rw-r--r--src/cz/crcs/ectester/reader/test/CardInvalidSuite.java4
-rw-r--r--src/cz/crcs/ectester/reader/test/CardMiscSuite.java63
-rw-r--r--src/cz/crcs/ectester/reader/test/CardSignatureSuite.java6
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java103
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTwistSuite.java4
18 files changed, 420 insertions, 82 deletions
diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java
index 921a9c8..e6835dd 100644
--- a/src/cz/crcs/ectester/reader/CardMngr.java
+++ b/src/cz/crcs/ectester/reader/CardMngr.java
@@ -331,7 +331,7 @@ public class CardMngr {
if (responseAPDU.getSW1() == (byte) 0x61) {
CommandAPDU apduToSend = new CommandAPDU((byte) 0x00,
(byte) 0xC0, (byte) 0x00, (byte) 0x00,
- responseAPDU.getSW1());
+ responseAPDU.getSW2());
responseAPDU = channel.transmit(apduToSend);
if (verbose)
diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java
index 0c04453..abc7264 100644
--- a/src/cz/crcs/ectester/reader/ECTesterReader.java
+++ b/src/cz/crcs/ectester/reader/ECTesterReader.java
@@ -37,15 +37,19 @@ import cz.crcs.ectester.reader.output.FileTestWriter;
import cz.crcs.ectester.reader.output.ResponseWriter;
import cz.crcs.ectester.reader.response.Response;
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;
import javax.xml.parsers.ParserConfigurationException;
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;
@@ -141,14 +145,24 @@ public class ECTesterReader {
System.err.println(Colors.error("Failed to connect to card."));
System.exit(1);
}
- cardManager.send(SELECT_ECTESTERAPPLET);
+ 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);
+ }
}
- // Setup logger, testWriter and respWriter
+ // Setup logger and respWriter
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();
@@ -160,6 +174,8 @@ public class ECTesterReader {
ecdh();
} else if (cli.hasOption("ecdsa")) {
ecdsa();
+ } else if (cli.hasOption("info")) {
+ info();
}
//disconnect
@@ -232,6 +248,8 @@ public class ECTesterReader {
* -dh / --ecdh [count]]
* -dsa / --ecdsa [count]
* -ln / --list-named [obj]
+ * -ls / --list-suites
+ * -nfo / --info
*
* Options:
* -b / --bit-size <b> // -a / --all
@@ -272,12 +290,13 @@ 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("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. Optionally specify a test number to run only a part of a test suite. <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());
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());
+ actions.addOption(Option.builder("nf").longOpt("info").desc("Get applet info.").build());
opts.addOptionGroup(actions);
@@ -347,6 +366,15 @@ 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()));
+ System.out.println(String.format("Array sizes (apduBuf, ram, ram2, apduArr): %d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength()));
+ }
+
/**
* Exports default card/simulation EC domain parameters to output file.
*
@@ -405,13 +433,13 @@ public class ECTesterReader {
*/
private void generate() throws CardException, IOException {
byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
+ Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass);
Response allocate = new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass).send();
respWriter.outputResponse(allocate);
- Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass);
OutputStreamWriter keysFile = FileUtil.openFiles(cfg.outputs);
- keysFile.write("index;time;pubW;privS\n");
+ keysFile.write("index;genTime;exportTime;pubW;privS\n");
int generated = 0;
int retry = 0;
@@ -423,10 +451,10 @@ public class ECTesterReader {
Command.Generate generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL);
Response.Generate response = generate.send();
- long elapsed = response.getDuration();
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) {
@@ -440,7 +468,7 @@ public class ECTesterReader {
String pub = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false);
String priv = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false);
- String line = String.format("%d;%d;%s;%s\n", generated, elapsed / 1000000, pub, priv);
+ String line = String.format("%d;%d;%d;%s;%s\n", generated, response.getDuration() / 1000000, export.getDuration() / 1000000, pub, priv);
keysFile.write(line);
keysFile.flush();
generated++;
@@ -533,10 +561,10 @@ public class ECTesterReader {
*/
private void ecdh() throws IOException, CardException {
byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
+ Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_BOTH, cfg.bits, keyClass);
List<Response> prepare = new LinkedList<>();
prepare.add(new Command.AllocateKeyAgreement(cardManager, cfg.ECKAType).send()); // Prepare KeyAgreement or required type
prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, cfg.bits, keyClass).send());
- Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_BOTH, cfg.bits, keyClass);
if (curve != null)
prepare.add(curve.send());
diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java
index 5a4af21..a3560df 100644
--- a/src/cz/crcs/ectester/reader/command/Command.java
+++ b/src/cz/crcs/ectester/reader/command/Command.java
@@ -133,6 +133,9 @@ public abstract class Command implements Cloneable {
} else {
keypair = dataStore.getObject(EC_Keypair.class, cfg.namedKey);
}
+ if (keypair == null) {
+ throw new IOException("KeyPair not found.");
+ }
data = keypair.flatten();
if (data == null) {
@@ -155,6 +158,9 @@ public abstract class Command implements Cloneable {
pub = dataStore.getObject(EC_Keypair.class, cfg.namedPublicKey);
}
}
+ if (pub == null) {
+ throw new IOException("Public key not found.");
+ }
byte[] pubkey = pub.flatten(EC_Consts.PARAMETER_W);
if (pubkey == null) {
@@ -177,6 +183,9 @@ public abstract class Command implements Cloneable {
priv = dataStore.getObject(EC_Keypair.class, cfg.namedPrivateKey);
}
}
+ if (priv == null) {
+ throw new IOException("Private key not found.");
+ }
byte[] privkey = priv.flatten(EC_Consts.PARAMETER_S);
if (privkey == null) {
@@ -383,18 +392,7 @@ public abstract class Command implements Cloneable {
@Override
public String getDescription() {
- String name;
- switch (curve) {
- case EC_Consts.CURVE_default:
- name = "default";
- break;
- case EC_Consts.CURVE_external:
- name = "external";
- break;
- default:
- name = "custom";
- break;
- }
+ String name = CardUtil.getCurveName(curve);
String what = CardUtil.getParameterString(params);
String pair;
@@ -864,5 +862,33 @@ public abstract class Command implements Cloneable {
return "Request JCSystem object deletion";
}
}
+
+ /**
+ *
+ */
+ public static class GetInfo extends Command {
+
+ /**
+ * @param cardManager cardManager to send APDU through
+ */
+ public GetInfo(CardMngr cardManager) {
+ super(cardManager);
+
+ this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GET_INFO, 0, 0);
+ }
+
+ @Override
+ public Response.GetInfo send() throws CardException {
+ long elapsed = -System.nanoTime();
+ ResponseAPDU response = cardManager.send(cmd);
+ elapsed += System.nanoTime();
+ return new Response.GetInfo(response, getDescription(), elapsed);
+ }
+
+ @Override
+ public String getDescription() {
+ return "Get applet info";
+ }
+ }
}
diff --git a/src/cz/crcs/ectester/reader/output/TextTestWriter.java b/src/cz/crcs/ectester/reader/output/TextTestWriter.java
index ad35012..e89d403 100644
--- a/src/cz/crcs/ectester/reader/output/TextTestWriter.java
+++ b/src/cz/crcs/ectester/reader/output/TextTestWriter.java
@@ -1,5 +1,6 @@
package cz.crcs.ectester.reader.output;
+import cz.crcs.ectester.applet.ECTesterApplet;
import cz.crcs.ectester.common.cli.Colors;
import cz.crcs.ectester.common.output.BaseTextTestWriter;
import cz.crcs.ectester.common.test.TestSuite;
@@ -7,6 +8,7 @@ import cz.crcs.ectester.common.test.Testable;
import cz.crcs.ectester.common.util.ByteUtil;
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 cz.crcs.ectester.reader.test.CardTestSuite;
import cz.crcs.ectester.reader.test.CommandTestable;
@@ -43,9 +45,13 @@ public class TextTestWriter extends BaseTextTestWriter {
if (suite instanceof CardTestSuite) {
CardTestSuite cardSuite = (CardTestSuite) suite;
StringBuilder sb = new StringBuilder();
- sb.append("═══ ").append(Colors.underline("ECTester version:")).append(" ").append(ECTesterReader.VERSION).append(ECTesterReader.GIT_COMMIT).append(System.lineSeparator());
- sb.append("═══ ").append(Colors.underline("Card ATR:")).append(" ").append(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)).append(System.lineSeparator());
try {
+ sb.append("═══ ").append(Colors.underline("ECTester version:")).append(" ").append(ECTesterReader.VERSION).append(ECTesterReader.GIT_COMMIT).append(System.lineSeparator());
+ Response.GetInfo info = new Command.GetInfo(cardSuite.getCard()).send();
+ 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 00cc6c6..9add072 100644
--- a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java
+++ b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java
@@ -108,6 +108,37 @@ public class XMLTestWriter extends BaseXMLTestWriter {
return result;
}
+ private Element appletElement(CardMngr card) {
+ Element result = doc.createElement("applet");
+ try {
+ Response.GetInfo info = new Command.GetInfo(card).send();
+ result.setAttribute("version", info.getVersion());
+ 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;
+ }
+
@Override
protected Element deviceElement(TestSuite suite) {
if (suite instanceof CardTestSuite) {
@@ -116,6 +147,7 @@ public class XMLTestWriter extends BaseXMLTestWriter {
result.setAttribute("type", "card");
result.setAttribute("ectester", ECTesterReader.VERSION + ECTesterReader.GIT_COMMIT);
result.appendChild(cplcElement(cardSuite.getCard()));
+ result.appendChild(appletElement(cardSuite.getCard()));
Element atr = doc.createElement("ATR");
atr.setTextContent(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false));
diff --git a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java
index 7c99a4a..56ecb71 100644
--- a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java
+++ b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java
@@ -83,6 +83,25 @@ public class YAMLTestWriter extends BaseYAMLTestWriter {
return result;
}
+ private Map<String, Object> appletObject(CardMngr card) {
+ Map<String, Object> result = new LinkedHashMap<>();
+ try {
+ Response.GetInfo info = new Command.GetInfo(card).send();
+ result.put("version", info.getVersion());
+ result.put("javacard", info.getJavaCardVersion());
+ result.put("base", info.getBase());
+ result.put("cleanup", info.getCleanupSupport());
+ Map<String, Integer> 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;
+ }
+
@Override
protected Map<String, Object> deviceObject(TestSuite suite) {
if (suite instanceof CardTestSuite) {
@@ -91,6 +110,7 @@ public class YAMLTestWriter extends BaseYAMLTestWriter {
result.put("type", "card");
result.put("ectester", ECTesterReader.VERSION + ECTesterReader.GIT_COMMIT);
result.put("cplc", cplcObject(cardSuite.getCard()));
+ result.put("applet", appletObject(cardSuite.getCard()));
result.put("ATR", ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false));
return result;
}
diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java
index 4814e41..235564e 100644
--- a/src/cz/crcs/ectester/reader/response/Response.java
+++ b/src/cz/crcs/ectester/reader/response/Response.java
@@ -79,6 +79,10 @@ public abstract class Response {
return resp;
}
+ public byte[] getData() {
+ return resp.getData();
+ }
+
public long getDuration() {
return time;
}
@@ -304,7 +308,7 @@ public abstract class Response {
if (pair == keyPair && param == mask) {
return index;
}
- if ((parameters & mask) != 0 && (pair & keyPair) != 0) {
+ if ((parameters & mask) != 0 && (pair & this.keyPair) != 0) {
if (mask == EC_Consts.PARAMETER_W) {
if ((key & EC_Consts.KEY_PUBLIC) != 0)
index++;
@@ -424,4 +428,78 @@ public abstract class Response {
parse(1, 0);
}
}
+
+ /**
+ *
+ */
+ public static class GetInfo extends 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);
+
+ parse(1, 1);
+ int offset = 2 + 2 + getParamLength(0);
+ byte[] data = getData();
+ base = ByteUtil.getShort(data, offset);
+ offset += 2;
+ 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() {
+ return new String(getParam(0));
+ }
+
+ public short getBase() {
+ return base;
+ }
+
+ public float getJavaCardVersion() {
+ byte major = (byte) (jcVersion >> 8);
+ byte minor = (byte) (jcVersion & 0xff);
+ int minorSize;
+ if (minor == 0) {
+ minorSize = 1;
+ } else {
+ minorSize = (int) Math.ceil(Math.log10(minor));
+ }
+ return (major + ((float) (minor) / (minorSize * 10)));
+ }
+
+ 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 710b704..172c8af 100644
--- a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java
@@ -31,8 +31,8 @@ public class CardCofactorSuite extends CardTestSuite {
@Override
protected void runTests() throws Exception {
Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "cofactor");
- List<Map.Entry<EC_Curve, List<EC_Key.Public>>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
- for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList) {
+ Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
EC_Curve curve = e.getKey();
List<EC_Key.Public> keys = e.getValue();
@@ -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/CardCompositeSuite.java b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java
index 336b371..4bf9290 100644
--- a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java
@@ -37,8 +37,8 @@ public class CardCompositeSuite extends CardTestSuite {
* is revealed.
*/
Map<String, EC_Key> keys = EC_Store.getInstance().getObjects(EC_Key.class, "composite");
- List<Map.Entry<EC_Curve, List<EC_Key>>> mappedKeys = EC_Store.mapKeyToCurve(keys.values());
- for (Map.Entry<EC_Curve, List<EC_Key>> curveKeys : mappedKeys) {
+ Map<EC_Curve, List<EC_Key>> mappedKeys = EC_Store.mapKeyToCurve(keys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key>> curveKeys : mappedKeys.entrySet()) {
EC_Curve curve = curveKeys.getKey();
List<Test> tests = new LinkedList<>();
Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_LOCAL, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
@@ -59,35 +59,35 @@ public class CardCompositeSuite extends CardTestSuite {
Map<String, EC_Curve> results = EC_Store.getInstance().getObjects(EC_Curve.class, "composite");
- List<Map.Entry<String, List<EC_Curve>>> groupList = EC_Store.mapToPrefix(results.values());
+ Map<String, List<EC_Curve>> groups = EC_Store.mapToPrefix(results.values());
/* Test the whole curves with both keypairs generated on card(no small-order public points provided).
*/
- List<EC_Curve> wholeCurves = groupList.stream().filter((e) -> e.getKey().equals("whole")).findFirst().get().getValue();
+ List<EC_Curve> wholeCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("whole")).findFirst().get().getValue();
testGroup(wholeCurves, "Composite generator order", ExpectedValue.FAILURE, "Card rejected to do ECDH with composite order generator.", "Card did not reject to do ECDH with composite order generator.");
/* Also test having a G of small order, so small R.
*/
- List<EC_Curve> smallRCurves = groupList.stream().filter((e) -> e.getKey().equals("small")).findFirst().get().getValue();
+ List<EC_Curve> smallRCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("small")).findFirst().get().getValue();
testGroup(smallRCurves, "Small generator order", ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a small order generator.", "Card incorrectly does ECDH over a small order generator.");
/* Test increasingly larger prime R, to determine where/if card behavior changes.
*/
- List<EC_Curve> varyingCurves = groupList.stream().filter((e) -> e.getKey().equals("varying")).findFirst().get().getValue();
+ List<EC_Curve> varyingCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("varying")).findFirst().get().getValue();
testGroup(varyingCurves, null, ExpectedValue.ANY, "", "");
/* Also test having a G of large but composite order, R = p * q,
*/
- List<EC_Curve> pqCurves = groupList.stream().filter((e) -> e.getKey().equals("pq")).findFirst().get().getValue();
+ List<EC_Curve> pqCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("pq")).findFirst().get().getValue();
testGroup(pqCurves, null, ExpectedValue.ANY, "", "");
/* Also test having G or large order being a Carmichael pseudoprime, R = p * q * r,
*/
- List<EC_Curve> ppCurves = groupList.stream().filter((e) -> e.getKey().equals("pp")).findFirst().get().getValue();
+ List<EC_Curve> ppCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("pp")).findFirst().get().getValue();
testGroup(ppCurves, "Generator order = Carmichael pseudoprime", ExpectedValue.ANY, "", "");
/* Also test rg0 curves.
*/
- List<EC_Curve> rg0Curves = groupList.stream().filter((e) -> e.getKey().equals("rg0")).findFirst().get().getValue();
+ List<EC_Curve> rg0Curves = groups.entrySet().stream().filter((e) -> e.getKey().equals("rg0")).findFirst().get().getValue();
testGroup(rg0Curves, null, ExpectedValue.ANY, "", "");
}
diff --git a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java
index ae25bf1..291cc04 100644
--- a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java
@@ -2,6 +2,8 @@ package cz.crcs.ectester.reader.test;
import cz.crcs.ectester.applet.ECTesterApplet;
import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
import cz.crcs.ectester.common.output.TestWriter;
import cz.crcs.ectester.common.test.CompoundTest;
import cz.crcs.ectester.common.test.Result;
@@ -9,6 +11,7 @@ import cz.crcs.ectester.common.test.Test;
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;
@@ -18,6 +21,7 @@ import javacard.security.KeyPair;
import java.security.spec.ECPoint;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
/**
* @author Jan Jancar johny@neuromancer.sk
@@ -51,6 +55,10 @@ public class CardCompressionSuite extends CardTestSuite {
if (cfg.binaryField) {
runCompression(KeyPair.ALG_EC_F2M);
}
+
+ // Now, do ECDH over SECG curves and give the implementation a compressed key that is not a quadratic residue in
+ // decompression.
+ runNonResidue();
}
private void runCompression(byte field) throws Exception {
@@ -59,27 +67,28 @@ public class CardCompressionSuite extends CardTestSuite {
for (short keyLength : keySizes) {
String spec = keyLength + "b " + CardUtil.getKeyTypeString(field);
+ byte curveId = EC_Consts.getCurve(keyLength, field);
Test allocateFirst = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, field), Result.ExpectedValue.SUCCESS));
if (!allocateFirst.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + spec + ".", allocateFirst));
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for compression test on " + spec + ".", allocateFirst));
continue;
}
List<Test> compressionTests = new LinkedList<>();
compressionTests.add(allocateFirst);
- Test setCustom = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.getCurve(keyLength, field), domain, null), Result.ExpectedValue.SUCCESS));
+ Test setCustom = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, curveId, domain, null), Result.ExpectedValue.SUCCESS));
Test genCustom = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.SUCCESS));
compressionTests.add(setCustom);
compressionTests.add(genCustom);
Response.Export key = new Command.Export(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W).send();
byte[] pubkey = key.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.KEY_PUBLIC);
+ EC_Curve secgCurve = EC_Store.getInstance().getObject(EC_Curve.class, "secg", CardUtil.getCurveName(curveId));
ECPoint pub;
try {
- pub = ECUtil.fromX962(pubkey, null);
+ pub = ECUtil.fromX962(pubkey, secgCurve.toCurve());
} catch (IllegalArgumentException iae) {
- // TODO: use external SECG curves so we have them here.
doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "", compressionTests.toArray(new Test[0])));
continue;
}
@@ -119,4 +128,26 @@ public class CardCompressionSuite extends CardTestSuite {
doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Compression test of " + spec + ".", compressionTests.toArray(new Test[0])));
}
}
+
+ private void runNonResidue() {
+ Map<String, EC_Key.Public> otherKeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "misc");
+ List<EC_Key.Public> compressionKeys = EC_Store.mapToPrefix(otherKeys.values()).get("compression");
+
+ for (EC_Key.Public key : compressionKeys) {
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, key.getCurve());
+ List<Test> tests = new LinkedList<>();
+ Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_LOCAL, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
+ if (!allocate.ok()) {
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for non-residue test on " + curve.getBits() + "b " + curve.getId() + ".", allocate));
+ continue;
+ }
+ tests.add(allocate);
+ tests.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS));
+ tests.add(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS));
+ byte[] pointData = ECUtil.toX962Compressed(key.getParam(EC_Consts.PARAMETER_W));
+ byte[] pointDataEncoded = ByteUtil.prependLength(pointData);
+ tests.add(CommandTest.expect(new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pointDataEncoded), Result.ExpectedValue.FAILURE));
+ doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Non-residue test of " + curve.getId() + ".", tests.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 e495b00..91f9ef6 100644
--- a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java
@@ -10,6 +10,7 @@ import cz.crcs.ectester.common.util.CardUtil;
import cz.crcs.ectester.reader.CardMngr;
import cz.crcs.ectester.reader.ECTesterReader;
import cz.crcs.ectester.reader.command.Command;
+import cz.crcs.ectester.reader.response.Response;
import javacard.security.KeyPair;
import java.util.LinkedList;
diff --git a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java
index c926a4d..f434d4d 100644
--- a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java
@@ -31,8 +31,8 @@ public class CardDegenerateSuite extends CardTestSuite {
@Override
protected void runTests() throws Exception {
Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "degenerate");
- List<Map.Entry<EC_Curve, List<EC_Key.Public>>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
- for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList) {
+ Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
EC_Curve curve = e.getKey();
List<EC_Key.Public> keys = e.getValue();
diff --git a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java
index b68b2ec..ccec401 100644
--- a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java
@@ -39,8 +39,8 @@ public class CardEdgeCasesSuite extends CardTestSuite {
@Override
protected void runTests() throws Exception {
Map<String, EC_KAResult> results = EC_Store.getInstance().getObjects(EC_KAResult.class, "wycheproof");
- List<Map.Entry<String, List<EC_KAResult>>> groupList = EC_Store.mapToPrefix(results.values());
- for (Map.Entry<String, List<EC_KAResult>> e : groupList) {
+ Map<String, List<EC_KAResult>> groups = EC_Store.mapToPrefix(results.values());
+ for (Map.Entry<String, List<EC_KAResult>> e : groups.entrySet()) {
String description = null;
switch (e.getKey()) {
case "addsub":
@@ -55,8 +55,8 @@ public class CardEdgeCasesSuite extends CardTestSuite {
}
List<Test> groupTests = new LinkedList<>();
- List<Map.Entry<EC_Curve, List<EC_KAResult>>> curveList = EC_Store.mapResultToCurve(e.getValue());
- for (Map.Entry<EC_Curve, List<EC_KAResult>> c : curveList) {
+ Map<EC_Curve, List<EC_KAResult>> curveList = EC_Store.mapResultToCurve(e.getValue());
+ for (Map.Entry<EC_Curve, List<EC_KAResult>> c : curveList.entrySet()) {
EC_Curve curve = c.getKey();
List<Test> curveTests = new LinkedList<>();
@@ -111,7 +111,7 @@ public class CardEdgeCasesSuite extends CardTestSuite {
}
{
- EC_KAResult openssl_bug = EC_Store.getInstance().getObject(EC_KAResult.class, "other", "openssl-bug");
+ EC_KAResult openssl_bug = EC_Store.getInstance().getObject(EC_KAResult.class, "misc", "openssl-bug");
EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, openssl_bug.getCurve());
EC_Key.Private skey = EC_Store.getInstance().getObject(EC_Key.Private.class, openssl_bug.getOtherKey());
EC_Key.Public pkey = EC_Store.getInstance().getObject(EC_Key.Public.class, openssl_bug.getOneKey());
@@ -145,7 +145,7 @@ public class CardEdgeCasesSuite extends CardTestSuite {
for (EC_Curve curve : curves) {
Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), 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));
+ doTest(CompoundTest.all(Result.ExpectedValue.FAILURE, "No support for " + curve.getBits() + "b " + curve.getId() + ".", 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);
@@ -238,7 +238,7 @@ public class CardEdgeCasesSuite extends CardTestSuite {
Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, secp160r1.getBits(), KeyPair.ALG_EC_FP), Result.ExpectedValue.SUCCESS));
if (!key.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.FAILURE, "No support for " + secp160r1.getBits() + "b ALG_EC_FP.", key));
+ doTest(CompoundTest.all(Result.ExpectedValue.FAILURE, "No support for " + secp160r1.getBits() + "b secp160r1.", key));
return;
}
Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, secp160r1.getParams(), secp160r1.flatten()), Result.ExpectedValue.SUCCESS);
diff --git a/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java b/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java
index 17c5d4b..3b9e0e5 100644
--- a/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java
@@ -35,8 +35,8 @@ public class CardInvalidSuite extends CardTestSuite {
* Try ECDH with invalid public keys of increasing order.
*/
Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "invalid");
- List<Map.Entry<EC_Curve, List<EC_Key.Public>>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
- for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList) {
+ Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
EC_Curve curve = e.getKey();
List<EC_Key.Public> keys = e.getValue();
diff --git a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java
index 8623e36..a2ce2ce 100644
--- a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java
@@ -7,12 +7,14 @@ 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.ArrayList;
+import java.util.Collection;
+import java.util.List;
import java.util.Map;
/**
@@ -21,7 +23,9 @@ 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, anomalous 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,",
+ "Barreto-Naehrig curves with small embedding degree and CM discriminant, MNT curves,",
+ "some Montgomery curves transformed to short Weierstrass form and Curve25519 transformed to short Weierstrass form.");
}
@Override
@@ -29,32 +33,45 @@ public class CardMiscSuite extends CardTestSuite {
Map<String, EC_Curve> anCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "anomalous");
Map<String, EC_Curve> ssCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "supersingular");
Map<String, EC_Curve> bnCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "Barreto-Naehrig");
+ Map<String, EC_Curve> mntCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "MNT");
+ List<EC_Curve> mCurves = new ArrayList<>();
+ mCurves.add(EC_Store.getInstance().getObject(EC_Curve.class, "other", "M-221"));
+ mCurves.add(EC_Store.getInstance().getObject(EC_Curve.class, "other", "M-383"));
+ mCurves.add(EC_Store.getInstance().getObject(EC_Curve.class, "other", "M-511"));
+ EC_Curve curve25519 = EC_Store.getInstance().getObject(EC_Curve.class, "other", "Curve25519");
- testCurves(anCurves, "anomalous", Result.ExpectedValue.FAILURE);
- testCurves(ssCurves, "supersingular", Result.ExpectedValue.FAILURE);
- testCurves(bnCurves, "Barreto-Naehrig", Result.ExpectedValue.ANY);
+ testCurves(anCurves.values(), "anomalous", Result.ExpectedValue.FAILURE);
+ testCurves(ssCurves.values(), "supersingular", Result.ExpectedValue.FAILURE);
+ testCurves(bnCurves.values(), "Barreto-Naehrig", Result.ExpectedValue.SUCCESS);
+ testCurves(mntCurves.values(), "MNT", Result.ExpectedValue.SUCCESS);
+ testCurves(mCurves, "Montgomery", Result.ExpectedValue.SUCCESS);
+ testCurve(curve25519, "Montgomery", Result.ExpectedValue.SUCCESS);
}
- private void testCurves(Map<String, EC_Curve> 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.FAILURE, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocateFirst));
- continue;
- }
+ private void testCurve(EC_Curve curve, String catName, Result.ExpectedValue expected) {
+ 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 " + catName + " curve: " + curve.getId() + ".", allocateFirst));
+ return;
+ }
+
+ 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.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 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.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);
+ if (cfg.cleanup) {
+ Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY);
+ doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform, cleanup));
+ } else {
+ doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform));
+ }
+ }
- if (cfg.cleanup) {
- Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY);
- doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + " " + 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));
- }
+ private void testCurves(Collection<EC_Curve> curves, String catName, Result.ExpectedValue expected) {
+ for (EC_Curve curve : curves) {
+ testCurve(curve, catName, expected);
}
}
}
diff --git a/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java b/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java
index 59def74..20546c8 100644
--- a/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java
@@ -28,16 +28,16 @@ public class CardSignatureSuite extends CardTestSuite {
@Override
protected void runTests() throws Exception {
Map<String, EC_SigResult> results = EC_Store.getInstance().getObjects(EC_SigResult.class, "wrong");
- List<Map.Entry<String, List<EC_SigResult>>> groupList = EC_Store.mapToPrefix(results.values());
+ Map<String, List<EC_SigResult>> groups = EC_Store.mapToPrefix(results.values());
- List<EC_SigResult> nok = groupList.stream().filter((e) -> e.getKey().equals("nok")).findFirst().get().getValue();
+ List<EC_SigResult> nok = groups.entrySet().stream().filter((e) -> e.getKey().equals("nok")).findFirst().get().getValue();
byte[] data = "Some stuff that is not the actual data".getBytes();
for (EC_SigResult sig : nok) {
ecdsaTest(sig, Result.ExpectedValue.FAILURE, data);
}
- List<EC_SigResult> ok = groupList.stream().filter((e) -> e.getKey().equals("ok")).findFirst().get().getValue();
+ List<EC_SigResult> ok = groups.entrySet().stream().filter((e) -> e.getKey().equals("ok")).findFirst().get().getValue();
for (EC_SigResult sig : ok) {
ecdsaTest(sig, Result.ExpectedValue.SUCCESS, null);
}
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<Test> 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<EC_Curve> 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<Test> 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<CommandTestable> kaCallback = new TestCallback<CommandTestable>() {
+ @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])));
}
}
}
diff --git a/src/cz/crcs/ectester/reader/test/CardTwistSuite.java b/src/cz/crcs/ectester/reader/test/CardTwistSuite.java
index 6ad4ce6..3df4c65 100644
--- a/src/cz/crcs/ectester/reader/test/CardTwistSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardTwistSuite.java
@@ -29,8 +29,8 @@ public class CardTwistSuite extends CardTestSuite {
@Override
protected void runTests() throws Exception {
Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "twist");
- List<Map.Entry<EC_Curve, List<EC_Key.Public>>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
- for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList) {
+ Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
EC_Curve curve = e.getKey();
List<EC_Key.Public> keys = e.getValue();