mirror of
https://github.com/openjdk/jdk15u.git
synced 2025-12-11 04:22:00 -06:00
8288508: Enhance ECDSA usage
Reviewed-by: abakhtin, bae Backport-of: efd603063e60ca6861b41309445d7b8e20768d9b
This commit is contained in:
parent
4b2dd7650b
commit
49f3d639ad
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 2022, 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
|
||||
@ -305,5 +305,44 @@ public final class ECUtil {
|
||||
}
|
||||
}
|
||||
|
||||
// Partial Public key validation as described in NIST SP 800-186 Appendix D.1.1.1.
|
||||
// The extra step in the full validation (described in Appendix D.1.1.2) is implemented
|
||||
// as sun.security.ec.ECOperations#checkOrder inside the jdk.crypto.ec module.
|
||||
public static void validatePublicKey(ECPoint point, ECParameterSpec spec)
|
||||
throws InvalidKeyException {
|
||||
BigInteger p;
|
||||
if (spec.getCurve().getField() instanceof ECFieldFp) {
|
||||
ECFieldFp f = (ECFieldFp) spec.getCurve().getField();
|
||||
p = f.getP();
|
||||
} else if (spec.getCurve().getField() instanceof ECFieldF2m) {
|
||||
// curves over binary fields are validated in SunEC code
|
||||
return;
|
||||
} else {
|
||||
throw new InvalidKeyException("Curve field is not supported");
|
||||
}
|
||||
|
||||
// 1. If Q is the point at infinity, output REJECT
|
||||
if (point.equals(ECPoint.POINT_INFINITY)) {
|
||||
throw new InvalidKeyException("Public point is at infinity");
|
||||
}
|
||||
// 2. Verify that x and y are integers in the interval [0, p-1]. Output REJECT if verification fails.
|
||||
BigInteger x = point.getAffineX();
|
||||
if (x.signum() < 0 || x.compareTo(p) >= 0) {
|
||||
throw new InvalidKeyException("Public point x is not in the interval [0, p-1]");
|
||||
}
|
||||
BigInteger y = point.getAffineY();
|
||||
if (y.signum() < 0 || y.compareTo(p) >= 0) {
|
||||
throw new InvalidKeyException("Public point y is not in the interval [0, p-1]");
|
||||
}
|
||||
// 3. Verify that (x, y) is a point on the W_a,b by checking that (x, y) satisfies the defining
|
||||
// equation y^2 = x^3 + a x + b where computations are carried out in GF(p). Output REJECT
|
||||
// if verification fails.
|
||||
BigInteger left = y.modPow(BigInteger.TWO, p);
|
||||
BigInteger right = x.pow(3).add(spec.getCurve().getA().multiply(x)).add(spec.getCurve().getB()).mod(p);
|
||||
if (!left.equals(right)) {
|
||||
throw new InvalidKeyException("Public point is not on the curve");
|
||||
}
|
||||
}
|
||||
|
||||
private ECUtil() {}
|
||||
}
|
||||
|
||||
@ -485,6 +485,9 @@ abstract class ECDSASignature extends SignatureSpi {
|
||||
@Override
|
||||
protected boolean engineVerify(byte[] signature) throws SignatureException {
|
||||
|
||||
ECPoint w = publicKey.getW();
|
||||
ECParameterSpec params = publicKey.getParams();
|
||||
|
||||
byte[] sig;
|
||||
if (p1363Format) {
|
||||
sig = signature;
|
||||
@ -493,11 +496,25 @@ abstract class ECDSASignature extends SignatureSpi {
|
||||
}
|
||||
|
||||
byte[] digest = getDigestValue();
|
||||
Optional<Boolean> verifyOpt
|
||||
= verifySignedDigestAvailable(publicKey, sig, digest);
|
||||
|
||||
if (verifyOpt.isPresent()) {
|
||||
return verifyOpt.get();
|
||||
Optional<ECDSAOperations> ops = ECDSAOperations.forParameters(params);
|
||||
|
||||
if (ops.isPresent()) {
|
||||
|
||||
// Partial public key validation
|
||||
try {
|
||||
ECUtil.validatePublicKey(w, params);
|
||||
} catch (InvalidKeyException e) {
|
||||
return false;
|
||||
}
|
||||
// Full public key validation, only necessary when h != 1.
|
||||
if (params.getCofactor() != 1) {
|
||||
if (!ops.get().getEcOperations().checkOrder(w)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return verifySignedDigestImpl(ops.get(), digest, publicKey, sig);
|
||||
|
||||
} else {
|
||||
if (SunEC.isNativeDisabled()) {
|
||||
NamedCurve nc = CurveDB.lookup(publicKey.getParams());
|
||||
@ -508,41 +525,24 @@ abstract class ECDSASignature extends SignatureSpi {
|
||||
: "unknown")));
|
||||
}
|
||||
|
||||
byte[] w;
|
||||
ECParameterSpec params = publicKey.getParams();
|
||||
// DER OID
|
||||
byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params);
|
||||
|
||||
byte[] encodedW;
|
||||
if (publicKey instanceof ECPublicKeyImpl) {
|
||||
w = ((ECPublicKeyImpl) publicKey).getEncodedPublicValue();
|
||||
encodedW = ((ECPublicKeyImpl) publicKey).getEncodedPublicValue();
|
||||
} else { // instanceof ECPublicKey
|
||||
w = ECUtil.encodePoint(publicKey.getW(), params.getCurve());
|
||||
encodedW = ECUtil.encodePoint(w, params.getCurve());
|
||||
}
|
||||
|
||||
try {
|
||||
return verifySignedDigest(sig, digest, w, encodedParams);
|
||||
return verifySignedDigest(sig, digest, encodedW, 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());
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
package sun.security.ec;
|
||||
|
||||
import sun.security.ec.point.*;
|
||||
import sun.security.util.ArrayUtil;
|
||||
import sun.security.util.math.*;
|
||||
import sun.security.util.math.intpoly.*;
|
||||
|
||||
@ -33,6 +34,7 @@ import java.math.BigInteger;
|
||||
import java.security.ProviderException;
|
||||
import java.security.spec.ECFieldFp;
|
||||
import java.security.spec.ECParameterSpec;
|
||||
import java.security.spec.ECPoint;
|
||||
import java.security.spec.EllipticCurve;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@ -489,5 +491,19 @@ public class ECOperations {
|
||||
p.getZ().setSum(t1);
|
||||
|
||||
}
|
||||
|
||||
// The extra step in the Full Public key validation as described in
|
||||
// NIST SP 800-186 Appendix D.1.1.2
|
||||
public boolean checkOrder(ECPoint point) {
|
||||
BigInteger x = point.getAffineX();
|
||||
BigInteger y = point.getAffineY();
|
||||
|
||||
// Verify that n Q = INFINITY. Output REJECT if verification fails.
|
||||
IntegerFieldModuloP field = this.getField();
|
||||
AffinePoint ap = new AffinePoint(field.getElement(x), field.getElement(y));
|
||||
byte[] scalar = this.orderField.getSize().toByteArray();
|
||||
ArrayUtil.reverse(scalar);
|
||||
return isNeutral(this.multiply(ap, scalar));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
@ -925,6 +925,12 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
|
||||
}
|
||||
|
||||
ecParams = &(key->ecParams);
|
||||
|
||||
if (EC_ValidatePublicKey(ecParams, &key->publicValue, kmflag) != SECSuccess) {
|
||||
PORT_SetError(SEC_ERROR_BAD_KEY);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
flen = (ecParams->fieldID.size + 7) >> 3;
|
||||
olen = ecParams->order.len;
|
||||
if (signature->len == 0 || signature->len%2 != 0 ||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user