diff options
| author | quapka | 2024-06-21 16:31:37 +0200 |
|---|---|---|
| committer | quapka | 2024-06-21 16:31:37 +0200 |
| commit | ada61982cc70a2c72a6fc765dc9b4a9c01202a27 (patch) | |
| tree | d92bee42106e850d4da90ad7174ac609ca175eda /standalone/src | |
| parent | c051ef2ecfa92723d6dea675ac8c345be92cf165 (diff) | |
| parent | c112d3e49bbbbf33cc70d12d196e109543c19a3c (diff) | |
| download | ECTester-ada61982cc70a2c72a6fc765dc9b4a9c01202a27.tar.gz ECTester-ada61982cc70a2c72a6fc765dc9b4a9c01202a27.tar.zst ECTester-ada61982cc70a2c72a6fc765dc9b4a9c01202a27.zip | |
Merge branch 'master' into build-with-nix
Diffstat (limited to 'standalone/src')
43 files changed, 1529 insertions, 508 deletions
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java b/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java index c702dee..e6d8188 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -36,10 +36,9 @@ import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; import cz.crcs.ectester.standalone.consts.SignatureIdent; import cz.crcs.ectester.standalone.libs.*; +import cz.crcs.ectester.standalone.libs.jni.SignalException; +import cz.crcs.ectester.standalone.libs.jni.TimeoutException; import cz.crcs.ectester.standalone.output.FileTestWriter; -import cz.crcs.ectester.standalone.output.TextTestWriter; -import cz.crcs.ectester.standalone.output.XMLTestWriter; -import cz.crcs.ectester.standalone.output.YAMLTestWriter; import cz.crcs.ectester.standalone.test.suites.*; import org.apache.commons.cli.*; @@ -55,8 +54,7 @@ import java.math.BigInteger; import java.nio.file.Files; import java.nio.file.Path; import java.security.*; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; +import java.security.interfaces.*; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; @@ -105,8 +103,13 @@ public class ECTesterStandalone { reqs.toFile().mkdirs(); if (!System.getProperty("os.name").startsWith("Windows")) { - FileUtil.writeNewer(LIB_RESOURCE_DIR + "lib_timing.so", reqs.resolve("lib_timing.so")); + FileUtil.write(LIB_RESOURCE_DIR + "lib_timing.so", reqs.resolve("lib_timing.so")); System.load(reqs.resolve("lib_timing.so").toString()); + + FileUtil.write(LIB_RESOURCE_DIR + "lib_csignals.so", reqs.resolve("lib_csignals.so")); + System.load(reqs.resolve("lib_csignals.so").toString()); + FileUtil.write(LIB_RESOURCE_DIR + "lib_cppsignals.so", reqs.resolve("lib_cppsignals.so")); + System.load(reqs.resolve("lib_cppsignals.so").toString()); } List<ProviderECLibrary> libObjects = new LinkedList<>(); @@ -133,16 +136,6 @@ public class ECTesterStandalone { } libs = libObjects.toArray(new ProviderECLibrary[0]); - //TODO: push this further down to only initialize if necessary. - // and only initialize the chosen lib (so give libs a name in Java only) - for (ECLibrary lib : libs) { - try { - lib.initialize(); - } catch (Exception ex) { - System.err.println(ex.getMessage()); - } - } - cfg = new Config(libs); if (!cfg.readOptions(cli)) { return; @@ -299,26 +292,36 @@ public class ECTesterStandalone { */ private void listLibraries() { for (ProviderECLibrary lib : libs) { - if (lib.isInitialized() && (cfg.selected == null || lib == cfg.selected)) { + if (cfg.selected == null || lib == cfg.selected) { + try { + if (!lib.initialize()) { + continue; + } + } catch (Exception ex) { + System.err.println("Error initializing " + lib.fullName()); + System.err.println(ex.getMessage()); + continue; + } + System.out.println("\t- " + Colors.bold(lib.name())); System.out.println(Colors.bold("\t\t- Fullname: ") + lib.getProvider().getName()); System.out.println(Colors.bold("\t\t- Version: ") + lib.getProvider().getVersionStr()); System.out.println(Colors.bold("\t\t- Supports native timing: ") + lib.getNativeTimingSupport().toString()); Set<KeyPairGeneratorIdent> kpgs = lib.getKPGs(); if (!kpgs.isEmpty()) { - System.out.println(Colors.bold("\t\t- KeyPairGenerators: ") + kpgs.stream().map(KeyPairGeneratorIdent::getName).collect(Collectors.joining(", "))); + System.out.println(Colors.bold("\t\t- KeyPairGenerators: ") + kpgs.stream().map(KeyPairGeneratorIdent::getName).sorted().collect(Collectors.joining(", "))); } Set<KeyAgreementIdent> eckas = lib.getKAs(); if (!eckas.isEmpty()) { - System.out.println(Colors.bold("\t\t- KeyAgreements: ") + eckas.stream().map(KeyAgreementIdent::getName).collect(Collectors.joining(", "))); + System.out.println(Colors.bold("\t\t- KeyAgreements: ") + eckas.stream().map(KeyAgreementIdent::getName).sorted().collect(Collectors.joining(", "))); } Set<SignatureIdent> sigs = lib.getSigs(); if (!sigs.isEmpty()) { - System.out.println(Colors.bold("\t\t- Signatures: ") + sigs.stream().map(SignatureIdent::getName).collect(Collectors.joining(", "))); + System.out.println(Colors.bold("\t\t- Signatures: ") + sigs.stream().map(SignatureIdent::getName).sorted().collect(Collectors.joining(", "))); } Set<String> curves = lib.getCurves(); if (!curves.isEmpty()) { - System.out.println(Colors.bold("\t\t- Curves: ") + String.join(", ", curves)); + System.out.println(Colors.bold("\t\t- Curves: ") + curves.stream().sorted().collect(Collectors.joining(", "))); } System.out.println(); } @@ -458,8 +461,8 @@ public class ECTesterStandalone { other = kpg.genKeyPair(); } - ECPrivateKey privkey = (ECPrivateKey) ECUtil.loadKey(EC_Consts.PARAMETER_S, cli.getOptionValue("ecdh.named-private"), cli.getOptionValue("ecdh.private"), spec); - ECPublicKey pubkey = (ECPublicKey) ECUtil.loadKey(EC_Consts.PARAMETER_W, cli.getOptionValue("ecdh.named-public"), cli.getOptionValue("ecdh.public"), spec); + PrivateKey privkey = (ECPrivateKey) ECUtil.loadKey(EC_Consts.PARAMETER_S, cli.getOptionValue("ecdh.named-private"), cli.getOptionValue("ecdh.private"), spec); + PublicKey pubkey = (ECPublicKey) ECUtil.loadKey(EC_Consts.PARAMETER_W, cli.getOptionValue("ecdh.named-public"), cli.getOptionValue("ecdh.public"), spec); int amount = Integer.parseInt(cli.getOptionValue("ecdh.amount", "1")); for (int i = 0; i < amount || amount == 0; ++i) { @@ -471,11 +474,11 @@ public class ECTesterStandalone { } if (!cli.hasOption("ecdh.named-private") && !cli.hasOption("ecdh.private")) { - privkey = (ECPrivateKey) one.getPrivate(); + privkey = one.getPrivate(); } if (!cli.hasOption("ecdh.named-public") && !cli.hasOption("ecdh.public")) { - pubkey = (ECPublicKey) other.getPublic(); + pubkey = other.getPublic(); } long elapsed = -System.nanoTime(); @@ -501,8 +504,8 @@ public class ECTesterStandalone { } ka = kaIdent.getInstance(lib.getProvider()); - String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false); - String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false); + String pub = ByteUtil.bytesToHex(ECUtil.pubkeyToBytes(pubkey), false); + String priv = ByteUtil.bytesToHex(ECUtil.privkeyToBytes(privkey), false); String dh = ByteUtil.bytesToHex(result, false); out.printf("%d;%d;%s;%s;%s%n", i, elapsed, pub, priv, dh); } @@ -605,17 +608,17 @@ public class ECTesterStandalone { String hashAlgoOut = sigIdent.getHashAlgo() != null ? String.format("[%s]", sigIdent.getHashAlgo()) : ""; out.printf("index;signTime[%s];verifyTime[%s];data;pubW;privS;signature%s;nonce;verified%n", timeUnit, timeUnit, hashAlgoOut); - ECPrivateKey privkey = (ECPrivateKey) ECUtil.loadKey(EC_Consts.PARAMETER_S, cli.getOptionValue("ecdsa.named-private"), cli.getOptionValue("ecdsa.private"), spec); - ECPublicKey pubkey = (ECPublicKey) ECUtil.loadKey(EC_Consts.PARAMETER_W, cli.getOptionValue("ecdsa.named-public"), cli.getOptionValue("ecdsa.public"), spec); + PrivateKey privkey = (ECPrivateKey) ECUtil.loadKey(EC_Consts.PARAMETER_S, cli.getOptionValue("ecdsa.named-private"), cli.getOptionValue("ecdsa.private"), spec); + PublicKey pubkey = (ECPublicKey) ECUtil.loadKey(EC_Consts.PARAMETER_W, cli.getOptionValue("ecdsa.named-public"), cli.getOptionValue("ecdsa.public"), spec); KeyPair one; if (cli.hasOption("ecdsa.fixed")) { one = kpg.genKeyPair(); if (!cli.hasOption("ecdsa.named-private")) { - privkey = (ECPrivateKey) one.getPrivate(); + privkey = one.getPrivate(); } if (!cli.hasOption("ecdsa.named-public")) { - pubkey = (ECPublicKey) one.getPublic(); + pubkey = one.getPublic(); } } @@ -626,10 +629,10 @@ public class ECTesterStandalone { one = kpg.genKeyPair(); if (!cli.hasOption("ecdsa.named-private")) { - privkey = (ECPrivateKey) one.getPrivate(); + privkey = one.getPrivate(); } if (!cli.hasOption("ecdsa.named-public")) { - pubkey = (ECPublicKey) one.getPublic(); + pubkey = one.getPublic(); } } @@ -653,27 +656,31 @@ public class ECTesterStandalone { verifyTime = lib.getLastNativeTiming(); } - String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false); - String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false); + String pub = ByteUtil.bytesToHex(ECUtil.pubkeyToBytes(pubkey), false); + String priv = ByteUtil.bytesToHex(ECUtil.privkeyToBytes(privkey), false); String sign = ByteUtil.bytesToHex(signature, false); String k = ""; - ECParameterSpec kSpec = spec; - if (kSpec == null) { - kSpec = privkey.getParams(); - } - if (kSpec != null) { - // Parse the types out of SignatureIdent. - String hashAlgo = sigIdent.getHashAlgo(); - String sigType = sigIdent.getSigType(); - if (sigType == null) { - sigType = sigIdent.toString(); + if (privkey instanceof ECPrivateKey) { + ECPrivateKey ecPrivateKey = (ECPrivateKey) privkey; + ECParameterSpec kSpec = spec; + if (kSpec == null) { + kSpec = ecPrivateKey.getParams(); } + if (kSpec != null) { + // Parse the types out of SignatureIdent. + String hashAlgo = sigIdent.getHashAlgo(); + String sigType = sigIdent.getSigType(); + if (sigType == null) { + sigType = sigIdent.toString(); + } - BigInteger kValue = ECUtil.recoverSignatureNonce(signature, data, privkey.getS(), kSpec, hashAlgo, sigType); - if (kValue != null) { - k = ByteUtil.bytesToHex(kValue.toByteArray(), false); + BigInteger kValue = ECUtil.recoverSignatureNonce(signature, data, ecPrivateKey.getS(), kSpec, hashAlgo, sigType); + if (kValue != null) { + k = ByteUtil.bytesToHex(kValue.toByteArray(), false); + } } } + out.printf("%d;%d;%d;%s;%s;%s;%s;%s;%d%n", i, signTime, verifyTime, dataString, pub, priv, sign, k, verified ? 1 : 0); } @@ -739,16 +746,31 @@ public class ECTesterStandalone { int amount = Integer.parseInt(cli.getOptionValue("generate.amount", "1")); for (int i = 0; i < amount || amount == 0; ++i) { long elapsed = -System.nanoTime(); - KeyPair kp = kpg.genKeyPair(); + KeyPair kp; + try { + kp = kpg.genKeyPair(); + } catch (SignalException exc) { + System.err.println(exc.getSigInfo()); + continue; + } catch (TimeoutException exc) { + System.err.println(exc); + continue; + } elapsed += System.nanoTime(); if (!lib.getNativeTimingSupport().isEmpty()) { elapsed = lib.getLastNativeTiming(); } - ECPublicKey publicKey = (ECPublicKey) kp.getPublic(); - ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate(); - - String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(publicKey.getW(), publicKey.getParams()), false); - String priv = ByteUtil.bytesToHex(privateKey.getS().toByteArray(), false); + PublicKey pubkey = kp.getPublic(); + PrivateKey privkey = kp.getPrivate(); + byte[] pubBytes = ECUtil.pubkeyToBytes(pubkey); + byte[] privBytes = ECUtil.privkeyToBytes(privkey); + String pub = ByteUtil.bytesToHex(pubBytes, false); + String priv = ByteUtil.bytesToHex(privBytes, false); + if (pubBytes == null || privBytes == null) { + System.err.println(pubkey.getClass().getCanonicalName()); + System.err.println(privkey.getClass().getCanonicalName()); + break; + } out.printf("%d;%d;%s;%s%n", i, elapsed, pub, priv); } @@ -763,8 +785,40 @@ public class ECTesterStandalone { private void test() throws TestException, ParserConfigurationException, FileNotFoundException { TestWriter writer = new FileTestWriter(cli.getOptionValue("test.format", "text"), !cli.hasOption("test.quiet"), cli.getOptionValues("test.output")); StandaloneTestSuite suite; + String suiteOpt = cli.getArg(0) != null ? cli.getArg(0).toLowerCase() : "default"; + String testSuite; + int testFrom; + int testTo; + if (suiteOpt.contains(":")) { + String[] parts = suiteOpt.split(":"); + if (parts.length < 2 || parts.length > 3) { + System.err.println("Invalid test suite selection."); + return; + } + testSuite = parts[0]; + try { + testFrom = Integer.parseInt(parts[1]); + } catch (NumberFormatException nfe) { + System.err.println("Invalid test_from number: " + parts[1] + "."); + return; + } + if (parts.length == 3) { + try { + testTo = Integer.parseInt(parts[2]); + } catch (NumberFormatException nfe) { + System.err.println("Invalid test_to number: " + parts[2] + "."); + return; + } + } else { + testTo = -1; + } + } else { + testSuite = suiteOpt; + testFrom = 0; + testTo = -1; + } - switch (cli.getArg(0).toLowerCase()) { + switch (testSuite) { case "test-vectors": suite = new StandaloneTestVectorSuite(writer, cfg, cli); break; @@ -798,12 +852,12 @@ public class ECTesterStandalone { case "performance": suite = new StandalonePerformanceSuite(writer, cfg, cli); break; - case "default": default: suite = new StandaloneDefaultSuite(writer, cfg, cli); + break; } - suite.run(); + suite.run(testFrom, testTo); } /** @@ -888,7 +942,7 @@ public class ECTesterStandalone { if (libraryName != null) { List<ProviderECLibrary> matchedLibs = new LinkedList<>(); for (ProviderECLibrary lib : libs) { - if (lib.isInitialized() && lib.name().toLowerCase().contains(libraryName.toLowerCase())) { + if (lib.name().toLowerCase().contains(libraryName.toLowerCase())) { matchedLibs.add(lib); } } @@ -900,6 +954,12 @@ public class ECTesterStandalone { return false; } else { selected = matchedLibs.get(0); + try { + selected.initialize(); + } catch (Exception ex) { + System.err.println("Error initializing " + selected.fullName()); + System.err.println(ex.getMessage()); + } } } } diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java index 60c60e8..c0cf793 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java @@ -18,10 +18,11 @@ public class KeyAgreementIdent extends Ident { private static final List<KeyAgreementIdent> ALL = new LinkedList<>(); static { - //https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html + // https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html // Basic ECDH and ECDHC (plain/raw) ALL.add(new KeyAgreementIdent("ECDH")); ALL.add(new KeyAgreementIdent("ECDHC", "ECCDH")); + // ECDH and ECDHC with SHA as KDF, OIDs from RFC 3278 ALL.add(new KeyAgreementIdent("ECDHwithSHA1KDF", true, "1.3.133.16.840.63.0.2")); ALL.add(new KeyAgreementIdent("ECCDHwithSHA1KDF", true, "1.3.133.16.840.63.0.3")); @@ -33,11 +34,13 @@ public class KeyAgreementIdent extends Ident { ALL.add(new KeyAgreementIdent("ECCDHwithSHA384KDF", true, "1.3.132.1.14.2")); ALL.add(new KeyAgreementIdent("ECDHwithSHA512KDF", true, "1.3.132.1.11.3")); ALL.add(new KeyAgreementIdent("ECCDHwithSHA512KDF", true, "1.3.132.1.14.3")); + // Microsoft specific KDF ALL.add(new KeyAgreementIdent("ECDHwithSHA1KDF(CNG)")); ALL.add(new KeyAgreementIdent("ECDHwithSHA256KDF(CNG)")); ALL.add(new KeyAgreementIdent("ECDHwithSHA384KDF(CNG)")); ALL.add(new KeyAgreementIdent("ECDHwithSHA512KDF(CNG)")); + // CKDF requires custom AlgorithmParameterSpec (only BouncyCastle) //ALL.add(new KeyAgreementIdent("ECDHwithSHA1CKDF", true)); //ALL.add(new KeyAgreementIdent("ECCDHwithSHA1CKDF", true)); @@ -47,6 +50,7 @@ public class KeyAgreementIdent extends Ident { //ALL.add(new KeyAgreementIdent("ECCDHwithSHA384CKDF", true)); //ALL.add(new KeyAgreementIdent("ECDHwithSHA512CKDF", true)); //ALL.add(new KeyAgreementIdent("ECCDHwithSHA512CKDF", true)); + // ECMQV - Disable for now as it needs diferent params(too different from DH) //ALL.add(new KeyAgreementIdent("ECMQV")); //ALL.add(new KeyAgreementIdent("ECMQVwithSHA1KDF", true)); @@ -59,10 +63,16 @@ public class KeyAgreementIdent extends Ident { //ALL.add(new KeyAgreementIdent("ECMQVwithSHA256CKDF", true, "1.3.132.1.15.1")); //ALL.add(new KeyAgreementIdent("ECMQVwithSHA384CKDF", true, "1.3.132.1.15.2")); //ALL.add(new KeyAgreementIdent("ECMQVwithSHA512CKDF", true, "1.3.132.1.15.3")); + // ECVKO - Disable for now as it needs diferent params(too different from DH) //ALL.add(new KeyAgreementIdent("ECVKO", "ECGOST3410", "1.2.643.2.2.19", "GOST-3410-2001", "1.2.643.2.2.96")); //ALL.add(new KeyAgreementIdent("ECVKO256", "ECGOST3410-2012-256", "1.2.643.7.1.1.6.1", "1.2.643.7.1.1.1.1")); //ALL.add(new KeyAgreementIdent("ECVKO512", "ECGOST3410-2012-512", "1.2.643.7.1.1.6.2", "1.2.643.7.1.1.1.2")); + + // XDH (RFC 7748) + ALL.add(new KeyAgreementIdent("XDH")); + ALL.add(new KeyAgreementIdent("X25519")); + ALL.add(new KeyAgreementIdent("X448")); } public static KeyAgreementIdent get(String ident) { diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java index 83eef75..49b982b 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java @@ -11,6 +11,7 @@ public class KeyPairGeneratorIdent extends Ident { private static final List<KeyPairGeneratorIdent> ALL = new LinkedList<>(); static { + // Short-Weierstrass ALL.add(new KeyPairGeneratorIdent("EC")); ALL.add(new KeyPairGeneratorIdent("ECDH")); ALL.add(new KeyPairGeneratorIdent("ECDSA")); @@ -22,6 +23,14 @@ public class KeyPairGeneratorIdent extends Ident { ALL.add(new KeyPairGeneratorIdent("ECKCDSA")); // ECGDSA? Botan provides. ALL.add(new KeyPairGeneratorIdent("ECGDSA")); + // Montgomery + ALL.add(new KeyPairGeneratorIdent("XDH")); + ALL.add(new KeyPairGeneratorIdent("X25519")); + ALL.add(new KeyPairGeneratorIdent("X448")); + // Twisted-Edwards + ALL.add(new KeyPairGeneratorIdent("EdDSA")); + ALL.add(new KeyPairGeneratorIdent("Ed25519")); + ALL.add(new KeyPairGeneratorIdent("Ed448")); } public static KeyPairGeneratorIdent get(String ident) { diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/consts/SignatureIdent.java b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/SignatureIdent.java index c3913b7..a65d0c5 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/consts/SignatureIdent.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/SignatureIdent.java @@ -30,17 +30,20 @@ public class SignatureIdent extends Ident { ALL.add(new SignatureIdent("SHA3-384withECDSA", "SHA3-384/ECDSA", "2.16.840.1.101.3.4.3.11")); ALL.add(new SignatureIdent("SHA3-512withECDSA", "SHA3-512/ECDSA", "2.16.840.1.101.3.4.3.12")); ALL.add(new SignatureIdent("RIPEMD160withECDSA", "RIPEMD160/ECDSA", "1.3.36.3.3.2.2")); + // ECNR ALL.add(new SignatureIdent("SHA1withECNR")); ALL.add(new SignatureIdent("SHA224withECNR")); ALL.add(new SignatureIdent("SHA256withECNR")); ALL.add(new SignatureIdent("SHA512withECNR")); + // CVC-ECDSA ALL.add(new SignatureIdent("SHA1withCVC-ECDSA", "SHA1/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.1")); ALL.add(new SignatureIdent("SHA224withCVC-ECDSA", "SHA224/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.2")); ALL.add(new SignatureIdent("SHA256withCVC-ECDSA", "SHA256/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.3")); ALL.add(new SignatureIdent("SHA384withCVC-ECDSA", "SHA384/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.4")); ALL.add(new SignatureIdent("SHA512withCVC-ECDSA", "SHA512/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.5")); + // PLAIN-ECDSA ALL.add(new SignatureIdent("SHA1withPLAIN-ECDSA", "SHA1/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.1")); ALL.add(new SignatureIdent("SHA224withPLAIN-ECDSA", "SHA224/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.2")); @@ -48,6 +51,7 @@ public class SignatureIdent extends Ident { ALL.add(new SignatureIdent("SHA384withPLAIN-ECDSA", "SHA384/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.4")); ALL.add(new SignatureIdent("SHA512withPLAIN-ECDSA", "SHA512/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.5")); ALL.add(new SignatureIdent("RIPEMD160withPLAIN-ECDSA", "RIPEMD160/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.6")); + // ECGOST ALL.add(new SignatureIdent("ECGOST3410", "ECGOST-3410", "GOST-3410-2001")); ALL.add(new SignatureIdent("GOST3411withECGOST3410", "GOST3411/ECGOST3410", "1.2.643.2.2.3")); @@ -56,6 +60,7 @@ public class SignatureIdent extends Ident { ALL.add(new SignatureIdent("ECGOST3410-2012-512", "GOST-3410-2012-512")); ALL.add(new SignatureIdent("GOST3411-2012-512withECGOST3410-2012-512", "GOST3411-2012-512/ECGOST3410-2012-5120", "1.2.643.7.1.1.3.3")); ALL.add(new SignatureIdent("SM3withSM2")); + // ECDDSA (rfc6979?) ALL.add(new SignatureIdent("ECDDSA", "SHA1withECDDSA", "SHA1withDETECDSA", "DETECDSA", "ECDETDSA")); ALL.add(new SignatureIdent("SHA224withECDDSA", "SHA224withDETECDSA")); @@ -66,6 +71,7 @@ public class SignatureIdent extends Ident { ALL.add(new SignatureIdent("SHA3-256withECDDSA", "SHA3-256withDETECDSA")); ALL.add(new SignatureIdent("SHA3-384withECDDSA", "SHA3-384withDETECDSA")); ALL.add(new SignatureIdent("SHA3-512withECDDSA", "SHA3-512withDETECDSA")); + // ECKCDSA? Botan provides. ALL.add(new SignatureIdent("ECKCDSA", "SHA1withECKCDSA", "1.2.410.200004.1.100.4.3")); ALL.add(new SignatureIdent("NONEwithECKCDSA")); @@ -74,6 +80,7 @@ public class SignatureIdent extends Ident { ALL.add(new SignatureIdent("SHA256withECKCDSA", "1.2.410.200004.1.100.4.5")); ALL.add(new SignatureIdent("SHA384withECKCDSA")); ALL.add(new SignatureIdent("SHA512withECKCDSA")); + // ECGDSA? Botan provides. ALL.add(new SignatureIdent("ECGDSA", "SHA1withECGDSA", "1.3.36.3.3.2.5.4.2")); ALL.add(new SignatureIdent("NONEwithECGDSA")); @@ -82,6 +89,11 @@ public class SignatureIdent extends Ident { ALL.add(new SignatureIdent("SHA224withECGDSA", "1.3.36.3.3.2.5.4.4")); ALL.add(new SignatureIdent("SHA384withECGDSA", "1.3.36.3.3.2.5.4.5")); ALL.add(new SignatureIdent("SHA512withECGDSA", "1.3.36.3.3.2.5.4.6")); + + // EdDSA (RFC 8032) + ALL.add(new SignatureIdent("EdDSA")); + ALL.add(new SignatureIdent("Ed25519")); + ALL.add(new SignatureIdent("Ed448")); } public static SignatureIdent get(String ident) { diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NativeECLibrary.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NativeECLibrary.java index 7f9d96e..c11dbdb 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NativeECLibrary.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NativeECLibrary.java @@ -33,7 +33,7 @@ public abstract class NativeECLibrary extends ProviderECLibrary { Path libPath = libDir.resolve(resource + "." + suffix); /* Write the shim. */ - boolean found = FileUtil.writeNewer(ECTesterStandalone.LIB_RESOURCE_DIR + resource + "." + suffix, libPath); + boolean found = FileUtil.write(ECTesterStandalone.LIB_RESOURCE_DIR + resource + "." + suffix, libPath); if (!found) { return false; } @@ -44,7 +44,7 @@ public abstract class NativeECLibrary extends ProviderECLibrary { if (requirement.endsWith(suffix)) { /* The requirement is bundled, write it */ Path reqPath = libReqDir.resolve(requirement); - found = FileUtil.writeNewer(ECTesterStandalone.LIB_RESOURCE_DIR + requirement, reqPath); + found = FileUtil.write(ECTesterStandalone.LIB_RESOURCE_DIR + requirement, reqPath); if (!found) { return false; } diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NettleLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NettleLib.java index 6b60779..d4df414 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NettleLib.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NettleLib.java @@ -1,6 +1,15 @@ package cz.crcs.ectester.standalone.libs; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.util.ECUtil; +import cz.crcs.ectester.data.EC_Store; + +import java.security.InvalidAlgorithmParameterException; import java.security.Provider; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.util.Arrays; import java.util.Set; /** @@ -17,4 +26,27 @@ public class NettleLib extends NativeECLibrary { @Override public native Set<String> getCurves(); + + public static ECGenParameterSpec parametersKnown(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { + if (params instanceof ECGenParameterSpec) { + if (Arrays.asList("secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1").contains(((ECGenParameterSpec) params).getName())) { + return (ECGenParameterSpec) params; + } + } else if (params instanceof ECParameterSpec) { + ECParameterSpec spec = (ECParameterSpec) params; + EC_Store store = EC_Store.getInstance(); + if (ECUtil.equalECParameterSpec(spec, store.getObject(EC_Curve.class, "secg/secp192r1").toSpec())) { + return new ECGenParameterSpec("secp192r1"); + } else if (ECUtil.equalECParameterSpec(spec, store.getObject(EC_Curve.class, "secg/secp224r1").toSpec())) { + return new ECGenParameterSpec("secp224r1"); + } else if (ECUtil.equalECParameterSpec(spec, store.getObject(EC_Curve.class, "secg/secp256r1").toSpec())) { + return new ECGenParameterSpec("secp256r1"); + } else if (ECUtil.equalECParameterSpec(spec, store.getObject(EC_Curve.class, "secg/secp384r1").toSpec())) { + return new ECGenParameterSpec("secp384r1"); + } else if (ECUtil.equalECParameterSpec(spec, store.getObject(EC_Curve.class, "secg/secp521r1").toSpec())) { + return new ECGenParameterSpec("secp521r1"); + } + } + throw new InvalidAlgorithmParameterException("Unknown curve."); + } } diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java index a9a49e9..d9d6749 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java @@ -104,6 +104,10 @@ public abstract class ProviderECLibrary implements ECLibrary { return name; } + public String fullName() { + return name() + " (" + provider.getName() + ")"; + } + public Provider getProvider() { return provider; } diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java index afed02b..d9a4d40 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java @@ -1,6 +1,9 @@ package cz.crcs.ectester.standalone.libs.jni; +import cz.crcs.ectester.common.ec.EC_Curve; import cz.crcs.ectester.common.util.ECUtil; +import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.standalone.libs.NettleLib; import javax.crypto.KeyAgreementSpi; import javax.crypto.SecretKey; @@ -11,7 +14,6 @@ import java.security.interfaces.ECPublicKey; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; -import java.security.spec.InvalidParameterSpecException; /** * @author Jan Jancar johny@neuromancer.sk @@ -61,6 +63,22 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { return secret.length; } + protected byte[] getPubkey() { + if (publicKey instanceof NativeECPublicKey) { + return ((NativeECPublicKey) publicKey).getData(); + } else { + return ECUtil.pubkeyToBytes(publicKey); + } + } + + protected byte[] getPrivkey() { + if (privateKey instanceof NativeECPrivateKey) { + return ((NativeECPrivateKey) privateKey).getData(); + } else { + return ECUtil.privkeyToBytes(privateKey); + } + } + private abstract static class SimpleKeyAgreementSpi extends NativeKeyAgreementSpi { @Override @@ -72,51 +90,79 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { this.params = params; } - private byte[] getPubkey() { - if (publicKey instanceof NativeECPublicKey) { - return ((NativeECPublicKey) publicKey).getData(); - } else { - return ECUtil.toX962Uncompressed(publicKey.getW(), ((ECParameterSpec) params)); + @Override + protected byte[] engineGenerateSecret() throws IllegalStateException { + return generateSecret(getPubkey(), getPrivkey(), (ECParameterSpec) params); + } + + abstract byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params); + + @Override + protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException { + if (algorithm == null) { + throw new NoSuchAlgorithmException("Algorithm must not be null."); } + return generateSecret(getPubkey(), getPrivkey(), (ECParameterSpec) params, algorithm); } - private byte[] getPrivkey() { - if (privateKey instanceof NativeECPrivateKey) { - return ((NativeECPrivateKey) privateKey).getData(); - } else { - return ECUtil.toByteArray(privateKey.getS(), ((ECParameterSpec) params).getOrder().bitLength()); + abstract SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm); + } + + private abstract static class ExtendedKeyAgreementSpi extends NativeKeyAgreementSpi { + + @Override + protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + if (!(params instanceof ECParameterSpec || params instanceof ECGenParameterSpec)) { + throw new InvalidAlgorithmParameterException("Unknown parameter class."); } + engineInit(key, random); + this.params = params; } @Override protected byte[] engineGenerateSecret() throws IllegalStateException { - return generateSecret(getPubkey(), getPrivkey(), (ECParameterSpec) params); + return generateSecret(publicKey, privateKey, params); } - abstract byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params); + abstract byte[] generateSecret(ECPublicKey pubkey, ECPrivateKey privkey, AlgorithmParameterSpec params); @Override protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException { if (algorithm == null) { throw new NoSuchAlgorithmException("Algorithm must not be null"); } - return generateSecret(getPubkey(), getPrivkey(), (ECParameterSpec) params, algorithm); + return generateSecret(publicKey, privateKey, params, algorithm); } - abstract SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm); + abstract SecretKey generateSecret(ECPublicKey pubkey, ECPrivateKey privkey, AlgorithmParameterSpec params, String algorithm); } - private abstract static class ExtendedKeyAgreementSpi extends NativeKeyAgreementSpi { + private abstract static class NamedKeyAgreementSpi extends NativeKeyAgreementSpi { + + @Override + protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException { + if (!(key instanceof ECPrivateKey)) { + throw new InvalidKeyException("Key must be instance of ECPrivateKey"); + } + privateKey = (ECPrivateKey) key; + try { + this.params = parametersKnown(privateKey.getParams()); + } catch (InvalidAlgorithmParameterException e) { + throw new InvalidKeyException(e); + } + } @Override protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { if (!(params instanceof ECParameterSpec || params instanceof ECGenParameterSpec)) { - throw new InvalidAlgorithmParameterException(); + throw new InvalidAlgorithmParameterException("Unknown parameter class."); } engineInit(key, random); - this.params = params; + this.params = parametersKnown(params); } + abstract ECGenParameterSpec parametersKnown(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException; + @Override protected byte[] engineGenerateSecret() throws IllegalStateException { return generateSecret(publicKey, privateKey, params); @@ -374,7 +420,7 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { } } - public abstract static class Nettle extends SimpleKeyAgreementSpi { + public abstract static class Nettle extends NamedKeyAgreementSpi { private final String type; public Nettle(String type) { @@ -382,43 +428,21 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { } @Override - byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params) { - try { - // TODO: OMG remove this monstrosity. - AlgorithmParameters tmp = AlgorithmParameters.getInstance("EC"); - tmp.init(params); - ECGenParameterSpec spec = tmp.getParameterSpec(ECGenParameterSpec.class); - switch (spec.getName()) { - case "1.2.840.10045.3.1.7": - spec = new ECGenParameterSpec("secp256r1"); - break; - case "1.2.840.10045.3.1.1": - spec = new ECGenParameterSpec("secp192r1"); - break; - case "1.3.132.0.33": - spec = new ECGenParameterSpec("secp224r1"); - break; - case "1.3.132.0.34": - spec = new ECGenParameterSpec("secp384r1"); - break; - case "1.3.132.0.35": - spec = new ECGenParameterSpec("secp521r1"); - break; - default: - return null; + ECGenParameterSpec parametersKnown(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { + return NettleLib.parametersKnown(params); + } - } - return generateSecret(pubkey, privkey, spec); + @Override + byte[] generateSecret(ECPublicKey pubkey, ECPrivateKey privkey, AlgorithmParameterSpec params) { + return generateSecret(getPubkey(), getPrivkey(), (ECGenParameterSpec) params); + } - } catch (NoSuchAlgorithmException | InvalidParameterSpecException e) { - return null; - } + @Override + SecretKey generateSecret(ECPublicKey pubkey, ECPrivateKey privkey, AlgorithmParameterSpec params, String algorithm) { + throw new UnsupportedOperationException("Not supported."); } native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECGenParameterSpec params); - - @Override - native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm); } public static class NettleECDH extends Nettle { diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java index 0a9487f..086c2c4 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java @@ -2,6 +2,7 @@ package cz.crcs.ectester.standalone.libs.jni; import cz.crcs.ectester.common.ec.EC_Curve; import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.standalone.libs.NettleLib; import java.security.*; import java.security.spec.AlgorithmParameterSpec; @@ -293,7 +294,7 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { @Override native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random); } - + public static class Libressl extends NativeKeyPairGeneratorSpi { public Libressl() { @@ -319,26 +320,48 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { } @Override - native boolean keysizeSupported(int keysize); + boolean keysizeSupported(int keysize) { + switch (keysize) { + case 192, 224, 256, 384, 521: + return true; + default: + return false; + } + } @Override - native boolean paramsSupported(AlgorithmParameterSpec params); + boolean paramsSupported(AlgorithmParameterSpec params) { + try { + NettleLib.parametersKnown(params); + return true; + } catch (InvalidAlgorithmParameterException ignored) { + return false; + } + } @Override - native KeyPair generate(int keysize, SecureRandom random); + KeyPair generate(int keysize, SecureRandom random) { + EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, "secg/secp" + keysize + "r1"); + return generate(keysize, random, curve.toSpec()); + } + + native KeyPair generate(int keysize, SecureRandom random, AlgorithmParameterSpec spec); @Override KeyPair generate(AlgorithmParameterSpec params, SecureRandom random) { - if (params instanceof ECGenParameterSpec) { - String curveName = ((ECGenParameterSpec) params).getName(); - if (curveName.contains("secp")) { - curveName = "secg/" + curveName; - } - EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName); - ECParameterSpec spec = curve.toSpec(); - return generate(params, random, spec); + ECGenParameterSpec named; + try { + named = NettleLib.parametersKnown(params); + } catch (InvalidAlgorithmParameterException ignored) { + return null; + } + String curveName = named.getName(); + if (curveName.startsWith("secp")) { + curveName = "secg/" + curveName; } - return null; + EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName); + ECParameterSpec spec = curve.toSpec(); + return generate(params, random, spec); } native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random, AlgorithmParameterSpec spec); diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/SigInfo.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/SigInfo.java new file mode 100644 index 0000000..3cb7bad --- /dev/null +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/SigInfo.java @@ -0,0 +1,80 @@ +package cz.crcs.ectester.standalone.libs.jni; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class SigInfo { + + private final int signo; + private final int code; + private final int errno; + private final int pid; + private final int uid; + private final long addr; + private final int status; + private final long band; + private final long sigval; + + public SigInfo(int signo, int code, int errno, int pid, int uid, long addr, int status, long band, long sigval) { + this.signo = signo; + this.code = code; + this.errno = errno; + this.pid = pid; + this.uid = uid; + this.addr = addr; + this.status = status; + this.band = band; + this.sigval = sigval; + } + + public int getSigno() { + return signo; + } + + public int getCode() { + return code; + } + + public int getErrno() { + return errno; + } + + public int getPid() { + return pid; + } + + public int getUid() { + return uid; + } + + public long getAddr() { + return addr; + } + + public int getStatus() { + return status; + } + + public long getBand() { + return band; + } + + public long getSigval() { + return sigval; + } + + @Override + public String toString() { + return "SigInfo{" + + "signo=" + signo + + ", code=" + code + + ", errno=" + errno + + ", pid=" + pid + + ", uid=" + uid + + ", addr=" + addr + + ", status=" + status + + ", band=" + band + + ", sigval=" + sigval + + '}'; + } +} diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/SignalException.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/SignalException.java new file mode 100644 index 0000000..726286e --- /dev/null +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/SignalException.java @@ -0,0 +1,18 @@ +package cz.crcs.ectester.standalone.libs.jni; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class SignalException extends RuntimeException { + + private final SigInfo sigInfo; + + public SignalException(SigInfo sigInfo) { + super("Signal caught."); + this.sigInfo = sigInfo; + } + + public SigInfo getSigInfo() { + return sigInfo; + } +} diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/TimeoutException.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/TimeoutException.java new file mode 100644 index 0000000..c4084b9 --- /dev/null +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/TimeoutException.java @@ -0,0 +1,11 @@ +package cz.crcs.ectester.standalone.libs.jni; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class TimeoutException extends RuntimeException { + + public TimeoutException(String message) { + super(message); + } +} diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/output/TextTestWriter.java b/standalone/src/main/java/cz/crcs/ectester/standalone/output/TextTestWriter.java index ba345e7..c53adb2 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/output/TextTestWriter.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/output/TextTestWriter.java @@ -48,7 +48,7 @@ public class TextTestWriter extends BaseTextTestWriter { StandaloneTestSuite standaloneSuite = (StandaloneTestSuite) suite; StringBuilder sb = new StringBuilder(); sb.append("═══ ").append(Colors.underline("ECTester version:")).append(" ").append(ECTesterStandalone.VERSION).append(System.lineSeparator()); - sb.append("═══ ").append(Colors.underline("Library:")).append(" ").append(standaloneSuite.getLibrary().name()).append(System.lineSeparator()); + sb.append("═══ ").append(Colors.underline("Library:")).append(" ").append(standaloneSuite.getLibrary().fullName()).append(System.lineSeparator()); return sb.toString(); } return ""; diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/output/XMLTestWriter.java b/standalone/src/main/java/cz/crcs/ectester/standalone/output/XMLTestWriter.java index 60751f5..2341fc7 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/output/XMLTestWriter.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/output/XMLTestWriter.java @@ -147,7 +147,7 @@ public class XMLTestWriter extends BaseXMLTestWriter { result.setAttribute("ectester", ECTesterStandalone.VERSION); Element name = doc.createElement("name"); - name.setTextContent(standaloneSuite.getLibrary().name()); + name.setTextContent(standaloneSuite.getLibrary().fullName()); result.appendChild(name); return result; } diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/output/YAMLTestWriter.java b/standalone/src/main/java/cz/crcs/ectester/standalone/output/YAMLTestWriter.java index 664fa18..66c5e38 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/output/YAMLTestWriter.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/output/YAMLTestWriter.java @@ -116,7 +116,7 @@ public class YAMLTestWriter extends BaseYAMLTestWriter { Map<String, Object> result = new LinkedHashMap<>(); result.put("type", "library"); result.put("ectester", ECTesterStandalone.VERSION); - result.put("name", standaloneSuite.getLibrary().name()); + result.put("name", standaloneSuite.getLibrary().fullName()); return result; } return null; diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTest.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTest.java index 32f82cb..8c49224 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTest.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTest.java @@ -4,6 +4,9 @@ import cz.crcs.ectester.common.test.Result; import cz.crcs.ectester.common.test.SimpleTest; import cz.crcs.ectester.common.test.TestCallback; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; + /** * @author Jan Jancar johny@neuromancer.sk */ @@ -38,6 +41,15 @@ public class KeyGeneratorTest extends SimpleTest<KeyGeneratorTestable> { @Override public String getDescription() { - return "KeyPairGenerator " + testable.getKpg().getAlgorithm(); + String params = ""; + if (testable.getKeysize() != 0) { + params = String.format("(default %d-bit curve)", testable.getKeysize()); + } else if (testable.getSpec() instanceof ECGenParameterSpec) { + String name = ((ECGenParameterSpec)testable.getSpec()).getName(); + params = String.format("(%s)", name); + } else if (testable.getSpec() instanceof ECParameterSpec) { + params = "(custom curve)"; + } + return "KeyPairGenerator " + testable.getKpg().getAlgorithm() + " on " + params; } } diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTestable.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTestable.java index 296ec3c..bc44eb8 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTestable.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTestable.java @@ -3,6 +3,8 @@ package cz.crcs.ectester.standalone.test.base; import java.security.InvalidAlgorithmParameterException; import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; /** @@ -12,7 +14,7 @@ public class KeyGeneratorTestable extends StandaloneTestable<KeyGeneratorTestabl private KeyPair kp; private final KeyPairGenerator kpg; private int keysize = 0; - private ECParameterSpec spec = null; + private AlgorithmParameterSpec spec = null; public KeyGeneratorTestable(KeyPairGenerator kpg) { this.kpg = kpg; @@ -28,6 +30,19 @@ public class KeyGeneratorTestable extends StandaloneTestable<KeyGeneratorTestabl this.spec = spec; } + public KeyGeneratorTestable(KeyPairGenerator kpg, ECGenParameterSpec spec) { + this.kpg = kpg; + this.spec = spec; + } + + public int getKeysize() { + return keysize; + } + + public AlgorithmParameterSpec getSpec() { + return spec; + } + public KeyPairGenerator getKpg() { return kpg; } diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCofactorSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCofactorSuite.java index 52b0fbf..bb9a509 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCofactorSuite.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCofactorSuite.java @@ -76,10 +76,10 @@ public class StandaloneCofactorSuite extends StandaloneTestSuite { ECParameterSpec spec = curve.toSpec(); KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec); - Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY); + Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY); runTest(generate); KeyPair kp = kgt.getKeyPair(); - if(kp == null) { + if (kp == null) { Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + ". " + "KeyAgreement tests will be skipped.", generate); doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Cofactor test of " + curve.getId() + ".", generateFail)); continue; @@ -101,7 +101,7 @@ public class StandaloneCofactorSuite extends StandaloneTestSuite { allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform " + kaIdent.getName() + " with public points on non-generator subgroup.", specificKaTests.toArray(new Test[0]))); } } - if(allKaTests.isEmpty()) { + if (allKaTests.isEmpty()) { allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified key agreement types is supported by the library.")); } Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Do tests.", allKaTests.toArray(new Test[0])); diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCompositeSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCompositeSuite.java index c59d864..839bb40 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCompositeSuite.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCompositeSuite.java @@ -85,10 +85,10 @@ public class StandaloneCompositeSuite extends StandaloneTestSuite { //Generate KeyPair KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec); - Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY); + Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY); runTest(generate); KeyPair kp = kgt.getKeyPair(); - if(kp == null) { + if (kp == null) { Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + ". " + "KeyAgreement tests will be skipped.", generate); doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ".", generateFail)); continue; @@ -104,14 +104,14 @@ public class StandaloneCompositeSuite extends StandaloneTestSuite { for (EC_Key.Public pub : curveKeys.getValue()) { ECPublicKey ecpub = ECUtil.toPublicKey(pub); KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider()); - KeyAgreementTestable testable = new KeyAgreementTestable(ka, ecpriv ,ecpub); + KeyAgreementTestable testable = new KeyAgreementTestable(ka, ecpriv, ecpub); Test keyAgreement = KeyAgreementTest.expectError(testable, Result.ExpectedValue.FAILURE); specificKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ", with generated private key, " + pub.getDesc(), keyAgreement)); } allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform " + kaIdent.getName() + " with various public points.", specificKaTests.toArray(new Test[0]))); } } - if(allKaTests.isEmpty()) { + if (allKaTests.isEmpty()) { allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified key agreement types is supported by the library.")); } Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Do tests.", allKaTests.toArray(new Test[0])); @@ -153,7 +153,7 @@ public class StandaloneCompositeSuite extends StandaloneTestSuite { } private void testGroup(List<EC_Curve> curves, KeyPairGenerator kpg, String testName, Result.ExpectedValue dhValue) throws Exception { - for (EC_Curve curve : curves) { + for (EC_Curve curve : curves) { String description; if (testName == null) { description = curve.getDesc() + " test of " + curve.getId() + "."; @@ -162,19 +162,19 @@ public class StandaloneCompositeSuite extends StandaloneTestSuite { } //generate KeyPair - KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, curve.toSpec()); - Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY); - runTest(generate); - KeyPair kp = kgt.getKeyPair(); - if(kp == null) { - Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + - ". " + " Other tests will be skipped.", generate); - doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, description, generateFail)); - continue; - } - Test generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generate); - ECPrivateKey ecpriv = (ECPrivateKey) kp.getPrivate(); - ECPublicKey ecpub = (ECPublicKey) kp.getPublic(); + KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, curve.toSpec()); + Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY); + runTest(generate); + KeyPair kp = kgt.getKeyPair(); + if (kp == null) { + Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + + ". " + " Other tests will be skipped.", generate); + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, description, generateFail)); + continue; + } + Test generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generate); + ECPrivateKey ecpriv = (ECPrivateKey) kp.getPrivate(); + ECPublicKey ecpub = (ECPublicKey) kp.getPublic(); //perform KeyAgreement tests List<Test> kaTests = new LinkedList<>(); @@ -185,7 +185,7 @@ public class StandaloneCompositeSuite extends StandaloneTestSuite { kaTests.add(KeyAgreementTest.expectError(testable, dhValue)); } } - if(kaTests.isEmpty()) { + if (kaTests.isEmpty()) { kaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified KeyAgreement types is supported by the library.")); } @@ -198,7 +198,7 @@ public class StandaloneCompositeSuite extends StandaloneTestSuite { sigTests.add(SignatureTest.expectError(testable, dhValue)); } } - if(sigTests.isEmpty()) { + if (sigTests.isEmpty()) { sigTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified Signature types is supported by the library.")); } diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneDegenerateSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneDegenerateSuite.java index 9ab8a39..d822a83 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneDegenerateSuite.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneDegenerateSuite.java @@ -22,6 +22,7 @@ import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; import java.util.*; @@ -77,22 +78,34 @@ public class StandaloneDegenerateSuite extends StandaloneTestSuite { KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec); Test generateSuccess; - Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY); + Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY); runTest(generate); KeyPair kp = kgt.getKeyPair(); - if(kp != null) { + if (kp != null) { generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generate); - } else { //If KeyPair generation fails, try generating it on a default curve instead. Use this key only if it has the same domain parameters as our public key. - KeyGeneratorTestable kgtOnDefaultCurve = new KeyGeneratorTestable(kpg, curve.getBits()); - Test generateOnDefaultCurve = KeyGeneratorTest.expectError(kgtOnDefaultCurve, Result.ExpectedValue.ANY); - runTest(generateOnDefaultCurve); - kp = kgtOnDefaultCurve.getKeyPair(); - if(kp != null && ECUtil.equalKeyPairParameters((ECPrivateKey) kp.getPrivate(), ECUtil.toPublicKey(keys.get(0)))) { - generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generateOnDefaultCurve); + } else { + // If KeyPair generation fails, try generating it on named curve instead. + ECGenParameterSpec namedSpec = new ECGenParameterSpec(curve.getId()); + KeyGeneratorTestable kgtOnNamedCurve = new KeyGeneratorTestable(kpg, namedSpec); + Test generateOnNamedCurve = KeyGeneratorTest.expectError(kgtOnNamedCurve, Result.ExpectedValue.ANY); + runTest(generateOnNamedCurve); + kp = kgtOnNamedCurve.getKeyPair(); + if (kp != null) { + generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair (named curve).", generateOnNamedCurve); } else { - Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + ". " + "KeyAgreement tests will be skipped.", generate); - doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId() + ".", generateFail)); - continue; + // If even the named curve generation fails, try generating with the default curve instead. Use this key only if it has the same domain parameters as our public key. + KeyGeneratorTestable kgtOnDefaultCurve = new KeyGeneratorTestable(kpg, curve.getBits()); + Test generateOnDefaultCurve = KeyGeneratorTest.expectError(kgtOnDefaultCurve, Result.ExpectedValue.ANY); + runTest(generateOnDefaultCurve); + kp = kgtOnDefaultCurve.getKeyPair(); + if (kp != null && ECUtil.equalKeyPairParameters((ECPrivateKey) kp.getPrivate(), ECUtil.toPublicKey(keys.get(0)))) { + generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair (default curve).", generateOnDefaultCurve); + } else { + Test generateNotEqual = CompoundTest.function(tests -> new Result(Result.Value.FAILURE, "Default parameters do not match the curve " + curve.getId()), "Default parameters do not match the curve " + curve.getId(), generateOnDefaultCurve); + Test generateFail = CompoundTest.any(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + ". " + "KeyAgreement tests will be skipped.", generate, generateOnNamedCurve, generateNotEqual); + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId() + ".", generateFail)); + continue; + } } } ECPrivateKey ecpriv = (ECPrivateKey) kp.getPrivate(); @@ -111,7 +124,7 @@ public class StandaloneDegenerateSuite extends StandaloneTestSuite { allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform " + kaIdent.getName() + " with degenerate public points..", specificKaTests.toArray(new Test[0]))); } } - if(allKaTests.isEmpty()) { + if (allKaTests.isEmpty()) { allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified key agreement types is supported by the library.")); } Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Do tests.", allKaTests.toArray(new Test[0])); diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneEdgeCasesSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneEdgeCasesSuite.java index 1900bea..7c46f02 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneEdgeCasesSuite.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneEdgeCasesSuite.java @@ -264,10 +264,10 @@ public class StandaloneEdgeCasesSuite extends StandaloneTestSuite { //generate KeyPair KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec); - Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY); + Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY); runTest(generate); KeyPair kp = kgt.getKeyPair(); - if(kp == null) { + if (kp == null) { Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + secp160r1.getBits() + "b secp160r1." + " Other tests will be skipped.", generate); doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Test private key values near zero, near p and near/larger than the order on" + secp160r1.getId() + ".", generateFail)); diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneInvalidSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneInvalidSuite.java index ace8945..48dfc37 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneInvalidSuite.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneInvalidSuite.java @@ -22,6 +22,7 @@ import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; import java.util.*; @@ -76,22 +77,34 @@ public class StandaloneInvalidSuite extends StandaloneTestSuite { KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec); Test generateSuccess; - Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY); + Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY); runTest(generate); KeyPair kp = kgt.getKeyPair(); - if(kp != null) { + if (kp != null) { generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generate); - } else { //If KeyPair generation fails, try generating it on a default curve instead. Use this key only if it has the same domain parameters as our public key. - KeyGeneratorTestable kgtOnDefaultCurve = new KeyGeneratorTestable(kpg, curve.getBits()); - Test generateOnDefaultCurve = KeyGeneratorTest.expectError(kgtOnDefaultCurve, Result.ExpectedValue.ANY); - runTest(generateOnDefaultCurve); - kp = kgtOnDefaultCurve.getKeyPair(); - if(kp != null && ECUtil.equalKeyPairParameters((ECPrivateKey) kp.getPrivate(), ECUtil.toPublicKey(keys.get(0)))) { - generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generateOnDefaultCurve); + } else { + // If KeyPair generation fails, try generating it on named curve instead. + ECGenParameterSpec namedSpec = new ECGenParameterSpec(curve.getId()); + KeyGeneratorTestable kgtOnNamedCurve = new KeyGeneratorTestable(kpg, namedSpec); + Test generateOnNamedCurve = KeyGeneratorTest.expectError(kgtOnNamedCurve, Result.ExpectedValue.ANY); + runTest(generateOnNamedCurve); + kp = kgtOnNamedCurve.getKeyPair(); + if (kp != null) { + generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair (named curve).", generateOnNamedCurve); } else { - Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + ". " + "KeyAgreement tests will be skipped.", generate); - doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId() + ".", generateFail)); - continue; + // If even the named curve generation fails, try generating with the default curve instead. Use this key only if it has the same domain parameters as our public key. + KeyGeneratorTestable kgtOnDefaultCurve = new KeyGeneratorTestable(kpg, curve.getBits()); + Test generateOnDefaultCurve = KeyGeneratorTest.expectError(kgtOnDefaultCurve, Result.ExpectedValue.ANY); + runTest(generateOnDefaultCurve); + kp = kgtOnDefaultCurve.getKeyPair(); + if (kp != null && ECUtil.equalKeyPairParameters((ECPrivateKey) kp.getPrivate(), ECUtil.toPublicKey(keys.get(0)))) { + generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair (default curve).", generateOnDefaultCurve); + } else { + Test generateNotEqual = CompoundTest.function(tests -> new Result(Result.Value.FAILURE, "Default parameters do not match the curve " + curve.getId()), "Default parameters do not match the curve " + curve.getId(), generateOnDefaultCurve); + Test generateFail = CompoundTest.any(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + ". " + "KeyAgreement tests will be skipped.", generate, generateOnNamedCurve, generateNotEqual); + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId() + ".", generateFail)); + continue; + } } } ECPrivateKey ecpriv = (ECPrivateKey) kp.getPrivate(); @@ -110,7 +123,7 @@ public class StandaloneInvalidSuite extends StandaloneTestSuite { allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform " + kaIdent.getName() + " with invalid public points.", specificKaTests.toArray(new Test[0]))); } } - if(allKaTests.isEmpty()) { + if (allKaTests.isEmpty()) { allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified key agreement types is supported by the library.")); } Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Do tests.", allKaTests.toArray(new Test[0])); diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandalonePerformanceSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandalonePerformanceSuite.java index e3b6d2e..a1b4d75 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandalonePerformanceSuite.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandalonePerformanceSuite.java @@ -73,7 +73,7 @@ public class StandalonePerformanceSuite extends StandaloneTestSuite { KeyGeneratorTestable kgtOther = null; ECParameterSpec spec = null; List<Test> kpgTests = new LinkedList<>(); - for(KeyPairGeneratorIdent kpgIdent : kpgIdents) { + for (KeyPairGeneratorIdent kpgIdent : kpgIdents) { KeyPairGenerator kpg = kpgIdent.getInstance(cfg.selected.getProvider()); if (cli.hasOption("test.bits")) { int bits = Integer.parseInt(cli.getOptionValue("test.bits")); @@ -111,7 +111,7 @@ public class StandalonePerformanceSuite extends StandaloneTestSuite { kaTests.add(PerformanceTest.repeat(testable, cfg.selected, kaIdent.getName(), count)); } } - if(kaTests.isEmpty()) { + if (kaTests.isEmpty()) { kaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified KeyAgreement types is supported by the library.")); } doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyAgreement performance tests", kaTests.toArray(new Test[0]))); @@ -121,17 +121,17 @@ public class StandalonePerformanceSuite extends StandaloneTestSuite { for (SignatureIdent sigIdent : cfg.selected.getSigs()) { if (sigAlgo == null || sigIdent.containsAny(sigTypes)) { Signature sig = sigIdent.getInstance(cfg.selected.getProvider()); - sigTests.add(PerformanceTest.repeat(new SignatureTestable(sig, kgtOne, null), cfg.selected, sigIdent.getName(),count)); - if(kgtOne.getKeyPair() != null) { + sigTests.add(PerformanceTest.repeat(new SignatureTestable(sig, kgtOne, null), cfg.selected, sigIdent.getName(), count)); + if (kgtOne.getKeyPair() != null) { ECPrivateKey signKey = (ECPrivateKey) kgtOne.getKeyPair().getPrivate(); sigTestsNoVerification.add(PerformanceTest.repeat(new SignatureTestable(sig, signKey, null, null), cfg.selected, sigIdent.getName(), count)); } } } - if(sigTestsNoVerification.isEmpty() & !sigTests.isEmpty()) { + if (sigTestsNoVerification.isEmpty() & !sigTests.isEmpty()) { sigTestsNoVerification.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Signature tests with no verification require a successfully generated private key.")); } - if(sigTests.isEmpty()) { + if (sigTests.isEmpty()) { sigTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified Signature types is supported by the library.")); sigTestsNoVerification.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified Signature types is supported by the library.")); } diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneSignatureSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneSignatureSuite.java index 94e810e..8e5e452 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneSignatureSuite.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneSignatureSuite.java @@ -73,6 +73,10 @@ public class StandaloneSignatureSuite extends StandaloneTestSuite { } private void ecdsaTest(EC_SigResult sig, SignatureIdent sigIdent, Result.ExpectedValue expected, byte[] defaultData) throws NoSuchAlgorithmException { + if (!sig.getSig().equals(sigIdent.getHashAlgo()) && !sig.getSig().equals("*")) { + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "ECDSA test of " + sig.getId() + " not applicable.")); + return; + } ECPublicKey ecpub = ECUtil.toPublicKey(EC_Store.getInstance().getObject(EC_Key.Public.class, sig.getVerifyKey())); byte[] data = sig.getSigData(); diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTestVectorSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTestVectorSuite.java index 1e1889c..111d354 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTestVectorSuite.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTestVectorSuite.java @@ -31,7 +31,7 @@ public class StandaloneTestVectorSuite extends StandaloneTestSuite { protected void runTests() throws Exception { Map<String, EC_KAResult> results = EC_Store.getInstance().getObjects(EC_KAResult.class, "test"); for (EC_KAResult result : results.values()) { - if(!"DH_PLAIN".equals(result.getKA())) { + if (!"DH_PLAIN".equals(result.getKA())) { continue; } diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTwistSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTwistSuite.java index f182952..37adbb2 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTwistSuite.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTwistSuite.java @@ -22,6 +22,7 @@ import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; import java.util.*; @@ -76,22 +77,34 @@ public class StandaloneTwistSuite extends StandaloneTestSuite { KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec); Test generateSuccess; - Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY); + Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY); runTest(generate); KeyPair kp = kgt.getKeyPair(); - if(kp != null) { + if (kp != null) { generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generate); - } else { //If KeyPair generation fails, try generating it on a default curve instead. Use this key only if it has the same domain parameters as our public key. - KeyGeneratorTestable kgtOnDefaultCurve = new KeyGeneratorTestable(kpg, curve.getBits()); - Test generateOnDefaultCurve = KeyGeneratorTest.expectError(kgtOnDefaultCurve, Result.ExpectedValue.ANY); - runTest(generateOnDefaultCurve); - kp = kgtOnDefaultCurve.getKeyPair(); - if(kp != null && ECUtil.equalKeyPairParameters((ECPrivateKey) kp.getPrivate(), ECUtil.toPublicKey(keys.get(0)))) { - generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generateOnDefaultCurve); + } else { + // If KeyPair generation fails, try generating it on named curve instead. + ECGenParameterSpec namedSpec = new ECGenParameterSpec(curve.getId()); + KeyGeneratorTestable kgtOnNamedCurve = new KeyGeneratorTestable(kpg, namedSpec); + Test generateOnNamedCurve = KeyGeneratorTest.expectError(kgtOnNamedCurve, Result.ExpectedValue.ANY); + runTest(generateOnNamedCurve); + kp = kgtOnNamedCurve.getKeyPair(); + if (kp != null) { + generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair (named curve).", generateOnNamedCurve); } else { - Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + ". " + "KeyAgreement tests will be skipped.", generate); - doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId() + ".", generateFail)); - continue; + // If even the named curve generation fails, try generating with the default curve instead. Use this key only if it has the same domain parameters as our public key. + KeyGeneratorTestable kgtOnDefaultCurve = new KeyGeneratorTestable(kpg, curve.getBits()); + Test generateOnDefaultCurve = KeyGeneratorTest.expectError(kgtOnDefaultCurve, Result.ExpectedValue.ANY); + runTest(generateOnDefaultCurve); + kp = kgtOnDefaultCurve.getKeyPair(); + if (kp != null && ECUtil.equalKeyPairParameters((ECPrivateKey) kp.getPrivate(), ECUtil.toPublicKey(keys.get(0)))) { + generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair (default curve).", generateOnDefaultCurve); + } else { + Test generateNotEqual = CompoundTest.function(tests -> new Result(Result.Value.FAILURE, "Default parameters do not match the curve " + curve.getId()), "Default parameters do not match the curve " + curve.getId(), generateOnDefaultCurve); + Test generateFail = CompoundTest.any(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + ". " + "KeyAgreement tests will be skipped.", generate, generateOnNamedCurve, generateNotEqual); + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId() + ".", generateFail)); + continue; + } } } ECPrivateKey ecpriv = (ECPrivateKey) kp.getPrivate(); @@ -110,7 +123,7 @@ public class StandaloneTwistSuite extends StandaloneTestSuite { allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform " + kaIdent.getName() + " with public points on twist.", specificKaTests.toArray(new Test[0]))); } } - if(allKaTests.isEmpty()) { + if (allKaTests.isEmpty()) { allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified key agreement types is supported by the library.")); } Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Do tests.", allKaTests.toArray(new Test[0])); diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneWrongSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneWrongSuite.java index a457a33..1aae9d5 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneWrongSuite.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneWrongSuite.java @@ -103,7 +103,7 @@ public class StandaloneWrongSuite extends StandaloneTestSuite { /* Just do the default run on the wrong curves. * These should generally fail, the curves aren't curves. */ - if(!skip) { + if (!skip) { Map<String, EC_Curve> wrongCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "wrong"); for (Map.Entry<String, EC_Curve> e : wrongCurves.entrySet()) { @@ -151,11 +151,11 @@ public class StandaloneWrongSuite extends StandaloneTestSuite { short bits = curve.getBits(); final byte[] originalp = curve.getParam(EC_Consts.PARAMETER_FP)[0]; - curve.setParam(EC_Consts.PARAMETER_FP, new byte[][]{ ByteUtil.hexToBytes("0")}); - Test prime0 = ecdhTest(toCustomSpec(curve),"ECDH with p = 0."); + curve.setParam(EC_Consts.PARAMETER_FP, new byte[][]{ByteUtil.hexToBytes("0")}); + Test prime0 = ecdhTest(toCustomSpec(curve), "ECDH with p = 0."); - curve.setParam(EC_Consts.PARAMETER_FP, new byte[][]{ ByteUtil.hexToBytes("1")}); - Test prime1 = ecdhTest(toCustomSpec(curve),"ECDH with p = 1."); + curve.setParam(EC_Consts.PARAMETER_FP, new byte[][]{ByteUtil.hexToBytes("1")}); + Test prime1 = ecdhTest(toCustomSpec(curve), "ECDH with p = 1."); short keyHalf = (short) (bits / 2); BigInteger prime = new BigInteger(keyHalf, 50, r); @@ -173,23 +173,23 @@ public class StandaloneWrongSuite extends StandaloneTestSuite { Test composite = ecdhTest(toCustomSpec(curve), "ECDH with p = q * s."); - Test wrongPrime = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with corrupted prime parameter.", prime0 , prime1, primePower, composite ); + Test wrongPrime = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with corrupted prime parameter.", prime0, prime1, primePower, composite); - curve.setParam(EC_Consts.PARAMETER_FP, new byte[][] {originalp}); + curve.setParam(EC_Consts.PARAMETER_FP, new byte[][]{originalp}); final byte[][] originalG = curve.getParam(EC_Consts.PARAMETER_G); byte[] Gx = new BigInteger(curve.getBits(), r).toByteArray(); byte[] Gy = new BigInteger(curve.getBits(), r).toByteArray(); - curve.setParam(EC_Consts.PARAMETER_G, new byte[][] {Gx, Gy}); + curve.setParam(EC_Consts.PARAMETER_G, new byte[][]{Gx, Gy}); Test fullRandomG = ecdhTest(toCustomSpec(curve), "ECDH with G = random data."); final BigInteger originalBigp = new BigInteger(1, originalp); byte[] smallerGx = new BigInteger(curve.getBits(), r).mod(originalBigp).toByteArray(); byte[] smallerGy = new BigInteger(curve.getBits(), r).mod(originalBigp).toByteArray(); - curve.setParam(EC_Consts.PARAMETER_G, new byte[][] {smallerGx, smallerGy}); + curve.setParam(EC_Consts.PARAMETER_G, new byte[][]{smallerGx, smallerGy}); Test randomG = ecdhTest(toCustomSpec(curve), "ECDH with G = random data mod p."); - curve.setParam(EC_Consts.PARAMETER_G, new byte[][] {ByteUtil.hexToBytes("0"), ByteUtil.hexToBytes("0")}); + curve.setParam(EC_Consts.PARAMETER_G, new byte[][]{ByteUtil.hexToBytes("0"), ByteUtil.hexToBytes("0")}); Test zeroG = ecdhTest(toCustomSpec(curve), "ECDH with G = infinity."); Test wrongG = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with corrupted G parameter.", fullRandomG, randomG, zeroG); @@ -199,7 +199,7 @@ public class StandaloneWrongSuite extends StandaloneTestSuite { final BigInteger originalBigR = new BigInteger(1, originalR); List<Test> allRTests = new LinkedList<>(); - if(!skip) { + if (!skip) { byte[] RZero = new byte[]{(byte) 0}; curve.setParam(EC_Consts.PARAMETER_R, new byte[][]{RZero}); allRTests.add(ecdhTest(toCustomSpec(curve), "ECDH with R = 0.")); @@ -215,7 +215,7 @@ public class StandaloneWrongSuite extends StandaloneTestSuite { prevPrimeR = BigInteger.probablePrime(originalBigR.bitLength() - 1, r); } while (prevPrimeR.compareTo(originalBigR) >= 0); byte[] prevRBytes = ECUtil.toByteArray(prevPrimeR, bits); - curve.setParam(EC_Consts.PARAMETER_R, new byte[][] {prevRBytes}); + curve.setParam(EC_Consts.PARAMETER_R, new byte[][]{prevRBytes}); allRTests.add(ecdhTest(toCustomSpec(curve), "ECDH with R = some prime (but [r]G != infinity) smaller than original R.")); BigInteger nextPrimeR = originalBigR.nextProbablePrime(); @@ -225,15 +225,15 @@ public class StandaloneWrongSuite extends StandaloneTestSuite { byte[] nonprimeRBytes = nextRBytes.clone(); nonprimeRBytes[nonprimeRBytes.length - 1] ^= 1; - curve.setParam(EC_Consts.PARAMETER_R, new byte[][] {nonprimeRBytes} ); + curve.setParam(EC_Consts.PARAMETER_R, new byte[][]{nonprimeRBytes}); allRTests.add(ecdhTest(toCustomSpec(curve), "ECDH with R = some composite (but [r]G != infinity).")); Test wrongR = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with corrupted R parameter.", allRTests.toArray(new Test[0])); - curve.setParam(EC_Consts.PARAMETER_R, new byte[][] {originalR}); + curve.setParam(EC_Consts.PARAMETER_R, new byte[][]{originalR}); byte[] kRaw = new byte[]{(byte) 0xff}; - curve.setParam(EC_Consts.PARAMETER_K, new byte[][] {kRaw}); + curve.setParam(EC_Consts.PARAMETER_K, new byte[][]{kRaw}); Test bigK = ecdhTest(toCustomSpec(curve), "ECDH with big K."); byte[] kZero = new byte[]{(byte) 0}; @@ -241,7 +241,7 @@ public class StandaloneWrongSuite extends StandaloneTestSuite { Test zeroK = ecdhTest(toCustomSpec(curve), "ECDH with K = 0."); Test wrongK = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with corrupted K parameter.", bigK, zeroK); - doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests of " + bits + "b " + "FP", wrongPrime, wrongG, wrongR , wrongK)); + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests of " + bits + "b " + "FP", wrongPrime, wrongG, wrongR, wrongK)); } @@ -284,10 +284,10 @@ public class StandaloneWrongSuite extends StandaloneTestSuite { private Test ecdhTest(ECParameterSpec spec, String desc) throws NoSuchAlgorithmException { //generate KeyPair KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec); - Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.FAILURE); + Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.FAILURE); runTest(generate); KeyPair kp = kgt.getKeyPair(); - if(kp == null) { + if (kp == null) { return CompoundTest.all(Result.ExpectedValue.SUCCESS, desc, generate); } ECPublicKey pub = (ECPublicKey) kp.getPublic(); diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/Makefile b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/Makefile index 1fa16c0..6282574 100644 --- a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/Makefile +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/Makefile @@ -4,7 +4,7 @@ CC?=gcc CXX?=g++ -LFLAGS+=-fPIC -shared +LFLAGS+=-fPIC -shared -L "$(JNI_LIBDIR)" -L "$(JNI_LIBDIR)/server" #-ljsig -ljvm CFLAGS+=-fPIC -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. -Wno-deprecated-declarations CXXFLAGS+=-fPIC -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. -Wno-deprecated-declarations @@ -36,12 +36,17 @@ endif ifneq ($(JAVA_HOME),) JNI_INCLUDEDIR ?= $(JAVA_HOME)/include + JNI_LIBDIR ?= $(JAVA_HOME)/lib endif ifeq ($(JNI_INCLUDEDIR),) $(error "Could not determine JNI include dir. Try specifying either JAVA_HOME or JNI_INCLUDEDIR.") endif +ifeq ($(JNI_LIBDIR),) + $(error "Could not determine JNI lib dir. Try specifying either JAVA_HOME or JNI_LIBDIR.") +endif + TARGETTRIPLET := $(shell $(CC) -dumpmachine) ifeq ($(JNI_PLATFORM),) @@ -68,6 +73,12 @@ c_utils.o: c_utils.c lib_timing.so: c_timing.c $(CC) -o $@ -shared $(CFLAGS) -Wl,-soname,lib_timing.so $< +lib_csignals.so: c_signals.c + $(CC) -o $@ -shared $(CFLAGS) -pthread -lpthread -Wl,-soname,lib_csignals.so $< + +lib_cppsignals.so: cpp_signals.cpp + $(CC) -o $@ -shared $(CFLAGS) -pthread -lpthread -Wl,-soname,lib_cppsignals.so $< + cpp_utils.o: cpp_utils.cpp $(CXX) $(CXXFLAGS) -c $< @@ -75,8 +86,8 @@ cpp_utils.o: cpp_utils.cpp # OpenSSL shim openssl: openssl_provider.so -openssl_provider.so: openssl.o c_utils.o | lib_timing.so - $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell pkg-config --libs openssl) -l:lib_timing.so +openssl_provider.so: openssl.o c_utils.o | lib_timing.so lib_csignals.so + $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell pkg-config --libs openssl) -l:lib_timing.so -l:lib_csignals.so openssl.o: openssl.c $(CC) $(shell pkg-config --cflags openssl) $(CFLAGS) -c $< @@ -88,8 +99,8 @@ boringssl: boringssl_provider.so lib_boringssl.so: cp $(PROJECT_ROOT_PATH)/ext/boringssl/build/crypto/libcrypto.so lib_boringssl.so -boringssl_provider.so: boringssl.o c_utils.o | lib_timing.so lib_boringssl.so - $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. lib_boringssl.so -l:lib_timing.so +boringssl_provider.so: boringssl.o c_utils.o | lib_timing.so lib_csignals.so lib_boringssl.so + $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. lib_boringssl.so -l:lib_timing.so -l:lib_csignals.so boringssl.o: boringssl.c $(CC) -I$(PROJECT_ROOT_PATH)/ext/boringssl/include/ $(CFLAGS) -c $< @@ -98,8 +109,8 @@ boringssl.o: boringssl.c # libgcrypt shim gcrypt: gcrypt_provider.so -gcrypt_provider.so: gcrypt.o c_utils.o | lib_timing.so - $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell libgcrypt-config --libs) -l:lib_timing.so +gcrypt_provider.so: gcrypt.o c_utils.o | lib_timing.so lib_csignals.so + $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. -pthread -lpthread $(shell libgcrypt-config --libs) -l:lib_timing.so -l:lib_csignals.so gcrypt.o: gcrypt.c $(CC) $(shell libgcrypt-config --cflags) $(CFLAGS) -c $< @@ -108,8 +119,8 @@ gcrypt.o: gcrypt.c # Libtomcrypt shim tomcrypt: tomcrypt_provider.so -tomcrypt_provider.so: tomcrypt.o c_utils.o | lib_timing.so - $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. -ltommath $(shell pkg-config --libs libtomcrypt) -l:lib_timing.so +tomcrypt_provider.so: tomcrypt.o c_utils.o | lib_timing.so lib_csignals.so + $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. -ltommath $(shell pkg-config --libs libtomcrypt) -l:lib_timing.so -l:lib_csignals.so tomcrypt.o: tomcrypt.c $(CC) -DLTM_DESC $(shell pkg-config --cflags libtomcrypt) $(CFLAGS) -c $< @@ -118,8 +129,8 @@ tomcrypt.o: tomcrypt.c # Botan-2 shim botan: botan_provider.so -botan_provider.so: botan.o cpp_utils.o | lib_timing.so - $(CXX) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell pkg-config --libs botan-2) -l:lib_timing.so +botan_provider.so: botan.o cpp_utils.o | lib_timing.so lib_cppsignals.so + $(CXX) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell pkg-config --libs botan-2) -l:lib_timing.so -l:lib_cppsignals.so botan.o: botan.cpp $(CXX) $(shell pkg-config --cflags botan-2) $(CXXFLAGS) -c $< @@ -132,8 +143,8 @@ ifeq ($(shell pkg-config --exists $(CRYPTOPP_NAME); echo $$?),1) endif cryptopp: cryptopp_provider.so -cryptopp_provider.so: cryptopp.o cpp_utils.o | lib_timing.so - $(CXX) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell pkg-config --libs $(CRYPTOPP_NAME)) -l:lib_timing.so +cryptopp_provider.so: cryptopp.o cpp_utils.o | lib_timing.so lib_cppsignals.so + $(CXX) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell pkg-config --libs $(CRYPTOPP_NAME)) -l:lib_timing.so -l:lib_cppsignals.so cryptopp.o: cryptopp.cpp $(CXX) $(shell pkg-config --cflags $(CRYPTOPP_NAME)) $(CXXFLAGS) -c $< @@ -145,8 +156,8 @@ mbedtls: mbedtls_provider.so lib_mbedtls.so: cp $(PROJECT_ROOT_PATH)/ext/mbedtls/build/library/libmbedcrypto.so lib_mbedtls.so -mbedtls_provider.so: mbedtls.o c_utils.o | lib_timing.so lib_mbedtls.so - $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. lib_mbedtls.so -l:lib_timing.so +mbedtls_provider.so: mbedtls.o c_utils.o | lib_timing.so lib_csignals.so lib_mbedtls.so + $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. lib_mbedtls.so -l:lib_timing.so -l:lib_csignals.so mbedtls.o: mbedtls.c $(CC) -I$(PROJECT_ROOT_PATH)/ext/mbedtls/build/include/ $(CFLAGS) -c $< @@ -158,8 +169,8 @@ ippcp: ippcp_provider.so lib_ippcp.so: cp $(PROJECT_ROOT_PATH)/ext/ipp-crypto/build/.build/RELEASE/lib/libippcp.so lib_ippcp.so -ippcp_provider.so: ippcp.o c_utils.o | lib_timing.so lib_ippcp.so - $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. lib_ippcp.so -l:lib_timing.so +ippcp_provider.so: ippcp.o c_utils.o | lib_timing.so lib_csignals.so lib_ippcp.so + $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. lib_ippcp.so -l:lib_timing.so -l:lib_csignals.so ippcp.o: ippcp.c $(CC) -I$(PROJECT_ROOT_PATH)/ext/ipp-crypto/build/.build/RELEASE/include/ $(CFLAGS) -c $< @@ -168,8 +179,8 @@ ippcp.o: ippcp.c # Nettle shim nettle: nettle_provider.so -nettle_provider.so: nettle.o c_utils.o | lib_timing.so - $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell pkg-config --libs nettle) -l:lib_timing.so $(shell pkg-config --libs hogweed) -lgmp +nettle_provider.so: nettle.o c_utils.o | lib_timing.so lib_csignals.so + $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell pkg-config --libs nettle) -l:lib_timing.so -l:lib_csignals.so $(shell pkg-config --libs hogweed) -lgmp nettle.o: nettle.c $(CC) $(shell pkg-config --cflags nettle) $(shell pkg-config --libs hogweed) -lgmp $(CFLAGS) -c $< @@ -181,8 +192,8 @@ libressl: libressl_provider.so lib_libressl.so: cp $(PROJECT_ROOT_PATH)/ext/libressl/build/crypto/libcrypto.so lib_libressl.so -libressl_provider.so: libressl.o c_utils.o | lib_timing.so lib_libressl.so - $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. lib_libressl.so -l:lib_timing.so +libressl_provider.so: libressl.o c_utils.o | lib_timing.so lib_csignals.so lib_libressl.so + $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. lib_libressl.so -l:lib_timing.so -l:lib_csignals.so libressl.o: libressl.c $(CC) -I$(PROJECT_ROOT_PATH)/ext/libressl/build/include/ $(CFLAGS) -c $< diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/boringssl.c b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/boringssl.c index 4cc95a5..919cc79 100644 --- a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/boringssl.c +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/boringssl.c @@ -1,5 +1,6 @@ #include "c_utils.h" #include "c_timing.h" +#include "c_signals.h" #include "native.h" #include <strings.h> @@ -288,9 +289,12 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) { EC_KEY *key = EC_KEY_new(); EC_KEY_set_group(key, curve); - native_timing_start(); - int err = EC_KEY_generate_key(key); - native_timing_stop(); + int err = 0; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = EC_KEY_generate_key(key); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (!err) { throw_new(env, "java/security/GeneralSecurityException", "Error generating key, EC_KEY_generate_key."); @@ -393,11 +397,20 @@ EC_KEY *barray_to_pubkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray pub) { jsize pub_len = (*env)->GetArrayLength(env, pub); jbyte *pub_data = (*env)->GetByteArrayElements(env, pub, NULL); EC_POINT *pub_point = EC_POINT_new(curve); - EC_POINT_oct2point(curve, pub_point, (unsigned char *) pub_data, pub_len, NULL); - (*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT); - EC_KEY_set_public_key(result, pub_point); - EC_POINT_free(pub_point); - return result; + int retval = EC_POINT_oct2point(curve, pub_point, (unsigned char *) pub_data, pub_len, NULL); + (*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT); + if (!retval) { + EC_POINT_free(pub_point); + throw_new(env, "java/security/GeneralSecurityException", "Error loading key, EC_POINT_oct2point."); + return NULL; + } + retval = EC_KEY_set_public_key(result, pub_point); + EC_POINT_free(pub_point); + if (!retval) { + throw_new(env, "java/security/GeneralSecurityException", "Error loading key, EC_KEY_set_public_key."); + return NULL; + } + return result; } EC_KEY *barray_to_privkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray priv) { @@ -407,32 +420,46 @@ EC_KEY *barray_to_privkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray priv) jbyte *priv_data = (*env)->GetByteArrayElements(env, priv, NULL); BIGNUM *s = BN_bin2bn((unsigned char *) priv_data, priv_len, NULL); (*env)->ReleaseByteArrayElements(env, priv, priv_data, JNI_ABORT); - EC_KEY_set_private_key(result, s); + int retval = EC_KEY_set_private_key(result, s); BN_free(s); + if (!retval) { + throw_new(env, "java/security/GeneralSecurityException", "Error loading key, EC_KEY_set_private_key."); + return NULL; + } return result; } JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Boringssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) { + jbyteArray result = NULL; EC_GROUP *curve = create_curve(env, params); if (!curve) { throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found."); - return NULL; + goto free_curve; } EC_KEY *pub = barray_to_pubkey(env, curve, pubkey); + if (!pub) { + goto free_pub; + } EC_KEY *priv = barray_to_privkey(env, curve, privkey); + if (!priv) { + goto free_priv; + } int field_size = EC_GROUP_get_degree(curve); size_t secret_len = (field_size + 7)/8; //TODO: Do more KeyAgreements here, but will have to do the hash-fun manually, // probably using the ECDH_KDF_X9_62 by wrapping it and dynamically choosing the EVP_MD. from the type string. - jbyteArray result = (*env)->NewByteArray(env, secret_len); + result = (*env)->NewByteArray(env, secret_len); jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL); - native_timing_start(); - int err = ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL); - native_timing_stop(); + int err = 0; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (err <= 0) { throw_new(env, "java/security/GeneralSecurityException", "Error computing ECDH, ECDH_compute_key."); @@ -442,8 +469,11 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey } (*env)->ReleaseByteArrayElements(env, result, result_data, 0); - EC_KEY_free(pub); +free_priv: EC_KEY_free(priv); +free_pub: + EC_KEY_free(pub); +free_curve: EC_GROUP_free(curve); return result; } @@ -454,38 +484,46 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgr } JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Boringssl_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) { + jbyteArray result = NULL; EC_GROUP *curve = create_curve(env, params); if (!curve) { throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found."); - return NULL; + goto free_curve; } EC_KEY *priv = barray_to_privkey(env, curve, privkey); + if (!priv) { + goto free_priv; + } jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); // TODO: Do more Signatures here, maybe use the EVP interface to get to the hashes easier and not hash manually? - native_timing_start(); - ECDSA_SIG *signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv); - native_timing_stop(); + ECDSA_SIG *signature = NULL; + SIG_TRY(TIMEOUT) { + native_timing_start(); + signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); if (!signature) { throw_new(env, "java/security/GeneralSecurityException", "Error signing, ECDSA_do_sign."); - EC_KEY_free(priv); EC_GROUP_free(curve); - return NULL; + goto free_priv; } jsize sig_len = i2d_ECDSA_SIG(signature, NULL); - jbyteArray result = (*env)->NewByteArray(env, sig_len); + result = (*env)->NewByteArray(env, sig_len); jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL); jbyte *result_data_ptr = result_data; i2d_ECDSA_SIG(signature, (unsigned char **)&result_data_ptr); (*env)->ReleaseByteArrayElements(env, result, result_data, 0); ECDSA_SIG_free(signature); +free_priv: EC_KEY_free(priv); +free_curve: EC_GROUP_free(curve); return result; } @@ -498,6 +536,10 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna } EC_KEY *pub = barray_to_pubkey(env, curve, pubkey); + if (!pub) { + EC_GROUP_free(curve); + return JNI_FALSE; + } jsize sig_len = (*env)->GetArrayLength(env, signature); jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL); @@ -508,9 +550,12 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); - native_timing_start(); - int result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub); - native_timing_stop(); + int result = 0; + SIG_TRY(TIMEOUT) { + native_timing_start(); + result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (result < 0) { throw_new(env, "java/security/GeneralSecurityException", "Error verifying, ECDSA_do_verify."); diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/c_signals.c b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/c_signals.c new file mode 100644 index 0000000..b452787 --- /dev/null +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/c_signals.c @@ -0,0 +1,117 @@ +#include "c_utils.h" +#include "c_signals.h" + +#if __linux || __posix + +#include <signal.h> +#include <setjmp.h> +#include <stdbool.h> +#include <pthread.h> +#include <unistd.h> + +static siginfo_t last_siginfo; +static bool initialized = false; +static bool caught = false; +static bool timedout = false; +static sigjmp_buf buf; +static sigjmp_buf *target = NULL; + +struct timer_arg { + unsigned int timeout; + pthread_t main_thread; +}; +static struct timer_arg ta; +static pthread_t timer_thread; + +void handler(int signo, siginfo_t *info, void *context) { + //printf("Signal, %i\n", signo); + last_siginfo = *info; + caught = true; + siglongjmp(*target, 1); +} + +void alarm_handler(int signo) { + //printf("Alarm\n"); + timedout = true; + siglongjmp(*target, 1); +} + + +sigjmp_buf *get_jmpbuf_c() { + return &buf; +} + +static struct sigaction old_segv; +static struct sigaction old_abrt; +static struct sigaction old_alrm; + +void *timer(void *arg) { + sleep(ta.timeout); + pthread_kill(ta.main_thread, SIGALRM); + return NULL; +} + +void init_signals_c(sigjmp_buf *env, unsigned int timeout) { + //printf("Initializing signals!\n"); + struct sigaction action; + action.sa_sigaction = handler; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO; + + sigaction(SIGSEGV, &action, &old_segv); + sigaction(SIGABRT, &action, &old_abrt); + + struct sigaction alarm_action; + alarm_action.sa_handler = alarm_handler; + sigemptyset(&alarm_action.sa_mask); + alarm_action.sa_flags = 0; + sigaction(SIGALRM, &alarm_action, &old_alrm); + + target = env; + initialized = true; + caught = false; + timedout = false; + + ta.timeout = timeout; + ta.main_thread = pthread_self(); + + pthread_create(&timer_thread, NULL, timer, (void *)&ta); +} + + +void deinit_signals_c() { + //printf("Deinitializing signals!\n"); + pthread_cancel(timer_thread); + + sigaction(SIGSEGV, &old_segv, NULL); + sigaction(SIGABRT, &old_abrt, NULL); + sigaction(SIGALRM, &old_alrm, NULL); + + target = NULL; + initialized = false; +} + +bool get_timedout_c() { + return timedout; +} + +jobject get_siginfo_c(JNIEnv *env) { + if (!caught) { + return NULL; + } + + jclass local_siginfo_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/SigInfo"); + jmethodID siginfo_init = (*env)->GetMethodID(env, local_siginfo_class, "<init>", "(IIIIIJIJJ)V"); + return (*env)->NewObject(env, local_siginfo_class, siginfo_init, + (jint) last_siginfo.si_signo, + (jint) last_siginfo.si_code, + (jint) last_siginfo.si_errno, + (jint) last_siginfo.si_pid, + (jint) last_siginfo.si_uid, + (jlong) last_siginfo.si_addr, + (jint) last_siginfo.si_status, + (jlong) last_siginfo.si_band, + (jlong) 0); +} + +#endif
\ No newline at end of file diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/c_signals.h b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/c_signals.h new file mode 100644 index 0000000..a82b572 --- /dev/null +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/c_signals.h @@ -0,0 +1,53 @@ +#pragma once + +#include <jni.h> +#include <setjmp.h> +#include <signal.h> + +#define TIMEOUT 5 + +/** + * + */ +void init_signals_c(jmp_buf *env, unsigned int timeout); + +/** + * + */ +sigjmp_buf *get_jmpbuf_c(); + +/** + * + */ +void deinit_signals_c(); + +/** + * + */ +bool get_timedout_c(); + +/** + * + */ +jobject get_siginfo_c(JNIEnv *env); + + +#define SIG_TRY(timeout) init_signals_c(get_jmpbuf_c(), timeout); \ + if (!sigsetjmp(*get_jmpbuf_c(), 1)) +#define SIG_CATCH() deinit_signals_c(); +#define SIG_DEINIT() deinit_signals_c(); +#define SIG_HANDLE(env) do { \ + jobject siginfo = get_siginfo_c(env); \ + if (siginfo != NULL) { \ + jclass sigexception_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/SignalException"); \ + jmethodID new_sigexception = (*env)->GetMethodID(env, sigexception_class, "<init>", "(Lcz/crcs/ectester/standalone/libs/jni/SigInfo;)V"); \ + jobject sigexception = (*env)->NewObject(env, sigexception_class, new_sigexception, siginfo); \ + (*env)->Throw(env, sigexception); \ + } \ + if (get_timedout_c()) { \ + jclass timeoutexception_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/TimeoutException"); \ + (*env)->ThrowNew(env, timeoutexception_class, "Operation timed out."); \ + } \ + } while (0) +#define SIG_CATCH_HANDLE(env) SIG_CATCH(); \ + SIG_HANDLE(env) diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/cpp_signals.cpp b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/cpp_signals.cpp new file mode 100644 index 0000000..999349a --- /dev/null +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/cpp_signals.cpp @@ -0,0 +1,122 @@ +#include "cpp_utils.hpp" +#include "cpp_signals.hpp" + +#if __linux || __posix + +#include <signal.h> +#include <setjmp.h> +#include <stdbool.h> +#include <pthread.h> +#include <unistd.h> + +static siginfo_t last_siginfo; +static bool initialized = false; +static bool caught = false; +static bool timedout = false; +static sigjmp_buf buf; +static sigjmp_buf *target = NULL; + +struct timer_arg { + unsigned int timeout; + pthread_t main_thread; +}; +static struct timer_arg ta; +static pthread_t timer_thread; + +extern "C" +{ + +void handler(int signo, siginfo_t *info, void *context) { + //printf("Signal, %i\n", signo); + last_siginfo = *info; + caught = true; + siglongjmp(*target, 1); +} + +void alarm_handler(int signo) { + //printf("Alarm\n"); + timedout = true; + siglongjmp(*target, 1); +} + + +sigjmp_buf *get_jmpbuf_cpp() { + return &buf; +} + +static struct sigaction old_segv; +static struct sigaction old_abrt; +static struct sigaction old_alrm; + +void *timer(void *arg) { + sleep(ta.timeout); + pthread_kill(ta.main_thread, SIGALRM); + return NULL; +} + +void init_signals_cpp(sigjmp_buf *env, unsigned int timeout) { + //printf("Initializing signals!\n"); + struct sigaction action; + action.sa_sigaction = handler; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO; + + sigaction(SIGSEGV, &action, &old_segv); + sigaction(SIGABRT, &action, &old_abrt); + + struct sigaction alarm_action; + alarm_action.sa_handler = alarm_handler; + sigemptyset(&alarm_action.sa_mask); + alarm_action.sa_flags = 0; + sigaction(SIGALRM, &alarm_action, &old_alrm); + + target = env; + initialized = true; + caught = false; + timedout = false; + + ta.timeout = timeout; + ta.main_thread = pthread_self(); + + pthread_create(&timer_thread, NULL, timer, (void *)&ta); +} + + +void deinit_signals_cpp() { + //printf("Deinitializing signals!\n"); + pthread_cancel(timer_thread); + + sigaction(SIGSEGV, &old_segv, NULL); + sigaction(SIGABRT, &old_abrt, NULL); + sigaction(SIGALRM, &old_alrm, NULL); + + target = NULL; + initialized = false; +} + +bool get_timedout_cpp() { + return timedout; +} + +jobject get_siginfo_cpp(JNIEnv *env) { + if (!caught) { + return NULL; + } + + jclass local_siginfo_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/SigInfo"); + jmethodID siginfo_init = env->GetMethodID(local_siginfo_class, "<init>", "(IIIIIJIJJ)V"); + return env->NewObject(local_siginfo_class, siginfo_init, + (jint) last_siginfo.si_signo, + (jint) last_siginfo.si_code, + (jint) last_siginfo.si_errno, + (jint) last_siginfo.si_pid, + (jint) last_siginfo.si_uid, + (jlong) last_siginfo.si_addr, + (jint) last_siginfo.si_status, + (jlong) last_siginfo.si_band, + (jlong) 0); +} + +} + +#endif
\ No newline at end of file diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/cpp_signals.hpp b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/cpp_signals.hpp new file mode 100644 index 0000000..4dc222f --- /dev/null +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/cpp_signals.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include <jni.h> +#include <setjmp.h> +#include <signal.h> + +#define TIMEOUT 5 + +extern "C" +{ + +/** + * + */ +void init_signals_cpp(jmp_buf *env, unsigned int timeout); + +/** + * + */ +sigjmp_buf *get_jmpbuf_cpp(); + +/** + * + */ +void deinit_signals_cpp(); + +/** + * + */ +bool get_timedout_cpp(); + +/** + * + */ +jobject get_siginfo_cpp(JNIEnv *env); + + +#define SIG_TRY(timeout) init_signals_cpp(get_jmpbuf_cpp(), timeout); \ + if (!sigsetjmp(*get_jmpbuf_cpp(), 1)) +#define SIG_CATCH() deinit_signals_cpp(); +#define SIG_DEINIT() deinit_signals_cpp(); +#define SIG_HANDLE(env) do { \ + jobject siginfo = get_siginfo_cpp(env); \ + if (siginfo != NULL) { \ + jclass sigexception_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/SignalException"); \ + jmethodID new_sigexception = env->GetMethodID(sigexception_class, "<init>", "(Lcz/crcs/ectester/standalone/libs/jni/SigInfo;)V"); \ + jobject sigexception = env->NewObject(sigexception_class, new_sigexception, siginfo); \ + env->Throw((jthrowable) sigexception); \ + } \ + if (get_timedout_cpp()) { \ + jclass timeoutexception_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/TimeoutException"); \ + env->ThrowNew(timeoutexception_class, "Operation timed out."); \ + } \ + } while (0) +#define SIG_CATCH_HANDLE(env) SIG_CATCH(); \ + SIG_HANDLE(env) + + +}
\ No newline at end of file diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp index 6ec2060..c4c74a6 100644 --- a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp @@ -71,6 +71,16 @@ using CryptoPP::Integer; #include "cpp_utils.hpp" #include "c_timing.h" +#include "cpp_signals.hpp" +#undef SIG_TRY +#undef SIG_CATCH_HANDLE +#undef SIG_CATCH +#undef SIG_HANDLE +#undef SIG_DEINIT +#define SIG_TRY(x) +#define SIG_CATCH_HANDLE(x) +#define SIG_CATCH() +#define SIG_DEINIT() /* * Crypto++: @@ -504,14 +514,17 @@ template <class EC> jobject generate_from_group(JNIEnv *env, DL_GroupParameters_ typename ECDH<EC>::Domain ec_domain(group); SecByteBlock priv(ec_domain.PrivateKeyLength()), pub(ec_domain.PublicKeyLength()); - try { - native_timing_start(); - ec_domain.GenerateKeyPair(rng, priv, pub); - native_timing_stop(); - } catch (Exception & ex) { - throw_new(env, "java/security/GeneralSecurityException", ex.what()); - return nullptr; - } + SIG_TRY(TIMEOUT) { + try { + native_timing_start(); + ec_domain.GenerateKeyPair(rng, priv, pub); + native_timing_stop(); + } catch (Exception & ex) { + SIG_DEINIT(); + throw_new(env, "java/security/GeneralSecurityException", ex.what()); + return nullptr; + } + } SIG_CATCH_HANDLE(env); jbyteArray pub_bytearray = env->NewByteArray(pub.SizeInBytes()); jbyte *pub_bytes = env->GetByteArrayElements(pub_bytearray, nullptr); @@ -587,31 +600,34 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey bool success; std::unique_ptr<SecByteBlock> secret; - try { - std::unique_ptr<DL_GroupParameters_EC<ECP>> ecp_group = fp_group_from_params(env, params); - if (ecp_group == nullptr) { - std::unique_ptr<DL_GroupParameters_EC<EC2N>> ec2n_group = f2m_group_from_params(env, params); + SIG_TRY(TIMEOUT) { + try { + std::unique_ptr<DL_GroupParameters_EC<ECP>> ecp_group = fp_group_from_params(env, params); + if (ecp_group == nullptr) { + std::unique_ptr<DL_GroupParameters_EC<EC2N>> ec2n_group = f2m_group_from_params(env, params); - ECDH<EC2N>::Domain dh_agreement(*ec2n_group); + ECDH<EC2N>::Domain dh_agreement(*ec2n_group); - secret = std::make_unique<SecByteBlock>(dh_agreement.AgreedValueLength()); - native_timing_start(); - success = dh_agreement.Agree(*secret, private_key, public_key); - native_timing_stop(); + secret = std::make_unique<SecByteBlock>(dh_agreement.AgreedValueLength()); + native_timing_start(); + success = dh_agreement.Agree(*secret, private_key, public_key); + native_timing_stop(); - } else { - ECDH<ECP>::Domain dh_agreement(*ecp_group); + } else { + ECDH<ECP>::Domain dh_agreement(*ecp_group); - secret = std::make_unique<SecByteBlock>(dh_agreement.AgreedValueLength()); - native_timing_start(); - success = dh_agreement.Agree(*secret, private_key, public_key); - native_timing_stop(); + secret = std::make_unique<SecByteBlock>(dh_agreement.AgreedValueLength()); + native_timing_start(); + success = dh_agreement.Agree(*secret, private_key, public_key); + native_timing_stop(); + } + } catch (Exception & ex) { + SIG_DEINIT(); + throw_new(env, "java/security/GeneralSecurityException", ex.what()); + return nullptr; } - } catch (Exception & ex) { - throw_new(env, "java/security/GeneralSecurityException", ex.what()); - return nullptr; - } + } SIG_CATCH_HANDLE(env); if (!success) { throw_new(env, "java/security/GeneralSecurityException", "Agreement was unsuccessful."); @@ -642,9 +658,12 @@ jbyteArray sign_message(JNIEnv *env, DL_GroupParameters_EC<EC> group, jbyteArray jsize data_length = env->GetArrayLength(data); jbyte *data_bytes = env->GetByteArrayElements(data, nullptr); - native_timing_start(); - size_t len = signer.SignMessage(rng, (byte *)data_bytes, data_length, (byte *)signature.c_str()); - native_timing_stop(); + size_t len; + SIG_TRY(TIMEOUT) { + native_timing_start(); + len = signer.SignMessage(rng, (byte *)data_bytes, data_length, (byte *)signature.c_str()); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); signature.resize(len); @@ -740,9 +759,12 @@ jboolean verify_message(JNIEnv *env, DL_GroupParameters_EC<EC> group, jbyteArray jsize data_length = env->GetArrayLength(data); jbyte *data_bytes = env->GetByteArrayElements(data, nullptr); - native_timing_start(); - bool result = verifier.VerifyMessage((byte *)data_bytes, data_length, sig, sig_len); - native_timing_stop(); + bool result; + SIG_TRY(TIMEOUT) { + native_timing_start(); + result = verifier.VerifyMessage((byte *)data_bytes, data_length, sig, sig_len); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); return result; diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/gcrypt.c b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/gcrypt.c index ef62fbf..795c30a 100644 --- a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/gcrypt.c +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/gcrypt.c @@ -1,5 +1,6 @@ #include "c_utils.h" #include "c_timing.h" +#include "c_signals.h" #include "native.h" #include <stdio.h> @@ -180,8 +181,11 @@ static jobject mpi_to_biginteger(JNIEnv *env, gcry_mpi_t mpi) { return NULL; } - jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V"); jbyteArray bytes = mpi_to_bytearray(env, mpi); + if (!bytes) { + return NULL; + } + jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V"); jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes); return result; } @@ -196,20 +200,6 @@ static gcry_mpi_t biginteger_to_mpi(JNIEnv *env, jobject bigint) { return bytearray_to_mpi(env, byte_array); } -static jint mpi_to_jint(gcry_mpi_t mpi) { - jint result = 0; - unsigned long nbits = gcry_mpi_get_nbits(mpi); - int max_bits = sizeof(jint) * 8; - for (size_t i = 0; i < nbits && i < max_bits; ++i) { - if (gcry_mpi_test_bit(mpi, nbits - i - 1)) { - result = ((result << 1) | 1); - } else { - result = (result << 1); - } - } - return result; -} - static jobject buff_to_ecpoint(JNIEnv *env, gcry_buffer_t buff) { jint coord_size = (buff.len - 1) / 2; jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V"); @@ -232,9 +222,10 @@ static jobject buff_to_ecpoint(JNIEnv *env, gcry_buffer_t buff) { static jobject create_ec_param_spec(JNIEnv *env, gcry_sexp_t key) { jobject result = NULL; - gcry_mpi_t p, a, b, n, h; + gcry_mpi_t p, a, b, n; + unsigned int h; gcry_buffer_t g = {0}; - gcry_error_t err = gcry_sexp_extract_param(key, "ecc", "pab&g+nh", &p, &a, &b, &g, &n, &h, NULL); + gcry_error_t err = gcry_sexp_extract_param(key, "ecc", "pab&g+n%uh", &p, &a, &b, &g, &n, &h, NULL); if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { throw_new_var(env, "java/security/GeneralSecurityException", "Error exporting domain parameters. Error: %ui", gcry_err_code(err)); goto end; @@ -244,7 +235,11 @@ static jobject create_ec_param_spec(JNIEnv *env, gcry_sexp_t key) { jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V"); jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, pi); - jobject ai = mpi_to_biginteger(env, a); + jobject ai = mpi_to_biginteger(env, a); + if (!ai) { + jmethodID biginteger_valueof = (*env)->GetStaticMethodID(env, biginteger_class, "valueOf", "(J)Ljava/math/BigInteger;"); + ai = (*env)->CallStaticObjectMethod(env, biginteger_class, biginteger_valueof, (jlong)0); + } jobject bi = mpi_to_biginteger(env, b); jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); @@ -253,7 +248,7 @@ static jobject create_ec_param_spec(JNIEnv *env, gcry_sexp_t key) { jobject gen = buff_to_ecpoint(env, g); jobject order = mpi_to_biginteger(env, n); - jint cofactor = mpi_to_jint(h); + jint cofactor = (jint) h; jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V"); result = (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, gen, order, cofactor); @@ -264,7 +259,6 @@ end: gcry_mpi_release(b); gcry_free(g.data); gcry_mpi_release(n); - gcry_mpi_release(h); return result; } @@ -272,9 +266,12 @@ static jobject generate_from_sexp(JNIEnv *env, gcry_sexp_t gen_sexp) { jobject result = NULL; gcry_sexp_t key_sexp; - native_timing_start(); - gcry_error_t err = gcry_pk_genkey(&key_sexp, gen_sexp); - native_timing_stop(); + gcry_error_t err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = gcry_pk_genkey(&key_sexp, gen_sexp); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { throw_new_var(env, "java/security/GeneralSecurityException", "Error generating key. Error: %ui", gcry_err_code(err)); @@ -460,12 +457,15 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey gcry_sexp_t res_sexp; // TODO: figure out why ecc_encrypt_raw takes signed representation.. Nobody uses that., everybody uses unsigned reduced mod p. - native_timing_start(); - gcry_error_t err = gcry_pk_encrypt(&res_sexp, enc_sexp, pub); - native_timing_stop(); + gcry_error_t err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = gcry_pk_encrypt(&res_sexp, enc_sexp, pub); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { - throw_new_var(env, "java/security/GeneralSecurityException", "Error performing ECDH. Error: %ui", gcry_err_code(err)); + throw_new_var(env, "java/security/GeneralSecurityException", "Error performing ECDH. Error: %u", gcry_err_code(err)); goto end; } @@ -572,11 +572,15 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig get_sign_data_sexp(env, &data_sexp, this, data); gcry_sexp_t res_sexp; - native_timing_start(); - gcry_error_t err = gcry_pk_sign(&res_sexp, data_sexp, priv_sexp); - native_timing_stop(); + gcry_error_t err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = gcry_pk_sign(&res_sexp, data_sexp, priv_sexp); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); + if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { - throw_new_var(env, "java/security/GeneralSecurityException", "Error performing ECDSA. Error: %ui", gcry_err_code(err)); + throw_new_var(env, "java/security/GeneralSecurityException", "Error performing ECDSA. Error: %u", gcry_err_code(err)); goto release_init; } @@ -584,7 +588,7 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig gcry_buffer_t s_buf = {0}; err = gcry_sexp_extract_param(res_sexp, "ecdsa", "&rs", &r_buf, &s_buf, NULL); if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { - throw_new_var(env, "java/security/GeneralSecurityException", "Error extracting ECDSA output. Error: %ui", gcry_err_code(err)); + throw_new_var(env, "java/security/GeneralSecurityException", "Error extracting ECDSA output. Error: %u", gcry_err_code(err)); goto release_res; } result = asn1_der_encode(env, r_buf.data, r_buf.len, s_buf.data, s_buf.len); @@ -627,13 +631,16 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna gcry_sexp_t sig_sexp; gcry_sexp_build(&sig_sexp, NULL, "(sig-val (ecdsa (r %M) (s %M)))", r_mpi, s_mpi); - native_timing_start(); - gcry_error_t err = gcry_pk_verify(sig_sexp, data_sexp, pub_sexp); - native_timing_stop(); + gcry_error_t err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = gcry_pk_verify(sig_sexp, data_sexp, pub_sexp); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { if (gcry_err_code(err) != GPG_ERR_BAD_SIGNATURE) { - throw_new(env, "java/security/GeneralSecurityException", "Error verif sig."); + throw_new_var(env, "java/security/GeneralSecurityException", "Error verif sig. Error: %u", gcry_err_code(err)); goto release_init; } } else { diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/ippcp.c b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/ippcp.c index 2f876d2..fbf917e 100644 --- a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/ippcp.c +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/ippcp.c @@ -1,5 +1,6 @@ #include "c_timing.h" #include "c_utils.h" +#include "c_signals.h" #include <stdint.h> #include <stdlib.h> @@ -379,9 +380,12 @@ static jobject generate_from_curve(JNIEnv *env, int keysize, IppsECCPState *curv int ord_bytes = (ord_bits + 7) / 8; IppsBigNumState *secret = new_bn(ord_bits); - native_timing_start(); - IppStatus err = ippsECCPGenKeyPair(secret, point, curve, prng_wrapper, prng_state); - native_timing_stop(); + IppStatus err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = ippsECCPGenKeyPair(secret, point, curve, prng_wrapper, prng_state); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (err != ippStsNoErr) { throw_new(env, "java/security/GeneralSecurityException", ippcpGetStatusString(err)); @@ -559,9 +563,12 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey IppsBigNumState *share = new_bn(keysize); - native_timing_start(); - IppStatus err = ippsECCPSharedSecretDH(priv_bn, pub, share, curve); - native_timing_stop(); + IppStatus err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = ippsECCPSharedSecretDH(priv_bn, pub, share, curve); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); free(priv_bn); free(pub); @@ -622,23 +629,29 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig jbyte r_buf[ord_bytes]; jbyte s_buf[ord_bytes]; - native_timing_start(); - IppStatus err = ippsECCPGenKeyPair(ephemeral_secret, ephemeral_point, curve, prng_wrapper, prng_state); - if (err != ippStsNoErr) { - throw_new(env, "java/security/GeneralSecurityException", ippcpGetStatusString(err)); - goto error; - } - err = ippsECCPSetKeyPair(ephemeral_secret, ephemeral_point, ippFalse, curve); - if (err != ippStsNoErr) { - throw_new(env, "java/security/GeneralSecurityException", ippcpGetStatusString(err)); - goto error; - } - err = ippsECCPSignDSA(data_bn, priv_bn, r, s, curve); - if (err != ippStsNoErr) { - throw_new(env, "java/security/GeneralSecurityException", ippcpGetStatusString(err)); - goto error; - } - native_timing_stop(); + IppStatus err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = ippsECCPGenKeyPair(ephemeral_secret, ephemeral_point, curve, prng_wrapper, prng_state); + if (err != ippStsNoErr) { + SIG_DEINIT(); + throw_new(env, "java/security/GeneralSecurityException", ippcpGetStatusString(err)); + goto error; + } + err = ippsECCPSetKeyPair(ephemeral_secret, ephemeral_point, ippFalse, curve); + if (err != ippStsNoErr) { + SIG_DEINIT(); + throw_new(env, "java/security/GeneralSecurityException", ippcpGetStatusString(err)); + goto error; + } + err = ippsECCPSignDSA(data_bn, priv_bn, r, s, curve); + if (err != ippStsNoErr) { + SIG_DEINIT(); + throw_new(env, "java/security/GeneralSecurityException", ippcpGetStatusString(err)); + goto error; + } + native_timing_stop(); + } SIG_CATCH_HANDLE(env); bn_get(r, (uint8_t *) r_buf, ord_bytes); bn_get(s, (uint8_t *) s_buf, ord_bytes); @@ -713,10 +726,13 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna IppECResult result; - native_timing_start(); - ippsECCPSetKeyPair(NULL, pub, ippTrue, curve); - IppStatus err = ippsECCPVerifyDSA(data_bn, r, s, &result, curve); - native_timing_stop(); + IppStatus err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + ippsECCPSetKeyPair(NULL, pub, ippTrue, curve); + err = ippsECCPVerifyDSA(data_bn, r, s, &result, curve); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); free(curve); free(pub); diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/libressl.c b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/libressl.c index 398ad1e..d329f45 100644 --- a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/libressl.c +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/libressl.c @@ -1,5 +1,6 @@ #include "c_utils.h" #include "c_timing.h" +#include "c_signals.h" #include "native.h" #include <string.h> @@ -313,9 +314,12 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) { EC_KEY *key = EC_KEY_new(); EC_KEY_set_group(key, curve); - native_timing_start(); - int err = EC_KEY_generate_key(key); - native_timing_stop(); + int err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = EC_KEY_generate_key(key); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (!err) { throw_new(env, "java/security/GeneralSecurityException", "Error generating key, EC_KEY_generate_key."); @@ -416,10 +420,19 @@ EC_KEY *barray_to_pubkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray pub) { jsize pub_len = (*env)->GetArrayLength(env, pub); jbyte *pub_data = (*env)->GetByteArrayElements(env, pub, NULL); EC_POINT *pub_point = EC_POINT_new(curve); - EC_POINT_oct2point(curve, pub_point, (unsigned char *) pub_data, pub_len, NULL); + int retval = EC_POINT_oct2point(curve, pub_point, (unsigned char *) pub_data, pub_len, NULL); (*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT); - EC_KEY_set_public_key(result, pub_point); + if (!retval) { + EC_POINT_free(pub_point); + throw_new(env, "java/security/GeneralSecurityException", "Error loading key, EC_POINT_oct2point."); + return NULL; + } + retval = EC_KEY_set_public_key(result, pub_point); EC_POINT_free(pub_point); + if (!retval) { + throw_new(env, "java/security/GeneralSecurityException", "Error loading key, EC_KEY_set_public_key."); + return NULL; + } return result; } @@ -430,32 +443,46 @@ EC_KEY *barray_to_privkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray priv) jbyte *priv_data = (*env)->GetByteArrayElements(env, priv, NULL); BIGNUM *s = BN_bin2bn((unsigned char *) priv_data, priv_len, NULL); (*env)->ReleaseByteArrayElements(env, priv, priv_data, JNI_ABORT); - EC_KEY_set_private_key(result, s); + int retval = EC_KEY_set_private_key(result, s); BN_free(s); + if (!retval) { + throw_new(env, "java/security/GeneralSecurityException", "Error loading key, EC_KEY_set_private_key."); + return NULL; + } return result; } JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Libressl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) { + jbyteArray result = NULL; EC_GROUP *curve = create_curve(env, params); if (!curve) { throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found."); - return NULL; + goto free_curve; } EC_KEY *pub = barray_to_pubkey(env, curve, pubkey); + if (!pub) { + goto free_pub; + } EC_KEY *priv = barray_to_privkey(env, curve, privkey); + if (!priv) { + goto free_priv; + } int field_size = EC_GROUP_get_degree(curve); size_t secret_len = (field_size + 7)/8; //TODO: Do more KeyAgreements here, but will have to do the hash-fun manually, // probably using the ECDH_KDF_X9_62 by wrapping it and dynamically choosing the EVP_MD. from the type string. - jbyteArray result = (*env)->NewByteArray(env, secret_len); + result = (*env)->NewByteArray(env, secret_len); jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL); - native_timing_start(); - int err = ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL); - native_timing_stop(); + int err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (err <= 0) { throw_new(env, "java/security/GeneralSecurityException", "Error computing ECDH, ECDH_compute_key."); @@ -465,8 +492,11 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey } (*env)->ReleaseByteArrayElements(env, result, result_data, 0); - EC_KEY_free(pub); +free_priv: EC_KEY_free(priv); +free_pub: + EC_KEY_free(pub); +free_curve: EC_GROUP_free(curve); return result; } @@ -477,21 +507,28 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgr } JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Libressl_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) { + jbyteArray result = NULL; EC_GROUP *curve = create_curve(env, params); if (!curve) { throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found."); - return NULL; + goto free_curve; } EC_KEY *priv = barray_to_privkey(env, curve, privkey); + if (!priv) { + goto free_priv; + } jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); // TODO: Do more Signatures here, maybe use the EVP interface to get to the hashes easier and not hash manually? - native_timing_start(); - ECDSA_SIG *signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv); - native_timing_stop(); + ECDSA_SIG *signature; + SIG_TRY(TIMEOUT) { + native_timing_start(); + signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); if (!signature) { @@ -501,14 +538,16 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig } jsize sig_len = i2d_ECDSA_SIG(signature, NULL); - jbyteArray result = (*env)->NewByteArray(env, sig_len); + result = (*env)->NewByteArray(env, sig_len); jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL); jbyte *result_data_ptr = result_data; i2d_ECDSA_SIG(signature, (unsigned char **)&result_data_ptr); (*env)->ReleaseByteArrayElements(env, result, result_data, 0); ECDSA_SIG_free(signature); +free_priv: EC_KEY_free(priv); +free_curve: EC_GROUP_free(curve); return result; } @@ -521,6 +560,10 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna } EC_KEY *pub = barray_to_pubkey(env, curve, pubkey); + if (!pub) { + EC_GROUP_free(curve); + return JNI_FALSE; + } jsize sig_len = (*env)->GetArrayLength(env, signature); jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL); @@ -531,9 +574,13 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); - native_timing_start(); - int result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub); - native_timing_stop(); + int result; + SIG_TRY(TIMEOUT) { + native_timing_start(); + result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); if (result < 0) { diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/mbedtls.c b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/mbedtls.c index ab556d8..7a552da 100644 --- a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/mbedtls.c +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/mbedtls.c @@ -1,5 +1,6 @@ #include "c_utils.h" #include "c_timing.h" +#include "c_signals.h" #include "native.h" #include <string.h> @@ -315,9 +316,12 @@ static jobject generate_from_curve(JNIEnv *env, mbedtls_ecp_group *group) { } gen_counter++; - native_timing_start(); - int error = mbedtls_ecp_gen_keypair(group, &d, &Q, ctr_drbg_wrapper, &ctr_drbg); - native_timing_stop(); + int error; + SIG_TRY(TIMEOUT) { + native_timing_start(); + error = mbedtls_ecp_gen_keypair(group, &d, &Q, ctr_drbg_wrapper, &ctr_drbg); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (error) { throw_new(env, "java/security/GeneralSecurityException", err_to_string(error)); @@ -453,9 +457,11 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey mbedtls_mpi result; mbedtls_mpi_init(&result); - native_timing_start(); - error = mbedtls_ecdh_compute_shared(&curve, &result, &pub, &priv, ctr_drbg_wrapper, &ctr_drbg); - native_timing_stop(); + SIG_TRY(TIMEOUT) { + native_timing_start(); + error = mbedtls_ecdh_compute_shared(&curve, &result, &pub, &priv, ctr_drbg_wrapper, &ctr_drbg); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (error) { throw_new(env, "java/security/GeneralSecurityException", err_to_string(error)); @@ -504,9 +510,11 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); - native_timing_start(); - error = mbedtls_ecdsa_sign(&curve, &r, &s, &priv, (unsigned char *) data_data, data_size, ctr_drbg_wrapper, &ctr_drbg); - native_timing_stop(); + SIG_TRY(TIMEOUT) { + native_timing_start(); + error = mbedtls_ecdsa_sign(&curve, &r, &s, &priv, (unsigned char *) data_data, data_size, ctr_drbg_wrapper, &ctr_drbg); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); mbedtls_mpi_free(&priv); mbedtls_ecp_group_free(&curve); @@ -563,9 +571,11 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); - native_timing_start(); - error = mbedtls_ecdsa_verify(&curve, (unsigned char *) data_data, data_size, &pub, &r, &s); - native_timing_stop(); + SIG_TRY(TIMEOUT) { + native_timing_start(); + error = mbedtls_ecdsa_verify(&curve, (unsigned char *) data_data, data_size, &pub, &r, &s); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); if (error) { diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/native.h b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/native.h index dcaf57c..60c59b1 100644 --- a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/native.h +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/native.h @@ -1861,3 +1861,139 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna } #endif #endif +/* Header for class cz_crcs_ectester_standalone_libs_NettleLib */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_NettleLib +#define _Included_cz_crcs_ectester_standalone_libs_NettleLib +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_NettleLib + * Method: createProvider + * Signature: ()Ljava/security/Provider; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_NettleLib_createProvider + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_NettleLib + * Method: getCurves + * Signature: ()Ljava/util/Set; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_NettleLib_getCurves + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle +#ifdef __cplusplus +extern "C" { +#endif +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle_serialVersionUID 1421746759512286392LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle_MAX_ARRAY_SIZE +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle_MAX_ARRAY_SIZE 2147483639L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle_KEYS +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle_KEYS 0L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle_VALUES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle_VALUES 1L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle_ENTRIES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle_ENTRIES 2L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle_serialVersionUID 4112578634029874840LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle_serialVersionUID -4298000515446427739LL +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Nettle + * Method: setup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Nettle_setup + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Nettle */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Nettle +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Nettle +#ifdef __cplusplus +extern "C" { +#endif +#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Nettle_DEFAULT_KEYSIZE +#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Nettle_DEFAULT_KEYSIZE 256L +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Nettle + * Method: generate + * Signature: (ILjava/security/SecureRandom;Ljava/security/spec/AlgorithmParameterSpec;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_generate__ILjava_security_SecureRandom_2Ljava_security_spec_AlgorithmParameterSpec_2 + (JNIEnv *, jobject, jint, jobject, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Nettle + * Method: generate + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;Ljava/security/spec/AlgorithmParameterSpec;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2Ljava_security_spec_AlgorithmParameterSpec_2 + (JNIEnv *, jobject, jobject, jobject, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Nettle */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Nettle +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Nettle +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Nettle + * Method: generateSecret + * Signature: ([B[BLjava/security/spec/ECGenParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Nettle_generateSecret + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Nettle */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Nettle +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Nettle +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Nettle + * Method: sign + * Signature: ([B[BLjava/security/spec/ECGenParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Nettle_sign + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Nettle + * Method: verify + * Signature: ([B[B[BLjava/security/spec/ECGenParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Nettle_verify + (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/nettle.c b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/nettle.c index dfc8389..e7ec00e 100644 --- a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/nettle.c +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/nettle.c @@ -1,5 +1,6 @@ #include "c_utils.h" #include "c_timing.h" +#include "c_signals.h" #include "native.h" #include <string.h> @@ -35,7 +36,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_NettleLib_create } JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Nettle_setup(JNIEnv *env, jobject self) { - INIT_PROVIDER(env, provider_class); ADD_KPG(env, self, "EC", "Nettle"); ADD_KA(env, self, "ECDH", "NettleECDH"); @@ -66,16 +66,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_NettleLib_getCur return result; } -JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_keysizeSupported(JNIEnv *env, jobject self, jint keysize) { - int supported[] = {192, 224, 256, 384, 521}; - for (int i = 0; i < 5; i++) { - if (keysize == supported[i]) { - return JNI_TRUE; - } - } - return JNI_FALSE; -} - static const struct ecc_curve* create_curve_from_name(JNIEnv *env, const char* curve_name) { if (!curve_name) { return NULL; @@ -115,34 +105,6 @@ static const struct ecc_curve* create_curve_from_size(JNIEnv *env, jint keysize) } } -JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_paramsSupported(JNIEnv *env, jobject self, jobject params){ - if (params == NULL) { - return JNI_FALSE; - } - - if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { - return JNI_FALSE; - } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) { - jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); - jstring name = (*env)->CallObjectMethod(env, params, get_name); - const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL); - - char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"}; - for (int i = 0; i < sizeof(curve_name); i++) { - if (strcasecmp(utf_name, curve_name[i]) == 0) { - (*env)->ReleaseStringUTFChars(env, name, utf_name); - return JNI_TRUE; - } - } - (*env)->ReleaseStringUTFChars(env, name, utf_name); - return JNI_FALSE; - } else { - return JNI_FALSE; - } - return JNI_FALSE; - -} - static jobject generate_from_curve(JNIEnv *env, const struct ecc_curve* curve, jobject spec, int byte_size) { struct ecc_point pub; @@ -150,9 +112,12 @@ static jobject generate_from_curve(JNIEnv *env, const struct ecc_curve* curve, j ecc_point_init(&pub, curve); ecc_scalar_init(&priv, curve); - native_timing_start(); - ecdsa_generate_keypair(&pub, &priv, (void *) &yarrow, (nettle_random_func *) yarrow256_random); - native_timing_stop(); + + SIG_TRY(TIMEOUT) { + native_timing_start(); + ecdsa_generate_keypair(&pub, &priv, (void *) &yarrow, (nettle_random_func *) yarrow256_random); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); mpz_t private_value; mpz_init(private_value); @@ -206,16 +171,15 @@ static jobject generate_from_curve(JNIEnv *env, const struct ecc_curve* curve, j return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey); } -JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random) { +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_generate__ILjava_security_SecureRandom_2Ljava_security_spec_AlgorithmParameterSpec_2(JNIEnv *env, jobject self, jint keysize, jobject random, jobject spec) { const struct ecc_curve* curve = create_curve_from_size(env, keysize); if (!curve) { throw_new(env, "java/lang/UnsupportedOperationException", "Not supported."); return NULL; } int byte_size = (keysize + 7) / 8; - jobject result = generate_from_curve(env, curve, NULL, byte_size); + jobject result = generate_from_curve(env, curve, spec, byte_size); return result; - return NULL; } JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2Ljava_security_spec_AlgorithmParameterSpec_2(JNIEnv *env, jobject self, jobject params, jobject random, jobject spec) { @@ -261,7 +225,10 @@ int barray_to_pubkey(JNIEnv *env, struct ecc_point* pubKey , jbyteArray pub) { mpz_import(x, pointLength, 1, sizeof(unsigned char), 0, 0, pub_data+1); mpz_import(y, pointLength, 1, sizeof(unsigned char), 0, 0, pub_data+1+pointLength); (*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT); - ecc_point_set(pubKey, x, y); + if (ecc_point_set(pubKey, x, y) == 0) { + throw_new(env, "java/security/GeneralSecurityException", "Error loading key, ecc_point_set."); + return 0; + } return pointLength; } @@ -276,7 +243,7 @@ int barray_to_privkey(JNIEnv *env, struct ecc_scalar* privKey, jbyteArray priv) return priv_len; } -JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Nettle_generateSecret___3B_3BLjava_security_spec_ECGenParameterSpec_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) { +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Nettle_generateSecret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) { jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); jstring name = (*env)->CallObjectMethod(env, params, get_name); const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL); @@ -303,7 +270,12 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey struct ecc_point eccPubPoint; ecc_point_init(&eccPubPoint, curve); - barray_to_pubkey(env, &eccPubPoint, pubkey); + int publen = barray_to_pubkey(env, &eccPubPoint, pubkey); + if (publen == 0) { + ecc_scalar_clear(&privScalar); + ecc_point_clear(&eccPubPoint); + return NULL; + } struct ecc_point resultPoint; ecc_point_init(&resultPoint, curve); @@ -311,9 +283,11 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey jbyteArray result = (*env)->NewByteArray(env, byte_size); jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL); - native_timing_start(); - ecc_point_mul(&resultPoint, &privScalar, &eccPubPoint); - native_timing_stop(); + SIG_TRY(TIMEOUT) { + native_timing_start(); + ecc_point_mul(&resultPoint, &privScalar, &eccPubPoint); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); mpz_t x; mpz_init(x); @@ -333,11 +307,6 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey return result; } -JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Nettle_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) { - throw_new(env, "java/lang/UnsupportedOperationException", "Not supported."); - return NULL; -} - // credit to https://github.com/crocs-muni/ECTester/blob/master/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c size_t signature_to_der(struct dsa_signature* signature, unsigned char *result, int byte_size) { size_t r_tmpSize; @@ -461,9 +430,11 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig struct dsa_signature signature; dsa_signature_init(&signature); - native_timing_start(); - ecdsa_sign(&privScalar, (void *) &yarrow, (nettle_random_func *) yarrow256_random, data_size, (unsigned char*)data_data, &signature); - native_timing_stop(); + SIG_TRY(TIMEOUT) { + native_timing_start(); + ecdsa_sign(&privScalar, (void *) &yarrow, (nettle_random_func *) yarrow256_random, data_size, (unsigned char*)data_data, &signature); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); @@ -515,9 +486,13 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); - native_timing_start(); - int result = ecdsa_verify(&eccPubPoint, data_size, (unsigned char*)data_data, &eccSignature); - native_timing_stop(); + int result; + SIG_TRY(TIMEOUT) { + native_timing_start(); + result = ecdsa_verify(&eccPubPoint, data_size, (unsigned char*)data_data, &eccSignature); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); ecc_point_clear(&eccPubPoint); diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/openssl.c b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/openssl.c index 3fa560e..59eb0db 100644 --- a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/openssl.c +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/openssl.c @@ -1,5 +1,6 @@ #include "c_utils.h" #include "c_timing.h" +#include "c_signals.h" #include "native.h" #include <string.h> @@ -350,9 +351,12 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) { EC_KEY *key = EC_KEY_new(); EC_KEY_set_group(key, curve); - native_timing_start(); - int result = EC_KEY_generate_key(key); - native_timing_stop(); + int result; + SIG_TRY(TIMEOUT) { + native_timing_start(); + result = EC_KEY_generate_key(key); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (!result) { throw_new(env, "java/security/GeneralSecurityException", "Error generating key, EC_KEY_generate_key."); @@ -451,10 +455,19 @@ EC_KEY *barray_to_pubkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray pub) { jsize pub_len = (*env)->GetArrayLength(env, pub); jbyte *pub_data = (*env)->GetByteArrayElements(env, pub, NULL); EC_POINT *pub_point = EC_POINT_new(curve); - EC_POINT_oct2point(curve, pub_point, (unsigned char *) pub_data, pub_len, NULL); + int retval = EC_POINT_oct2point(curve, pub_point, (unsigned char *) pub_data, pub_len, NULL); (*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT); - EC_KEY_set_public_key(result, pub_point); + if (!retval) { + EC_POINT_free(pub_point); + throw_new(env, "java/security/GeneralSecurityException", "Error loading key, EC_POINT_oct2point."); + return NULL; + } + retval = EC_KEY_set_public_key(result, pub_point); EC_POINT_free(pub_point); + if (!retval) { + throw_new(env, "java/security/GeneralSecurityException", "Error loading key, EC_KEY_set_public_key."); + return NULL; + } return result; } @@ -465,8 +478,12 @@ EC_KEY *barray_to_privkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray priv) jbyte *priv_data = (*env)->GetByteArrayElements(env, priv, NULL); BIGNUM *s = BN_bin2bn((unsigned char *) priv_data, priv_len, NULL); (*env)->ReleaseByteArrayElements(env, priv, priv_data, JNI_ABORT); - EC_KEY_set_private_key(result, s); + int retval = EC_KEY_set_private_key(result, s); BN_free(s); + if (!retval) { + throw_new(env, "java/security/GeneralSecurityException", "Error loading key, EC_KEY_set_private_key."); + return NULL; + } return result; } @@ -478,7 +495,13 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey } EC_KEY *pub = barray_to_pubkey(env, curve, pubkey); + if (!pub) { + return NULL; + } EC_KEY *priv = barray_to_privkey(env, curve, privkey); + if (!priv) { + return NULL; + } int field_size = EC_GROUP_get_degree(curve); size_t secret_len = (field_size + 7)/8; @@ -488,12 +511,15 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey jbyteArray result = (*env)->NewByteArray(env, secret_len); jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL); - native_timing_start(); - int err = ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL); - native_timing_stop(); + int err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (err <= 0) { - throw_new(env, "java/security/GeneralSecurityException", "Error computing ECDH, ECDH_compute_key."); + throw_new_var(env, "java/security/GeneralSecurityException", "Error computing ECDH, ECDH_compute_key (%i).", err); EC_KEY_free(pub); EC_KEY_free(priv); EC_GROUP_free(curve); (*env)->ReleaseByteArrayElements(env, result, result_data, JNI_ABORT); return NULL; @@ -519,14 +545,20 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig } EC_KEY *priv = barray_to_privkey(env, curve, privkey); + if (!priv) { + return NULL; + } jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); // TODO: Do more Signatures here, maybe use the EVP interface to get to the hashes easier and not hash manually? - native_timing_start(); - ECDSA_SIG *signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv); - native_timing_stop(); + ECDSA_SIG *signature; + SIG_TRY(TIMEOUT) { + native_timing_start(); + signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); if (!signature) { @@ -556,6 +588,9 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna } EC_KEY *pub = barray_to_pubkey(env, curve, pubkey); + if (!pub) { + return JNI_FALSE; + } jsize sig_len = (*env)->GetArrayLength(env, signature); jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL); @@ -566,13 +601,17 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); - native_timing_start(); - int result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub); - native_timing_stop(); + int result; + SIG_TRY(TIMEOUT) { + native_timing_start(); + result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); if (result < 0) { - throw_new(env, "java/security/GeneralSecurityException", "Error verifying, ECDSA_do_verify."); + throw_new_var(env, "java/security/GeneralSecurityException", "Error verifying, ECDSA_do_verify (%i).", result); EC_KEY_free(pub); EC_GROUP_free(curve); ECDSA_SIG_free(sig_obj); return JNI_FALSE; } diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c index efaa3b9..23f28ca 100644 --- a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c @@ -1,5 +1,6 @@ #include "c_utils.h" #include "c_timing.h" +#include "c_signals.h" #include "native.h" #include <stdio.h> @@ -191,6 +192,22 @@ static ltc_ecc_set_type* create_curve(JNIEnv *env, jobject params) { jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;"); jobject p = (*env)->CallObjectMethod(env, field, get_p); + jmethodID biginteger_valueof = (*env)->GetStaticMethodID(env, biginteger_class, "valueOf", "(J)Ljava/math/BigInteger;"); + jobject three = (*env)->CallStaticObjectMethod(env, biginteger_class, biginteger_valueof, (jlong) 3); + + jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;"); + jobject a = (*env)->CallObjectMethod(env, elliptic_curve, get_a); + + jmethodID biginteger_add = (*env)->GetMethodID(env, biginteger_class, "add", "(Ljava/math/BigInteger;)Ljava/math/BigInteger;"); + jobject a_3 = (*env)->CallObjectMethod(env, a, biginteger_add, three); + + jmethodID biginteger_equals = (*env)->GetMethodID(env, biginteger_class, "equals", "(Ljava/lang/Object;)Z"); + jboolean eq = (*env)->CallBooleanMethod(env, p, biginteger_equals, a_3); + + if (!eq) { + return NULL; + } + jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;"); jobject g = (*env)->CallObjectMethod(env, params, get_g); @@ -232,9 +249,12 @@ static void free_curve(ltc_ecc_set_type *curve) { static jobject generate_from_curve(JNIEnv *env, const ltc_ecc_set_type *curve) { ecc_key key; - native_timing_start(); - int err = ecc_make_key_ex(<c_prng, find_prng("yarrow"), &key, curve); - native_timing_stop(); + int err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = ecc_make_key_ex(<c_prng, find_prng("yarrow"), &key, curve); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (err != CRYPT_OK) { throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); @@ -381,9 +401,12 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey unsigned char result[curve->size]; unsigned long output_len = curve->size; - native_timing_start(); - int err = ecc_shared_secret(&priv, &pub, result, &output_len); - native_timing_stop(); + int err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = ecc_shared_secret(&priv, &pub, result, &output_len); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (err != CRYPT_OK) { throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); @@ -425,9 +448,12 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig unsigned char result[curve->size*4]; unsigned long output_len = curve->size*4; - native_timing_start(); - int err = ecc_sign_hash((unsigned char *) data_data, data_size, result, &output_len, <c_prng, find_prng("yarrow"), &priv); - native_timing_stop(); + int err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = ecc_sign_hash((unsigned char *) data_data, data_size, result, &output_len, <c_prng, find_prng("yarrow"), &priv); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (err != CRYPT_OK) { throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); @@ -467,9 +493,12 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL); int result; - native_timing_start(); - int err = ecc_verify_hash((unsigned char *) sig_data, sig_size, (unsigned char *) data_data, data_size, &result, &pub); - native_timing_stop(); + int err; + SIG_TRY(TIMEOUT) { + native_timing_start(); + err = ecc_verify_hash((unsigned char *) sig_data, sig_size, (unsigned char *) data_data, data_size, &result, &pub); + native_timing_stop(); + } SIG_CATCH_HANDLE(env); if (err != CRYPT_OK) { throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); diff --git a/standalone/src/test/java/cz/crcs/ectester/standalone/AppTests.java b/standalone/src/test/java/cz/crcs/ectester/standalone/AppTests.java index 7ff2826..1f82bb0 100644 --- a/standalone/src/test/java/cz/crcs/ectester/standalone/AppTests.java +++ b/standalone/src/test/java/cz/crcs/ectester/standalone/AppTests.java @@ -2,7 +2,6 @@ package cz.crcs.ectester.standalone; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Timeout; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.junitpioneer.jupiter.StdIo; @@ -91,9 +90,6 @@ public class AppTests { @MethodSource("libs") @StdIo() public void defaultSuite(String libName, StdOut out) { - // TODO: "Nettle" is very broken here for a weird reason. - assumeFalse(libName.equals("Nettle")); - String[] args = buildCLIArgs(libName, "default"); if (libName.equals("Botan") || libName.equals("Crypto++")) { args = buildCLIArgs(libName, "default", "--kpg-type", "ECDH"); @@ -124,9 +120,6 @@ public class AppTests { @ParameterizedTest @MethodSource("libs") public void performanceSuite(String libName) { - // TODO: "Nettle" is very broken here for a weird reason. - assumeFalse(libName.equals("Nettle")); - String[] args = buildCLIArgs(libName, "performance"); if (libName.equals("Botan") || libName.equals("Crypto++")) { args = buildCLIArgs(libName, "performance", "--kpg-type", "ECDH"); @@ -162,7 +155,6 @@ public class AppTests { @ParameterizedTest @MethodSource("libs") - @Timeout(20) public void miscSuite(String libName) { String[] args = buildCLIArgs(libName, "miscellaneous", "-q"); if (libName.equals("Botan") || libName.equals("Crypto++")) { @@ -173,11 +165,7 @@ public class AppTests { @ParameterizedTest @MethodSource("libs") - @Timeout(20) public void twistSuite(String libName) { - // TODO: "Nettle" is very broken here for a weird reason. - assumeFalse(libName.equals("Nettle")); - String[] args = buildCLIArgs(libName, "twist", "-q"); if (libName.equals("Botan") || libName.equals("Crypto++")) { args = buildCLIArgs(libName, "twist", "--kpg-type", "ECDH", "-q"); @@ -187,11 +175,7 @@ public class AppTests { @ParameterizedTest @MethodSource("libs") - @Timeout(20) public void degenerateSuite(String libName) { - // TODO: "Nettle" is very broken here for a weird reason. - assumeFalse(libName.equals("Nettle")); - String[] args = buildCLIArgs(libName, "degenerate", "-q"); if (libName.equals("Botan") || libName.equals("Crypto++")) { args = buildCLIArgs(libName, "degenerate", "--kpg-type", "ECDH", "-q"); @@ -201,7 +185,6 @@ public class AppTests { @ParameterizedTest @MethodSource("libs") - @Timeout(20) public void edgeCasesSuite(String libName) { // TODO: Crypto++ and tomcrypt is broken here. assumeFalse(libName.equals("Crypto++") || libName.equals("tomcrypt")); @@ -213,9 +196,9 @@ public class AppTests { ECTesterStandalone.main(args); } + /* @ParameterizedTest @MethodSource("libs") - @Timeout(20) // TODO: This breaks the tests because the libs do all sorts of weird stuff here. @Disabled public void compositeSuite(String libName) { @@ -228,10 +211,10 @@ public class AppTests { } ECTesterStandalone.main(args); } + */ @ParameterizedTest @MethodSource("libs") - @Timeout(20) public void cofactorSuite(String libName) { String[] args = buildCLIArgs(libName, "cofactor", "-q"); if (libName.equals("Botan") || libName.equals("Crypto++")) { @@ -240,9 +223,9 @@ public class AppTests { ECTesterStandalone.main(args); } + /* @ParameterizedTest @MethodSource("libs") - @Timeout(20) // TODO: This breaks the tests because the libs do all sorts of weird stuff here. @Disabled public void wrongSuite(String libName) { @@ -255,14 +238,11 @@ public class AppTests { } ECTesterStandalone.main(args); } + */ @ParameterizedTest @MethodSource("libs") - @Timeout(20) public void invalidSuite(String libName) { - // TODO: "Nettle" is very broken here for a weird reason. - assumeFalse(libName.equals("Nettle")); - String[] args = buildCLIArgs(libName, "invalid", "-q"); if (libName.equals("Botan") || libName.equals("Crypto++")) { args = buildCLIArgs(libName, "invalid", "--kpg-type", "ECDH", "-q"); |
