8225745: NoSuchAlgorithmException exception for SHA256withECDSA with RSASSA-PSS support
Summary: Fixed SignatureUtil and ECDSA signature impl to handle EC parameters
Reviewed-by: weijun
--- a/src/java.base/share/classes/sun/security/util/CurveDB.java Thu Jul 11 12:13:52 2019 -0700
+++ b/src/java.base/share/classes/sun/security/util/CurveDB.java Thu Jul 11 20:11:47 2019 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2019, 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
@@ -104,21 +104,10 @@
if (namedCurve.getCurve().getField().getFieldSize() != fieldSize) {
continue;
}
- if (namedCurve.getCurve().equals(params.getCurve()) == false) {
- continue;
- }
- if (namedCurve.getGenerator().equals(params.getGenerator()) ==
- false) {
- continue;
+ if (ECUtil.equals(namedCurve, params)) {
+ // everything matches our named curve, return it
+ return namedCurve;
}
- if (namedCurve.getOrder().equals(params.getOrder()) == false) {
- continue;
- }
- if (namedCurve.getCofactor() != params.getCofactor()) {
- continue;
- }
- // everything matches our named curve, return it
- return namedCurve;
}
// no match found
return null;
--- a/src/java.base/share/classes/sun/security/util/ECUtil.java Thu Jul 11 12:13:52 2019 -0700
+++ b/src/java.base/share/classes/sun/security/util/ECUtil.java Thu Jul 11 20:11:47 2019 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2019, 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
@@ -32,7 +32,7 @@
import java.security.spec.*;
import java.util.Arrays;
-public class ECUtil {
+public final class ECUtil {
// Used by SunPKCS11 and SunJSSE.
public static ECPoint decodePoint(byte[] data, EllipticCurve curve)
@@ -220,6 +220,21 @@
return nameSpec.getName();
}
+ public static boolean equals(ECParameterSpec spec1, ECParameterSpec spec2) {
+ if (spec1 == spec2) {
+ return true;
+ }
+
+ if (spec1 == null || spec2 == null) {
+ return false;
+ }
+ return (spec1.getCofactor() == spec2.getCofactor() &&
+ spec1.getOrder().equals(spec2.getOrder()) &&
+ spec1.getCurve().equals(spec2.getCurve()) &&
+ spec1.getGenerator().equals(spec2.getGenerator()));
+ }
+
+
// Convert the concatenation R and S in into their DER encoding
public static byte[] encodeSignature(byte[] signature) throws SignatureException {
--- a/src/java.base/share/classes/sun/security/util/SignatureUtil.java Thu Jul 11 12:13:52 2019 -0700
+++ b/src/java.base/share/classes/sun/security/util/SignatureUtil.java Thu Jul 11 20:11:47 2019 +0000
@@ -28,6 +28,7 @@
import java.io.IOException;
import java.security.*;
import java.security.spec.*;
+import java.util.Locale;
import sun.security.rsa.RSAUtil;
import jdk.internal.access.SharedSecrets;
@@ -74,14 +75,9 @@
AlgorithmParameters params)
throws ProviderException {
- sigName = checkName(sigName);
+ sigName = checkName(sigName).toUpperCase(Locale.ENGLISH);
AlgorithmParameterSpec paramSpec = null;
if (params != null) {
- if (sigName.toUpperCase().indexOf("RSA") == -1) {
- throw new ProviderException
- ("Unrecognized algorithm for signature parameters " +
- sigName);
- }
// AlgorithmParameters.getAlgorithm() may returns oid if it's
// created during DER decoding. Convert to use the standard name
// before passing it to RSAUtil
@@ -93,7 +89,20 @@
throw new ProviderException(e);
}
}
- paramSpec = RSAUtil.getParamSpec(params);
+
+ if (sigName.indexOf("RSA") != -1) {
+ paramSpec = RSAUtil.getParamSpec(params);
+ } else if (sigName.indexOf("ECDSA") != -1) {
+ try {
+ paramSpec = params.getParameterSpec(ECParameterSpec.class);
+ } catch (Exception e) {
+ throw new ProviderException("Error handling EC parameters", e);
+ }
+ } else {
+ throw new ProviderException
+ ("Unrecognized algorithm for signature parameters " +
+ sigName);
+ }
}
return paramSpec;
}
@@ -103,17 +112,31 @@
public static AlgorithmParameterSpec getParamSpec(String sigName,
byte[] paramBytes)
throws ProviderException {
- sigName = checkName(sigName);
+ sigName = checkName(sigName).toUpperCase(Locale.ENGLISH);
AlgorithmParameterSpec paramSpec = null;
+
if (paramBytes != null) {
- if (sigName.toUpperCase().indexOf("RSA") == -1) {
+ if (sigName.indexOf("RSA") != -1) {
+ AlgorithmParameters params =
+ createAlgorithmParameters(sigName, paramBytes);
+ paramSpec = RSAUtil.getParamSpec(params);
+ } else if (sigName.indexOf("ECDSA") != -1) {
+ try {
+ Provider p = Signature.getInstance(sigName).getProvider();
+ paramSpec = ECUtil.getECParameterSpec(p, paramBytes);
+ } catch (Exception e) {
+ throw new ProviderException("Error handling EC parameters", e);
+ }
+ // ECUtil discards exception and returns null, so we need to check
+ // the returned value
+ if (paramSpec == null) {
+ throw new ProviderException("Error handling EC parameters");
+ }
+ } else {
throw new ProviderException
("Unrecognized algorithm for signature parameters " +
sigName);
}
- AlgorithmParameters params =
- createAlgorithmParameters(sigName, paramBytes);
- paramSpec = RSAUtil.getParamSpec(params);
}
return paramSpec;
}
--- a/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java Thu Jul 11 12:13:52 2019 -0700
+++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java Thu Jul 11 20:11:47 2019 +0000
@@ -72,6 +72,9 @@
// public key, if initialized for verifying
private ECPublicKey publicKey;
+ // signature parameters
+ private ECParameterSpec sigParams = null;
+
// The format. true for the IEEE P1363 format. false (default) for ASN.1
private final boolean p1363Format;
@@ -279,10 +282,14 @@
@Override
protected void engineInitVerify(PublicKey publicKey)
throws InvalidKeyException {
- this.publicKey = (ECPublicKey) ECKeyFactory.toECKey(publicKey);
+ ECPublicKey key = (ECPublicKey) ECKeyFactory.toECKey(publicKey);
+ if (!isCompatible(this.sigParams, key.getParams())) {
+ throw new InvalidKeyException("Key params does not match signature params");
+ }
// Should check that the supplied key is appropriate for signature
// algorithm (e.g. P-256 for SHA256withECDSA)
+ this.publicKey = key;
this.privateKey = null;
resetDigest();
}
@@ -298,10 +305,14 @@
@Override
protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
throws InvalidKeyException {
- this.privateKey = (ECPrivateKey) ECKeyFactory.toECKey(privateKey);
+ ECPrivateKey key = (ECPrivateKey) ECKeyFactory.toECKey(privateKey);
+ if (!isCompatible(this.sigParams, key.getParams())) {
+ throw new InvalidKeyException("Key params does not match signature params");
+ }
// Should check that the supplied key is appropriate for signature
// algorithm (e.g. P-256 for SHA256withECDSA)
+ this.privateKey = key;
this.publicKey = null;
this.random = random;
resetDigest();
@@ -354,6 +365,16 @@
needsReset = true;
}
+ private static boolean isCompatible(ECParameterSpec sigParams,
+ ECParameterSpec keyParams) {
+ if (sigParams == null) {
+ // no restriction on key param
+ return true;
+ }
+ return ECUtil.equals(sigParams, keyParams);
+ }
+
+
private byte[] signDigestImpl(ECDSAOperations ops, int seedBits,
byte[] digest, ECPrivateKeyImpl privImpl, SecureRandom random)
throws SignatureException {
@@ -495,9 +516,16 @@
@Override
protected void engineSetParameter(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
- if (params != null) {
+ if (params != null && !(params instanceof ECParameterSpec)) {
throw new InvalidAlgorithmParameterException("No parameter accepted");
}
+ ECKey key = (this.privateKey == null? this.publicKey : this.privateKey);
+ if ((key != null) && !isCompatible((ECParameterSpec)params, key.getParams())) {
+ throw new InvalidAlgorithmParameterException
+ ("Signature params does not match key params");
+ }
+
+ sigParams = (ECParameterSpec) params;
}
// get parameter, not supported. See JCA doc
@@ -510,7 +538,17 @@
@Override
protected AlgorithmParameters engineGetParameters() {
- return null;
+ if (sigParams == null) {
+ return null;
+ }
+ try {
+ AlgorithmParameters ap = AlgorithmParameters.getInstance("EC");
+ ap.init(sigParams);
+ return ap;
+ } catch (Exception e) {
+ // should never happen
+ throw new ProviderException("Error retrieving EC parameters", e);
+ }
}
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/security/x509/X509CertImpl/ECSigParamsVerifyWithCert.java Thu Jul 11 20:11:47 2019 +0000
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019, 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.
+ */
+
+/*
+ * @test
+ * @bug 8225745
+ * @summary Ensure ECDSA certificates with signature algorithm parameters
+ * can be verified successfully
+ * @run main ECSigParamsVerifyWithCert
+ */
+import java.io.*;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+public class ECSigParamsVerifyWithCert {
+
+ // ECDSA certificate with non-null signature parameters, i.e.
+ // Signature Algorithm: SHA256withECDSA, params unparsed,
+ // OID = 1.2.840.10045.4.3.2
+ private static String ecEntityWithSigParamsStr =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIICXjCCAfmgAwIBAgIIHzREzASpiTowFAYIKoZIzj0EAwIGCCqGSM49AwEHMGAx\n" +
+ "IzAhBgNVBAMMGkNvcmRhIE5vZGUgSW50ZXJtZWRpYXRlIENBMQswCQYDVQQKDAJS\n" +
+ "MzEOMAwGA1UECwwFY29yZGExDzANBgNVBAcMBkxvbmRvbjELMAkGA1UEBhMCVUsw\n" +
+ "HhcNMTgwNjI1MDAwMDAwWhcNMjcwNTIwMDAwMDAwWjAxMQswCQYDVQQGEwJHQjEP\n" +
+ "MA0GA1UEBwwGTG9uZG9uMREwDwYDVQQKDAhNZWdhQ29ycDBZMBMGByqGSM49AgEG\n" +
+ "CCqGSM49AwEHA0IABG2VjWPPFnGVka3G9++Sz/GPRkAkht4BDoYTlkRz8hpwr4iu\n" +
+ "fU6NlReirLOB4LBLZcmp16xm4RYsN5ouTS7Z3wKjgcEwgb4wHQYDVR0OBBYEFBnY\n" +
+ "sikYpaSL9U8FUygbqN3sIvMOMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgGG\n" +
+ "MCMGA1UdJQQcMBoGCCsGAQUFBwMBBggrBgEFBQcDAgYEVR0lADARBgorBgEEAYOK\n" +
+ "YgEBBAMCAQQwRwYDVR0eAQH/BD0wO6A3MDWkMzAxMQswCQYDVQQGEwJHQjEPMA0G\n" +
+ "A1UEBwwGTG9uZG9uMREwDwYDVQQKDAhNZWdhQ29ycKEAMBQGCCqGSM49BAMCBggq\n" +
+ "hkjOPQMBBwNJADBGAiEAos+QzgwwH2hfOtrlLncHnoT2YXXHP4q5h01T2DRmjcMC\n" +
+ "IQDa3xZz7CkyyNO1+paAthiNVIlGwwnl4UxuYMwkAiWACw==\n" +
+ "-----END CERTIFICATE-----\n";
+
+ // ECDSA certificate with only signature algorithm oid, no parameters, i.e.
+ // Signature Algorithm: SHA256withECDSA, OID = 1.2.840.10045.4.3.2
+ private static String ecSigner =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIICETCCAbigAwIBAgIIaHr3YTnjT8YwCgYIKoZIzj0EAwIwWDEbMBkGA1UEAwwS\n" +
+ "Q29yZGEgTm9kZSBSb290IENBMQswCQYDVQQKDAJSMzEOMAwGA1UECwwFY29yZGEx\n" +
+ "DzANBgNVBAcMBkxvbmRvbjELMAkGA1UEBhMCVUswHhcNMTcwNTIyMDAwMDAwWhcN\n" +
+ "MjcwNTIwMDAwMDAwWjBgMSMwIQYDVQQDDBpDb3JkYSBOb2RlIEludGVybWVkaWF0\n" +
+ "ZSBDQTELMAkGA1UECgwCUjMxDjAMBgNVBAsMBWNvcmRhMQ8wDQYDVQQHDAZMb25k\n" +
+ "b24xCzAJBgNVBAYTAlVLMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEA8veoCbh\n" +
+ "ZmazlyIFWjExBd8ru5OYdFW9Z9ZD5BVg/dswdKC4dlHMHe/sQ4TxFmkYNqf7DTTt\n" +
+ "ePtdHT7Eb1LGYKNkMGIwHQYDVR0OBBYEFOvuLjAVKUCuGZge2G/jfX8HosITMAsG\n" +
+ "A1UdDwQEAwIBhjAjBgNVHSUEHDAaBggrBgEFBQcDAQYIKwYBBQUHAwIGBFUdJQAw\n" +
+ "DwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBEAiB6wr47tuC71qi6+FbY\n" +
+ "XYDTvK+QmAi5ywkFc95I9fPLaQIgIM+nNNQ50NwK610h3bG37XC2tGu+A7Dhtt2Q\n" +
+ "4nDqu30=\n" +
+ "-----END CERTIFICATE-----\n";
+
+ public static void main(String[] args) throws Exception {
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ ByteArrayInputStream is
+ = new ByteArrayInputStream(ecEntityWithSigParamsStr.getBytes());
+ X509Certificate ecEntityWithSigParams = (X509Certificate)certFactory.generateCertificate(is);
+ is = new ByteArrayInputStream(ecSigner.getBytes());
+ X509Certificate ecSigner = (X509Certificate)certFactory.generateCertificate(is);
+
+ try {
+ ecEntityWithSigParams.verify(ecSigner.getPublicKey());
+ System.out.println("Test Passed: EC Cert verified");
+ } catch (Exception e) {
+ System.out.println("Failed, cannot verify EC certificate with sig params");
+ throw e;
+ }
+ }
+}