8237218: Support NIST Curves verification in java implementation
Reviewed-by: ascarpino
This commit is contained in:
parent
2596e83a34
commit
533649b8ca
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -34,6 +34,17 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
public final class ECUtil {
|
public final class ECUtil {
|
||||||
|
|
||||||
|
// Used by SunEC
|
||||||
|
public static byte[] sArray(BigInteger s, ECParameterSpec params) {
|
||||||
|
byte[] arr = s.toByteArray();
|
||||||
|
ArrayUtil.reverse(arr);
|
||||||
|
int byteLength = (params.getOrder().bitLength() + 7) / 8;
|
||||||
|
byte[] arrayS = new byte[byteLength];
|
||||||
|
int length = Math.min(byteLength, arr.length);
|
||||||
|
System.arraycopy(arr, 0, arrayS, 0, length);
|
||||||
|
return arrayS;
|
||||||
|
}
|
||||||
|
|
||||||
// Used by SunPKCS11 and SunJSSE.
|
// Used by SunPKCS11 and SunJSSE.
|
||||||
public static ECPoint decodePoint(byte[] data, EllipticCurve curve)
|
public static ECPoint decodePoint(byte[] data, EllipticCurve curve)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -32,6 +32,7 @@ import static sun.security.ec.ECOperations.IntermediateValueException;
|
|||||||
|
|
||||||
import java.security.ProviderException;
|
import java.security.ProviderException;
|
||||||
import java.security.spec.*;
|
import java.security.spec.*;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public class ECDSAOperations {
|
public class ECDSAOperations {
|
||||||
@ -164,10 +165,7 @@ public class ECDSAOperations {
|
|||||||
IntegerModuloP r = R.asAffine().getX();
|
IntegerModuloP r = R.asAffine().getX();
|
||||||
// put r into the correct field by fully reducing to an array
|
// put r into the correct field by fully reducing to an array
|
||||||
byte[] temp = new byte[length];
|
byte[] temp = new byte[length];
|
||||||
r.asByteArray(temp);
|
r = b2a(r, orderField, temp);
|
||||||
r = orderField.getElement(temp);
|
|
||||||
// store r in result
|
|
||||||
r.asByteArray(temp);
|
|
||||||
byte[] result = new byte[2 * length];
|
byte[] result = new byte[2 * length];
|
||||||
ArrayUtil.reverse(temp);
|
ArrayUtil.reverse(temp);
|
||||||
System.arraycopy(temp, 0, result, 0, length);
|
System.arraycopy(temp, 0, result, 0, length);
|
||||||
@ -198,5 +196,68 @@ public class ECDSAOperations {
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
public boolean verifySignedDigest(byte[] digest, byte[] sig, ECPoint pp) {
|
||||||
|
|
||||||
|
IntegerFieldModuloP field = ecOps.getField();
|
||||||
|
IntegerFieldModuloP orderField = ecOps.getOrderField();
|
||||||
|
int length = (orderField.getSize().bitLength() + 7) / 8;
|
||||||
|
|
||||||
|
byte[] r;
|
||||||
|
byte[] s;
|
||||||
|
|
||||||
|
int encodeLength = sig.length / 2;
|
||||||
|
if (sig.length %2 != 0 || encodeLength > length) {
|
||||||
|
return false;
|
||||||
|
} else if (encodeLength == length) {
|
||||||
|
r = Arrays.copyOf(sig, length);
|
||||||
|
s = Arrays.copyOfRange(sig, length, length * 2);
|
||||||
|
} else {
|
||||||
|
r = new byte[length];
|
||||||
|
s = new byte[length];
|
||||||
|
System.arraycopy(sig, 0, r, length - encodeLength, encodeLength);
|
||||||
|
System.arraycopy(sig, encodeLength, s, length - encodeLength, encodeLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayUtil.reverse(r);
|
||||||
|
ArrayUtil.reverse(s);
|
||||||
|
IntegerModuloP ri = orderField.getElement(r);
|
||||||
|
IntegerModuloP si = orderField.getElement(s);
|
||||||
|
// z
|
||||||
|
int lengthE = Math.min(length, digest.length);
|
||||||
|
byte[] E = new byte[lengthE];
|
||||||
|
System.arraycopy(digest, 0, E, 0, lengthE);
|
||||||
|
ArrayUtil.reverse(E);
|
||||||
|
IntegerModuloP e = orderField.getElement(E);
|
||||||
|
|
||||||
|
IntegerModuloP sInv = si.multiplicativeInverse();
|
||||||
|
ImmutableIntegerModuloP u1 = e.multiply(sInv);
|
||||||
|
ImmutableIntegerModuloP u2 = ri.multiply(sInv);
|
||||||
|
|
||||||
|
AffinePoint pub = new AffinePoint(field.getElement(pp.getAffineX()),
|
||||||
|
field.getElement(pp.getAffineY()));
|
||||||
|
|
||||||
|
byte[] temp1 = new byte[length];
|
||||||
|
b2a(u1, orderField, temp1);
|
||||||
|
|
||||||
|
byte[] temp2 = new byte[length];
|
||||||
|
b2a(u2, orderField, temp2);
|
||||||
|
|
||||||
|
MutablePoint p1 = ecOps.multiply(basePoint, temp1);
|
||||||
|
MutablePoint p2 = ecOps.multiply(pub, temp2);
|
||||||
|
|
||||||
|
ecOps.setSum(p1, p2.asAffine());
|
||||||
|
IntegerModuloP result = p1.asAffine().getX();
|
||||||
|
result = result.additiveInverse().add(ri);
|
||||||
|
|
||||||
|
b2a(result, orderField, temp1);
|
||||||
|
return ECOperations.allZero(temp1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public ImmutableIntegerModuloP b2a(IntegerModuloP b,
|
||||||
|
IntegerFieldModuloP orderField, byte[] temp1) {
|
||||||
|
b.asByteArray(temp1);
|
||||||
|
ImmutableIntegerModuloP b2 = orderField.getElement(temp1);
|
||||||
|
b2.asByteArray(temp1);
|
||||||
|
return b2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -374,13 +374,14 @@ abstract class ECDSASignature extends SignatureSpi {
|
|||||||
return ECUtil.equals(sigParams, keyParams);
|
return ECUtil.equals(sigParams, keyParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private byte[] signDigestImpl(ECDSAOperations ops, int seedBits,
|
private byte[] signDigestImpl(ECDSAOperations ops, int seedBits,
|
||||||
byte[] digest, ECPrivateKeyImpl privImpl, SecureRandom random)
|
byte[] digest, ECPrivateKey priv, SecureRandom random)
|
||||||
throws SignatureException {
|
throws SignatureException {
|
||||||
|
|
||||||
byte[] seedBytes = new byte[(seedBits + 7) / 8];
|
byte[] seedBytes = new byte[(seedBits + 7) / 8];
|
||||||
byte[] s = privImpl.getArrayS();
|
byte[] s = priv instanceof ECPrivateKeyImpl
|
||||||
|
? ((ECPrivateKeyImpl)priv).getArrayS()
|
||||||
|
: ECUtil.sArray(priv.getS(), priv.getParams());
|
||||||
|
|
||||||
// Attempt to create the signature in a loop that uses new random input
|
// Attempt to create the signature in a loop that uses new random input
|
||||||
// each time. The chance of failure is very small assuming the
|
// each time. The chance of failure is very small assuming the
|
||||||
@ -401,13 +402,9 @@ abstract class ECDSASignature extends SignatureSpi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Optional<byte[]> signDigestImpl(ECPrivateKey privateKey,
|
private Optional<byte[]> signDigestAvailable(ECPrivateKey privateKey,
|
||||||
byte[] digest, SecureRandom random) throws SignatureException {
|
byte[] digest, SecureRandom random) throws SignatureException {
|
||||||
|
|
||||||
if (! (privateKey instanceof ECPrivateKeyImpl)) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
ECPrivateKeyImpl privImpl = (ECPrivateKeyImpl) privateKey;
|
|
||||||
ECParameterSpec params = privateKey.getParams();
|
ECParameterSpec params = privateKey.getParams();
|
||||||
|
|
||||||
// seed is the key size + 64 bits
|
// seed is the key size + 64 bits
|
||||||
@ -418,7 +415,7 @@ abstract class ECDSASignature extends SignatureSpi {
|
|||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
} else {
|
} else {
|
||||||
byte[] sig = signDigestImpl(opsOpt.get(), seedBits, digest,
|
byte[] sig = signDigestImpl(opsOpt.get(), seedBits, digest,
|
||||||
privImpl, random);
|
privateKey, random);
|
||||||
return Optional.of(sig);
|
return Optional.of(sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -461,7 +458,7 @@ abstract class ECDSASignature extends SignatureSpi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
byte[] digest = getDigestValue();
|
byte[] digest = getDigestValue();
|
||||||
Optional<byte[]> sigOpt = signDigestImpl(privateKey, digest, random);
|
Optional<byte[]> sigOpt = signDigestAvailable(privateKey, digest, random);
|
||||||
byte[] sig;
|
byte[] sig;
|
||||||
if (sigOpt.isPresent()) {
|
if (sigOpt.isPresent()) {
|
||||||
sig = sigOpt.get();
|
sig = sigOpt.get();
|
||||||
@ -480,17 +477,6 @@ abstract class ECDSASignature extends SignatureSpi {
|
|||||||
@Override
|
@Override
|
||||||
protected boolean engineVerify(byte[] signature) throws SignatureException {
|
protected boolean engineVerify(byte[] signature) throws SignatureException {
|
||||||
|
|
||||||
byte[] w;
|
|
||||||
ECParameterSpec params = publicKey.getParams();
|
|
||||||
// DER OID
|
|
||||||
byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params);
|
|
||||||
|
|
||||||
if (publicKey instanceof ECPublicKeyImpl) {
|
|
||||||
w = ((ECPublicKeyImpl) publicKey).getEncodedPublicValue();
|
|
||||||
} else { // instanceof ECPublicKey
|
|
||||||
w = ECUtil.encodePoint(publicKey.getW(), params.getCurve());
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] sig;
|
byte[] sig;
|
||||||
if (p1363Format) {
|
if (p1363Format) {
|
||||||
sig = signature;
|
sig = signature;
|
||||||
@ -498,13 +484,53 @@ abstract class ECDSASignature extends SignatureSpi {
|
|||||||
sig = ECUtil.decodeSignature(signature);
|
sig = ECUtil.decodeSignature(signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
byte[] digest = getDigestValue();
|
||||||
return verifySignedDigest(sig, getDigestValue(), w, encodedParams);
|
Optional<Boolean> verifyOpt
|
||||||
} catch (GeneralSecurityException e) {
|
= verifySignedDigestAvailable(publicKey, sig, digest);
|
||||||
throw new SignatureException("Could not verify signature", e);
|
|
||||||
|
if (verifyOpt.isPresent()) {
|
||||||
|
return verifyOpt.get();
|
||||||
|
} else {
|
||||||
|
byte[] w;
|
||||||
|
ECParameterSpec params = publicKey.getParams();
|
||||||
|
// DER OID
|
||||||
|
byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params);
|
||||||
|
|
||||||
|
if (publicKey instanceof ECPublicKeyImpl) {
|
||||||
|
w = ((ECPublicKeyImpl) publicKey).getEncodedPublicValue();
|
||||||
|
} else { // instanceof ECPublicKey
|
||||||
|
w = ECUtil.encodePoint(publicKey.getW(), params.getCurve());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return verifySignedDigest(sig, digest, w, encodedParams);
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
throw new SignatureException("Could not verify signature", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Optional<Boolean> verifySignedDigestAvailable(
|
||||||
|
ECPublicKey publicKey, byte[] sig, byte[] digestValue) {
|
||||||
|
|
||||||
|
ECParameterSpec params = publicKey.getParams();
|
||||||
|
|
||||||
|
Optional<ECDSAOperations> opsOpt =
|
||||||
|
ECDSAOperations.forParameters(params);
|
||||||
|
if (opsOpt.isEmpty()) {
|
||||||
|
return Optional.empty();
|
||||||
|
} else {
|
||||||
|
boolean result = verifySignedDigestImpl(opsOpt.get(), digestValue,
|
||||||
|
publicKey, sig);
|
||||||
|
return Optional.of(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean verifySignedDigestImpl(ECDSAOperations ops,
|
||||||
|
byte[] digest, ECPublicKey pub, byte[] sig) {
|
||||||
|
return ops.verifySignedDigest(digest, sig, pub.getW());
|
||||||
|
}
|
||||||
|
|
||||||
// set parameter, not supported. See JCA doc
|
// set parameter, not supported. See JCA doc
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -153,12 +153,7 @@ public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey {
|
|||||||
|
|
||||||
public byte[] getArrayS() {
|
public byte[] getArrayS() {
|
||||||
if (arrayS == null) {
|
if (arrayS == null) {
|
||||||
byte[] arr = getS().toByteArray();
|
arrayS = ECUtil.sArray(getS(), params);
|
||||||
ArrayUtil.reverse(arr);
|
|
||||||
int byteLength = (params.getOrder().bitLength() + 7) / 8;
|
|
||||||
arrayS = new byte[byteLength];
|
|
||||||
int length = Math.min(byteLength, arr.length);
|
|
||||||
System.arraycopy(arr, 0, arrayS, 0, length);
|
|
||||||
}
|
}
|
||||||
return arrayS.clone();
|
return arrayS.clone();
|
||||||
}
|
}
|
||||||
|
246
test/jdk/sun/security/ec/ECDSAJavaVerify.java
Normal file
246
test/jdk/sun/security/ec/ECDSAJavaVerify.java
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.sun.jdi.Bootstrap;
|
||||||
|
import com.sun.jdi.VMDisconnectedException;
|
||||||
|
import com.sun.jdi.VirtualMachine;
|
||||||
|
import com.sun.jdi.connect.Connector;
|
||||||
|
import com.sun.jdi.connect.LaunchingConnector;
|
||||||
|
import com.sun.jdi.event.Event;
|
||||||
|
import com.sun.jdi.event.EventSet;
|
||||||
|
import com.sun.jdi.event.MethodEntryEvent;
|
||||||
|
import com.sun.jdi.request.MethodEntryRequest;
|
||||||
|
|
||||||
|
import java.security.AlgorithmParameters;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.Signature;
|
||||||
|
import java.security.SignatureException;
|
||||||
|
import java.security.interfaces.ECPrivateKey;
|
||||||
|
import java.security.interfaces.ECPublicKey;
|
||||||
|
import java.security.spec.ECGenParameterSpec;
|
||||||
|
import java.security.spec.ECParameterSpec;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8237218
|
||||||
|
* @summary Support NIST Curves verification in java implementation
|
||||||
|
* @modules jdk.crypto.ec
|
||||||
|
* jdk.jdi
|
||||||
|
* @run main ECDSAJavaVerify debug
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ATTENTION: This test depends on method names inside the non-exported
|
||||||
|
// class sun.security.ec.ECDSASignature.
|
||||||
|
public class ECDSAJavaVerify {
|
||||||
|
|
||||||
|
static final String[] ALL_ALGS = new String[] {
|
||||||
|
"SHA1withECDSA", "SHA256withECDSA", "SHA384withECDSA", "SHA512withECDSA"};
|
||||||
|
|
||||||
|
static final String[] ALL_CURVES = new String[] {
|
||||||
|
"secp128r1", "secp256k1", "secp256r1", "secp384r1", "secp521r1"};
|
||||||
|
|
||||||
|
static final List<String> ALL_JAVA_CURVES
|
||||||
|
= List.of("secp256r1", "secp384r1", "secp521r1");
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
if (args.length == 1) {
|
||||||
|
// Debugging a new process with no arg
|
||||||
|
debug();
|
||||||
|
} else if (args.length == 3) {
|
||||||
|
// If one test case fail, re-run it with first 3 columns
|
||||||
|
new Test().run(Integer.parseInt(args[0]), args[1], args[2]);
|
||||||
|
} else {
|
||||||
|
// Run all test cases
|
||||||
|
Test t = new Test();
|
||||||
|
Random r = new Random();
|
||||||
|
|
||||||
|
for (String sigAlg : ALL_ALGS) {
|
||||||
|
for (String curve : ALL_CURVES) {
|
||||||
|
t.run(r.nextInt(1000000), sigAlg, curve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void debug() throws Exception {
|
||||||
|
|
||||||
|
LaunchingConnector launchingConnector = Bootstrap
|
||||||
|
.virtualMachineManager().defaultConnector();
|
||||||
|
|
||||||
|
Map<String, Connector.Argument> arguments
|
||||||
|
= launchingConnector.defaultArguments();
|
||||||
|
arguments.get("main").setValue(ECDSAJavaVerify.class.getName());
|
||||||
|
arguments.get("options").setValue(
|
||||||
|
"-cp " + System.getProperty("test.classes"));
|
||||||
|
VirtualMachine vm = launchingConnector.launch(arguments);
|
||||||
|
|
||||||
|
MethodEntryRequest req = vm.eventRequestManager()
|
||||||
|
.createMethodEntryRequest();
|
||||||
|
req.addClassFilter("sun.security.ec.ECDSASignature");
|
||||||
|
req.enable();
|
||||||
|
|
||||||
|
int numberOfTests = ALL_ALGS.length * ALL_CURVES.length * 2;
|
||||||
|
|
||||||
|
// Expected methods to call. 'J' for java impl, 'N' for native impl
|
||||||
|
char[] expected = new char[numberOfTests];
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
for (String dummy : ALL_ALGS) {
|
||||||
|
for (String curve : ALL_CURVES) {
|
||||||
|
char caller = ALL_JAVA_CURVES.contains(curve) ? 'J' : 'N';
|
||||||
|
// For each case, Signature::verify is called twice
|
||||||
|
expected[pos++] = caller;
|
||||||
|
expected[pos++] = caller;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test result, init as ' ', '-' if run, 'x' for unexpected.
|
||||||
|
char[] result = new char[numberOfTests];
|
||||||
|
Arrays.fill(result, ' ');
|
||||||
|
|
||||||
|
String stdout, stderr;
|
||||||
|
|
||||||
|
try {
|
||||||
|
EventSet eventSet;
|
||||||
|
pos = -1; // will become 0 when entering 'engineVerify'
|
||||||
|
while ((eventSet = vm.eventQueue().remove()) != null) {
|
||||||
|
for (Event event : eventSet) {
|
||||||
|
if (event instanceof MethodEntryEvent) {
|
||||||
|
MethodEntryEvent e = (MethodEntryEvent)event;
|
||||||
|
switch (e.method().name()) {
|
||||||
|
case "engineVerify":
|
||||||
|
pos++;
|
||||||
|
result[pos] = '-';
|
||||||
|
break;
|
||||||
|
case "verifySignedDigestImpl": // the java impl
|
||||||
|
if (expected[pos] != 'J') {
|
||||||
|
result[pos] = 'x';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "verifySignedDigest":
|
||||||
|
if (expected[pos] != 'N') { // the native impl
|
||||||
|
result[pos] = 'x';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vm.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (VMDisconnectedException e) {
|
||||||
|
System.out.println("Virtual Machine is disconnected.");
|
||||||
|
} finally {
|
||||||
|
stderr = new String(vm.process().getErrorStream().readAllBytes());
|
||||||
|
stdout = new String(vm.process().getInputStream().readAllBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("stderr:\n" + stderr);
|
||||||
|
System.out.println("stdout:\n" + stdout);
|
||||||
|
|
||||||
|
String sResult = new String(result);
|
||||||
|
|
||||||
|
System.out.println("Expected: " + new String(expected));
|
||||||
|
System.out.println(" Actual: " + sResult);
|
||||||
|
|
||||||
|
if (pos != numberOfTests - 1 || sResult.contains("x")) {
|
||||||
|
throw new Exception("Unexpected result");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stdout.contains("fail") || !stderr.isEmpty()) {
|
||||||
|
throw new Exception("Test failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Test {
|
||||||
|
|
||||||
|
public boolean run(int seed, String sigAlg, String curve)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
// A determined SecureRandom based on seed. If there is anything
|
||||||
|
// wrong, we can reproduce the problem using the seed.
|
||||||
|
Random r = new Random(seed);
|
||||||
|
SecureRandom rand = new SecureRandom() {
|
||||||
|
@Override
|
||||||
|
public void nextBytes(byte[] bytes) {
|
||||||
|
r.nextBytes(bytes);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AlgorithmParameters ap = AlgorithmParameters.getInstance("EC", "SunEC");
|
||||||
|
ap.init(new ECGenParameterSpec(curve));
|
||||||
|
ECParameterSpec spec = ap.getParameterSpec(ECParameterSpec.class);
|
||||||
|
|
||||||
|
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "SunEC");
|
||||||
|
kpg.initialize(spec, rand);
|
||||||
|
KeyPair kp = kpg.generateKeyPair();
|
||||||
|
ECPrivateKey ecPrivateKey = (ECPrivateKey) kp.getPrivate();
|
||||||
|
ECPublicKey ecPublicKey = (ECPublicKey) kp.getPublic();
|
||||||
|
|
||||||
|
Signature s1 = Signature.getInstance(sigAlg, "SunEC");
|
||||||
|
s1.initSign(ecPrivateKey, rand);
|
||||||
|
byte[] msg = new byte[1234];
|
||||||
|
rand.nextBytes(msg);
|
||||||
|
s1.update(msg);
|
||||||
|
byte[] sig = s1.sign();
|
||||||
|
|
||||||
|
Signature s2 = Signature.getInstance(sigAlg, "SunEC");
|
||||||
|
s2.initVerify(ecPublicKey);
|
||||||
|
s2.update(msg);
|
||||||
|
|
||||||
|
boolean result1 = s2.verify(sig);
|
||||||
|
|
||||||
|
s2.initVerify(ecPublicKey);
|
||||||
|
// modify the signature in some random manner
|
||||||
|
if (rand.nextInt(10) < 8) {
|
||||||
|
sig[rand.nextInt(10000) % sig.length]
|
||||||
|
= (byte) rand.nextInt(10000);
|
||||||
|
} else {
|
||||||
|
int newLength = rand.nextInt(100);
|
||||||
|
if (newLength == sig.length) {
|
||||||
|
newLength += 1 + rand.nextInt(2);
|
||||||
|
}
|
||||||
|
sig = Arrays.copyOf(sig, newLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean result2;
|
||||||
|
try {
|
||||||
|
result2 = s2.verify(sig);
|
||||||
|
} catch (SignatureException se) {
|
||||||
|
result2 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean finalResult = result1 && !result2;
|
||||||
|
System.out.printf("%10d %20s %20s -- %5s %5s -- %s\n",
|
||||||
|
seed, sigAlg, curve, result1, result2,
|
||||||
|
finalResult ? "succeed" : "fail");
|
||||||
|
|
||||||
|
return finalResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user