# HG changeset patch # User valeriep # Date 1562875907 0 # Node ID 6521aec1c26eead05da0c65e3bf1cb02dcbea703 # Parent 340d73f42b3c03570f2bbaf98e417d7a19274b3f 8225745: NoSuchAlgorithmException exception for SHA256withECDSA with RSASSA-PSS support Summary: Fixed SignatureUtil and ECDSA signature impl to handle EC parameters Reviewed-by: weijun diff -r 340d73f42b3c -r 6521aec1c26e src/java.base/share/classes/sun/security/util/CurveDB.java --- 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; diff -r 340d73f42b3c -r 6521aec1c26e src/java.base/share/classes/sun/security/util/ECUtil.java --- 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 { diff -r 340d73f42b3c -r 6521aec1c26e src/java.base/share/classes/sun/security/util/SignatureUtil.java --- 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; } diff -r 340d73f42b3c -r 6521aec1c26e src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java --- 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); + } } /** diff -r 340d73f42b3c -r 6521aec1c26e test/jdk/sun/security/x509/X509CertImpl/ECSigParamsVerifyWithCert.java --- /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; + } + } +}