aboutsummaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/reader/test/CardWrongSuite.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cz/crcs/ectester/reader/test/CardWrongSuite.java')
-rw-r--r--src/cz/crcs/ectester/reader/test/CardWrongSuite.java227
1 files changed, 227 insertions, 0 deletions
diff --git a/src/cz/crcs/ectester/reader/test/CardWrongSuite.java b/src/cz/crcs/ectester/reader/test/CardWrongSuite.java
new file mode 100644
index 0000000..8bc7c90
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardWrongSuite.java
@@ -0,0 +1,227 @@
+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_Params;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.common.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 javacard.security.KeyPair;
+
+import java.math.BigInteger;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import static cz.crcs.ectester.common.test.Result.ExpectedValue;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardWrongSuite extends CardTestSuite {
+
+ public CardWrongSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
+ super(writer, cfg, cardManager, "wrong", "The wrong curve suite tests whether the card rejects domain parameters which are not curves.");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ /* Just do the default run on the wrong curves.
+ * These should generally fail, the curves aren't curves.
+ */
+ Map<String, EC_Curve> curves = EC_Store.getInstance().getObjects(EC_Curve.class, "wrong");
+ for (Map.Entry<String, EC_Curve> e : curves.entrySet()) {
+ EC_Curve curve = e.getValue();
+ List<Test> tests = new LinkedList<>();
+ Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
+ if (!key.ok()) {
+ doTest(CompoundTest.all(ExpectedValue.FAILURE, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()), key));
+ continue;
+ }
+ tests.add(key);
+ Test set = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.FAILURE));
+ Test generate = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.FAILURE));
+ Test setup = runTest(CompoundTest.any(ExpectedValue.SUCCESS, "Set wrong curve and generate keypairs.", set, generate));
+ tests.add(setup);
+
+ for (byte kaType : EC_Consts.KA_TYPES) {
+ Test allocate = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), ExpectedValue.SUCCESS));
+ if (allocate.ok()) {
+ Test ka = runTest(CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType), ExpectedValue.FAILURE));
+ Test kaTest = runTest(CompoundTest.all(ExpectedValue.SUCCESS, "Allocate and perform KA.", allocate, ka));
+ tests.add(kaTest);
+ }
+ }
+ doTest(CompoundTest.function((tsts) -> {
+ for (int i = 0; i < tsts.length; ++i) {
+ if (i != 1 && !tsts[i].ok()) {
+ return new Result(Result.Value.FAILURE, "Some tests did not have the expected result.");
+ }
+ }
+ return new Result(Result.Value.SUCCESS, "All tests had the expected result.");
+ }, "Wrong curve test of " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()), tests.toArray(new Test[0])));
+ }
+ /*
+ * Do some interesting tests with corrupting the custom curves.
+ * For prime field:
+ * - p = 0
+ * - p = 1
+ * - p is a square of a prime
+ * - p is a composite q * s with q, s primes
+ * - TODO: p divides discriminant
+ */
+ Random r = new Random();
+ for (short keyLength : EC_Consts.FP_SIZES) {
+ byte curve = EC_Consts.getCurve(keyLength, KeyPair.ALG_EC_FP);
+ Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_FP), ExpectedValue.SUCCESS));
+ if (!key.ok()) {
+ doTest(CompoundTest.all(ExpectedValue.FAILURE, "No support for " + keyLength + "b ALG_EC_FP.", key));
+ continue;
+ }
+ Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, curve, EC_Consts.PARAMETERS_DOMAIN_FP, null), ExpectedValue.SUCCESS);
+ Test setup = CompoundTest.all(ExpectedValue.SUCCESS, "KeyPair setup.", key, set);
+
+ Test prime0 = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_FP, EC_Consts.TRANSFORMATION_ZERO), "Set p = 0.", "ECDH with p = 0.");
+ Test prime1 = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_FP, EC_Consts.TRANSFORMATION_ONE), "Set p = 1.", "ECDH with p = 1.");
+
+ short keyHalf = (short) (keyLength / 2);
+ BigInteger prime = new BigInteger(keyHalf, 50, r);
+ BigInteger primePow = prime.pow(2);
+ byte[] primePowBytes = ECUtil.toByteArray(primePow, keyLength);
+ EC_Params primePowData = new EC_Params(EC_Consts.PARAMETER_FP, new byte[][]{primePowBytes});
+ Test primePower = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, primePowData.getParams(), primePowData.flatten()), "Set p = square of a prime.", "ECDH with p = q^2.");
+
+ BigInteger q = new BigInteger(keyHalf, r);
+ BigInteger s = new BigInteger(keyHalf, r);
+ BigInteger compositeValue = q.multiply(s);
+ byte[] compositeBytes = ECUtil.toByteArray(compositeValue, keyLength);
+ EC_Params compositeData = new EC_Params(EC_Consts.PARAMETER_FP, new byte[][]{compositeBytes});
+ Test composite = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, compositeData.getParams(), compositeData.flatten()), "Set p = product of two primes.", "ECDH with p = q * s.");
+
+ Test wrongPrime = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted prime parameter.", prime0, prime1, primePower, composite);
+
+ Test resetSetup = CompoundTest.all(ExpectedValue.SUCCESS, "Reset keypair.", set.clone());
+
+ Test randomG = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_G, (short) (EC_Consts.TRANSFORMATION_FULLRANDOM | EC_Consts.TRANSFORMATION_04_MASK)), "Set G = random non-point/point-like.", "ECDH with non-point G.");
+ Test fullRandomG = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_G, EC_Consts.TRANSFORMATION_FULLRANDOM), "Set G = random data.", "ECDH with G = random data.");
+ Test zeroG = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_G, EC_Consts.TRANSFORMATION_INFINITY), "Set G = inifnity.", "ECDH with G = infinity.");
+ Test wrongG = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted G parameter.", randomG, fullRandomG, zeroG);
+
+ byte[] originalR = new byte[keyLength];
+ EC_Consts.getCurveParameter(curve, EC_Consts.PARAMETER_R, originalR, (short) 0);
+ BigInteger originalBigR = new BigInteger(1, originalR);
+
+ Test zeroR = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, EC_Consts.PARAMETER_R, EC_Consts.TRANSFORMATION_ZERO), "Set R = 0.", "ECDH with R = 0.");
+ Test oneR = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, EC_Consts.PARAMETER_R, EC_Consts.TRANSFORMATION_ONE), "Set R = 1.", "ECDH with R = 1.");
+
+ BigInteger prevPrimeR;
+ do {
+ prevPrimeR = BigInteger.probablePrime(originalBigR.bitLength() - 1, r);
+ } while (prevPrimeR.compareTo(originalBigR) >= 0);
+ byte[] prevRBytes = ECUtil.toByteArray(prevPrimeR, keyLength);
+ EC_Params prevRData = new EC_Params(EC_Consts.PARAMETER_R, new byte[][]{prevRBytes});
+ Test prevprimeWrongR = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, prevRData.getParams(), prevRData.flatten()), "Set R = some prime (but [r]G != infinity) smaller than original R.", "ECDH with wrong R, prevprime.");
+
+ BigInteger nextPrimeR = originalBigR.nextProbablePrime();
+ byte[] nextRBytes = ECUtil.toByteArray(nextPrimeR, keyLength);
+ EC_Params nextRData = new EC_Params(EC_Consts.PARAMETER_R, new byte[][]{nextRBytes});
+ Test nextprimeWrongR = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, nextRData.getParams(), nextRData.flatten()), "Set R = some prime (but [r]G != infinity) larger than original R.", "ECDH with wrong R, nextprime.");
+
+ byte[] nonprimeRBytes = nextRBytes.clone();
+ nonprimeRBytes[0] ^= 1;
+ EC_Params nonprimeWrongRData = new EC_Params(EC_Consts.PARAMETER_R, new byte[][]{nonprimeRBytes});
+ Test nonprimeWrongR = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, nonprimeWrongRData.getParams(), nonprimeWrongRData.flatten()), "Set R = some composite (but [r]G != infinity).", "ECDH with wrong R, composite.");
+
+ Test wrongR = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted R parameter.", zeroR, oneR, prevprimeWrongR, nextprimeWrongR, nonprimeWrongR);
+
+ byte[] kRaw = new byte[]{(byte) 0xff};
+ EC_Params kData = new EC_Params(EC_Consts.PARAMETER_K, new byte[][]{kRaw});
+ Test bigK = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, kData.getParams(), kData.flatten()), "", "");
+
+ byte[] kZero = new byte[]{(byte) 0};
+ EC_Params kZeroData = new EC_Params(EC_Consts.PARAMETER_K, new byte[][]{kZero});
+ Test zeroK = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, kZeroData.getParams(), kZeroData.flatten()), "", "");
+
+ Test wrongK = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted K parameter.", bigK, zeroK);
+
+ doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(KeyPair.ALG_EC_FP), setup, wrongPrime, resetSetup, wrongG, resetSetup.clone(), wrongR, resetSetup.clone(), wrongK, resetSetup.clone()));
+ }
+
+ /*
+ * For binary field:
+ * - e1, e2 or e3 is larger than m.
+ * - e1 = e2 = e3 = 0
+ */
+ for (short keyLength : EC_Consts.F2M_SIZES) {
+ byte curve = EC_Consts.getCurve(keyLength, KeyPair.ALG_EC_F2M);
+ Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_F2M), ExpectedValue.SUCCESS));
+ if (!key.ok()) {
+ doTest(CompoundTest.all(ExpectedValue.FAILURE, "No support for " + keyLength + "b ALG_EC_F2M.", key));
+ continue;
+ }
+ Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, curve, EC_Consts.PARAMETERS_DOMAIN_F2M, null), ExpectedValue.SUCCESS);
+ Test setup = CompoundTest.all(ExpectedValue.SUCCESS, "KeyPair setup.", key, set);
+
+ Test coeff0 = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_F2M, EC_Consts.TRANSFORMATION_ZERO), "Set e1 = e2 = e3 = 0.", "ECDH with wrong field polynomial: x^" + keyLength);
+
+ short e1 = (short) (2 * keyLength);
+ short e2 = (short) (3 * keyLength);
+ short e3 = (short) (4 * keyLength);
+ byte[][] coeffBytes = new byte[][]{
+ ByteUtil.shortToBytes(keyLength),
+ ByteUtil.shortToBytes(e1),
+ ByteUtil.shortToBytes(e2),
+ ByteUtil.shortToBytes(e3)};
+ EC_Params coeffParams = new EC_Params(EC_Consts.PARAMETER_F2M, coeffBytes);
+ Test coeffLarger = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, coeffParams.getParams(), coeffParams.flatten()), "Set e1=" + e1 + ", e2=" + e2 + ", e3=" + e3, "ECDH with wrong field poly, powers larger than " + keyLength);
+
+ Test wrong = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted field polynomial parameter.", coeff0, coeffLarger);
+ doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(KeyPair.ALG_EC_F2M), setup, wrong));
+ }
+
+ /*
+ * TODO: tests for both Fp and F2m:
+ * - generator not on curve,
+ * - generator not on proper subgroup of curve(as specified by order/cofactor),
+ * - wrong order,
+ * - wrong cofactor.
+ */
+ }
+
+ private Test ecdhTest(Command setupCmd, String prepareDesc, String fullDesc) {
+ Test setup = CommandTest.expect(setupCmd, ExpectedValue.FAILURE);
+ Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.FAILURE);
+ Test preparePhase = CompoundTest.any(ExpectedValue.SUCCESS, prepareDesc, setup, generate);
+ Test allocateECDH = CommandTest.expect(new Command.AllocateKeyAgreement(this.card, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), ExpectedValue.SUCCESS);
+ Test ecdh = 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), ExpectedValue.FAILURE);
+
+
+ return CompoundTest.function((tests) -> {
+ if (preparePhase.ok() | !allocateECDH.ok() | ecdh.ok()) {
+ return new Result(Result.Value.SUCCESS, "All tests had the expected result.");
+ } else {
+ return new Result(Result.Value.FAILURE, "Some tests did not have the expected result.");
+ }
+ }, (tests) -> {
+ preparePhase.run();
+ if (preparePhase.ok()) {
+ return;
+ }
+ allocateECDH.run();
+ if (!allocateECDH.ok()) {
+ return;
+ }
+ ecdh.run();
+ }, fullDesc, preparePhase, allocateECDH, ecdh);
+ }
+}