--- old/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java 2019-05-28 09:11:52.418419000 +0200 +++ new/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java 2019-05-28 09:11:51.485762100 +0200 @@ -32,9 +32,11 @@ import java.security.*; import java.security.interfaces.*; import java.security.spec.*; +import java.util.Optional; import sun.security.jca.JCAUtil; import sun.security.util.*; +import static sun.security.ec.ECOperations.IntermediateValueException; /** * ECDSA signature implementation. This class currently supports the @@ -147,7 +149,7 @@ // Stores the precomputed message digest value. @Override protected void engineUpdate(byte[] b, int off, int len) - throws SignatureException { + throws SignatureException { if (offset >= precomputedDigest.length) { offset = RAW_ECDSA_MAX + 1; return; @@ -172,7 +174,7 @@ } @Override - protected void resetDigest(){ + protected void resetDigest() { offset = 0; } @@ -222,14 +224,14 @@ // Nested class for SHA224withECDSA signatures public static final class SHA224 extends ECDSASignature { public SHA224() { - super("SHA-224"); + super("SHA-224"); } } // Nested class for SHA224withECDSAinP1363Format signatures public static final class SHA224inP1363Format extends ECDSASignature { public SHA224inP1363Format() { - super("SHA-224", true); + super("SHA-224", true); } } @@ -278,7 +280,7 @@ // initialize for verification. See JCA doc @Override protected void engineInitVerify(PublicKey publicKey) - throws InvalidKeyException { + throws InvalidKeyException { this.publicKey = (ECPublicKey) ECKeyFactory.toECKey(publicKey); // Should check that the supplied key is appropriate for signature @@ -290,14 +292,14 @@ // initialize for signing. See JCA doc @Override protected void engineInitSign(PrivateKey privateKey) - throws InvalidKeyException { + throws InvalidKeyException { engineInitSign(privateKey, null); } // initialize for signing. See JCA doc @Override protected void engineInitSign(PrivateKey privateKey, SecureRandom random) - throws InvalidKeyException { + throws InvalidKeyException { this.privateKey = (ECPrivateKey) ECKeyFactory.toECKey(privateKey); // Should check that the supplied key is appropriate for signature @@ -337,7 +339,7 @@ // update the signature with the plaintext data. See JCA doc @Override protected void engineUpdate(byte[] b, int off, int len) - throws SignatureException { + throws SignatureException { messageDigest.update(b, off, len); needsReset = true; } @@ -354,20 +356,67 @@ needsReset = true; } - // sign the data and return the signature. See JCA doc - @Override - protected byte[] engineSign() throws SignatureException { + private byte[] signDigestImpl(ECDSAOperations ops, int seedBits, + byte[] digest, ECPrivateKeyImpl privImpl, SecureRandom random) + throws SignatureException { + + byte[] seedBytes = new byte[(seedBits + 7) / 8]; + byte[] s = privImpl.getArrayS(); + + // Attempt to create the signature in a loop that uses new random input + // each time. The chance of failure is very small assuming the + // implementation derives the nonce using extra bits + int numAttempts = 128; + for (int i = 0; i < numAttempts; i++) { + random.nextBytes(seedBytes); + ECDSAOperations.Seed seed = new ECDSAOperations.Seed(seedBytes); + try { + return ops.signDigest(s, digest, seed); + } catch (IntermediateValueException ex) { + // try again in the next iteration + } + } + + throw new SignatureException("Unable to produce signature after " + + numAttempts + " attempts"); + } + + + private Optional signDigestImpl(ECPrivateKey privateKey, + byte[] digest, SecureRandom random) throws SignatureException { + + if (! (privateKey instanceof ECPrivateKeyImpl)) { + return Optional.empty(); + } + ECPrivateKeyImpl privImpl = (ECPrivateKeyImpl) privateKey; + ECParameterSpec params = privateKey.getParams(); + + // seed is the key size + 64 bits + int seedBits = params.getOrder().bitLength() + 64; + Optional opsOpt = + ECDSAOperations.forParameters(params); + if (opsOpt.isEmpty()) { + return Optional.empty(); + } else { + byte[] sig = signDigestImpl(opsOpt.get(), seedBits, digest, + privImpl, random); + return Optional.of(sig); + } + } + + private byte[] signDigestNative(ECPrivateKey privateKey, byte[] digest, + SecureRandom random) throws SignatureException { + byte[] s = privateKey.getS().toByteArray(); ECParameterSpec params = privateKey.getParams(); + // DER OID byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params); int keySize = params.getCurve().getField().getFieldSize(); // seed is twice the key size (in bytes) plus 1 byte[] seed = new byte[(((keySize + 7) >> 3) + 1) * 2]; - if (random == null) { - random = JCAUtil.getSecureRandom(); - } + random.nextBytes(seed); // random bits needed for timing countermeasures @@ -375,14 +424,32 @@ // values must be non-zero to enable countermeasures timingArgument |= 1; - byte[] sig; try { - sig = signDigest(getDigestValue(), s, encodedParams, seed, + return signDigest(digest, s, encodedParams, seed, timingArgument); } catch (GeneralSecurityException e) { throw new SignatureException("Could not sign data", e); } + } + + // sign the data and return the signature. See JCA doc + @Override + protected byte[] engineSign() throws SignatureException { + + if (random == null) { + random = JCAUtil.getSecureRandom(); + } + + byte[] digest = getDigestValue(); + Optional sigOpt = signDigestImpl(privateKey, digest, random); + byte[] sig; + if (sigOpt.isPresent()) { + sig = sigOpt.get(); + } else { + sig = signDigestNative(privateKey, digest, random); + } + if (p1363Format) { return sig; } else { @@ -400,7 +467,7 @@ byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params); if (publicKey instanceof ECPublicKeyImpl) { - w = ((ECPublicKeyImpl)publicKey).getEncodedPublicValue(); + w = ((ECPublicKeyImpl) publicKey).getEncodedPublicValue(); } else { // instanceof ECPublicKey w = ECUtil.encodePoint(publicKey.getW(), params.getCurve()); } @@ -423,13 +490,13 @@ @Override @Deprecated protected void engineSetParameter(String param, Object value) - throws InvalidParameterException { + throws InvalidParameterException { throw new UnsupportedOperationException("setParameter() not supported"); } @Override protected void engineSetParameter(AlgorithmParameterSpec params) - throws InvalidAlgorithmParameterException { + throws InvalidAlgorithmParameterException { if (params != null) { throw new InvalidAlgorithmParameterException("No parameter accepted"); } @@ -439,7 +506,7 @@ @Override @Deprecated protected Object engineGetParameter(String param) - throws InvalidParameterException { + throws InvalidParameterException { throw new UnsupportedOperationException("getParameter() not supported"); } @@ -464,7 +531,7 @@ out.putInteger(r); out.putInteger(s); DerValue result = - new DerValue(DerValue.tag_Sequence, out.toByteArray()); + new DerValue(DerValue.tag_Sequence, out.toByteArray()); return result.toByteArray(); @@ -497,9 +564,9 @@ // r and s each occupy half the array byte[] result = new byte[k << 1]; System.arraycopy(rBytes, 0, result, k - rBytes.length, - rBytes.length); + rBytes.length); System.arraycopy(sBytes, 0, result, result.length - sBytes.length, - sBytes.length); + sBytes.length); return result; } catch (Exception e) { @@ -539,13 +606,13 @@ * @return byte[] the signature. */ private static native byte[] signDigest(byte[] digest, byte[] s, - byte[] encodedParams, byte[] seed, int timing) - throws GeneralSecurityException; + byte[] encodedParams, byte[] seed, int timing) + throws GeneralSecurityException; /** * Verifies the signed digest using the public key. * - * @param signedDigest the signature to be verified. It is encoded + * @param signature the signature to be verified. It is encoded * as a concatenation of the key's R and S values. * @param digest the digest to be used. * @param w the public key's W point (in uncompressed form). @@ -554,6 +621,6 @@ * @return boolean true if the signature is successfully verified. */ private static native boolean verifySignedDigest(byte[] signature, - byte[] digest, byte[] w, byte[] encodedParams) - throws GeneralSecurityException; + byte[] digest, byte[] w, byte[] encodedParams) + throws GeneralSecurityException; }