Wed, 06 Nov 2019 09:45:04 -0800
8223940: Private key not supported by chosen signature algorithm
Reviewed-by: valeriep
1.1 --- a/src/share/classes/sun/security/ssl/CertificateVerify.java Thu Jan 10 07:54:16 2019 -0800 1.2 +++ b/src/share/classes/sun/security/ssl/CertificateVerify.java Wed Nov 06 09:45:04 2019 -0800 1.3 @@ -31,6 +31,7 @@ 1.4 import java.text.MessageFormat; 1.5 import java.util.Arrays; 1.6 import java.util.Locale; 1.7 +import java.util.Map; 1.8 import sun.security.ssl.SSLHandshake.HandshakeMessage; 1.9 import sun.security.ssl.X509Authentication.X509Credentials; 1.10 import sun.security.ssl.X509Authentication.X509Possession; 1.11 @@ -585,30 +586,27 @@ 1.12 1.13 // This happens in client side only. 1.14 ClientHandshakeContext chc = (ClientHandshakeContext)context; 1.15 - this.signatureScheme = SignatureScheme.getPreferableAlgorithm( 1.16 + Map.Entry<SignatureScheme, Signature> schemeAndSigner = 1.17 + SignatureScheme.getSignerOfPreferableAlgorithm( 1.18 chc.peerRequestedSignatureSchemes, 1.19 x509Possession, 1.20 chc.negotiatedProtocol); 1.21 - if (signatureScheme == null) { 1.22 + if (schemeAndSigner == null) { 1.23 // Unlikely, the credentials generator should have 1.24 // selected the preferable signature algorithm properly. 1.25 throw chc.conContext.fatal(Alert.INTERNAL_ERROR, 1.26 - "No preferred signature algorithm for CertificateVerify"); 1.27 + "No supported CertificateVerify signature algorithm for " + 1.28 + x509Possession.popPrivateKey.getAlgorithm() + 1.29 + " key"); 1.30 } 1.31 1.32 + this.signatureScheme = schemeAndSigner.getKey(); 1.33 byte[] temproary = null; 1.34 try { 1.35 - Signature signer = 1.36 - signatureScheme.getSignature(x509Possession.popPrivateKey); 1.37 + Signature signer = schemeAndSigner.getValue(); 1.38 signer.update(chc.handshakeHash.archived()); 1.39 temproary = signer.sign(); 1.40 - } catch (NoSuchAlgorithmException | 1.41 - InvalidAlgorithmParameterException nsae) { 1.42 - throw chc.conContext.fatal(Alert.INTERNAL_ERROR, 1.43 - "Unsupported signature algorithm (" + 1.44 - signatureScheme.name + 1.45 - ") used in CertificateVerify handshake message", nsae); 1.46 - } catch (InvalidKeyException | SignatureException ikse) { 1.47 + } catch (SignatureException ikse) { 1.48 throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 1.49 "Cannot produce CertificateVerify signature", ikse); 1.50 } 1.51 @@ -668,7 +666,7 @@ 1.52 this.signature = Record.getBytes16(m); 1.53 try { 1.54 Signature signer = 1.55 - signatureScheme.getSignature(x509Credentials.popPublicKey); 1.56 + signatureScheme.getVerifier(x509Credentials.popPublicKey); 1.57 signer.update(shc.handshakeHash.archived()); 1.58 if (!signer.verify(signature)) { 1.59 throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 1.60 @@ -897,17 +895,22 @@ 1.61 X509Possession x509Possession) throws IOException { 1.62 super(context); 1.63 1.64 - this.signatureScheme = SignatureScheme.getPreferableAlgorithm( 1.65 - context.peerRequestedSignatureSchemes, 1.66 - x509Possession, 1.67 - context.negotiatedProtocol); 1.68 - if (signatureScheme == null) { 1.69 + Map.Entry<SignatureScheme, Signature> schemeAndSigner = 1.70 + SignatureScheme.getSignerOfPreferableAlgorithm( 1.71 + context.peerRequestedSignatureSchemes, 1.72 + x509Possession, 1.73 + context.negotiatedProtocol); 1.74 + if (schemeAndSigner == null) { 1.75 // Unlikely, the credentials generator should have 1.76 // selected the preferable signature algorithm properly. 1.77 throw context.conContext.fatal(Alert.INTERNAL_ERROR, 1.78 - "No preferred signature algorithm for CertificateVerify"); 1.79 + "No supported CertificateVerify signature algorithm for " + 1.80 + x509Possession.popPrivateKey.getAlgorithm() + 1.81 + " key"); 1.82 } 1.83 1.84 + this.signatureScheme = schemeAndSigner.getKey(); 1.85 + 1.86 byte[] hashValue = context.handshakeHash.digest(); 1.87 byte[] contentCovered; 1.88 if (context.sslConfig.isClientMode) { 1.89 @@ -924,17 +927,10 @@ 1.90 1.91 byte[] temproary = null; 1.92 try { 1.93 - Signature signer = 1.94 - signatureScheme.getSignature(x509Possession.popPrivateKey); 1.95 + Signature signer = schemeAndSigner.getValue(); 1.96 signer.update(contentCovered); 1.97 temproary = signer.sign(); 1.98 - } catch (NoSuchAlgorithmException | 1.99 - InvalidAlgorithmParameterException nsae) { 1.100 - throw context.conContext.fatal(Alert.INTERNAL_ERROR, 1.101 - "Unsupported signature algorithm (" + 1.102 - signatureScheme.name + 1.103 - ") used in CertificateVerify handshake message", nsae); 1.104 - } catch (InvalidKeyException | SignatureException ikse) { 1.105 + } catch (SignatureException ikse) { 1.106 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE, 1.107 "Cannot produce CertificateVerify signature", ikse); 1.108 } 1.109 @@ -1005,7 +1001,7 @@ 1.110 1.111 try { 1.112 Signature signer = 1.113 - signatureScheme.getSignature(x509Credentials.popPublicKey); 1.114 + signatureScheme.getVerifier(x509Credentials.popPublicKey); 1.115 signer.update(contentCovered); 1.116 if (!signer.verify(signature)) { 1.117 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
2.1 --- a/src/share/classes/sun/security/ssl/DHServerKeyExchange.java Thu Jan 10 07:54:16 2019 -0800 2.2 +++ b/src/share/classes/sun/security/ssl/DHServerKeyExchange.java Wed Nov 06 09:45:04 2019 -0800 2.3 @@ -42,6 +42,7 @@ 2.4 import java.text.MessageFormat; 2.5 import java.util.EnumSet; 2.6 import java.util.Locale; 2.7 +import java.util.Map; 2.8 import javax.crypto.interfaces.DHPublicKey; 2.9 import javax.crypto.spec.DHParameterSpec; 2.10 import javax.crypto.spec.DHPublicKeySpec; 2.11 @@ -125,24 +126,21 @@ 2.12 shc.negotiatedProtocol.useTLS12PlusSpec(); 2.13 Signature signer = null; 2.14 if (useExplicitSigAlgorithm) { 2.15 - signatureScheme = SignatureScheme.getPreferableAlgorithm( 2.16 - shc.peerRequestedSignatureSchemes, 2.17 - x509Possession, 2.18 - shc.negotiatedProtocol); 2.19 - if (signatureScheme == null) { 2.20 + Map.Entry<SignatureScheme, Signature> schemeAndSigner = 2.21 + SignatureScheme.getSignerOfPreferableAlgorithm( 2.22 + shc.peerRequestedSignatureSchemes, 2.23 + x509Possession, 2.24 + shc.negotiatedProtocol); 2.25 + if (schemeAndSigner == null) { 2.26 // Unlikely, the credentials generator should have 2.27 // selected the preferable signature algorithm properly. 2.28 throw shc.conContext.fatal(Alert.INTERNAL_ERROR, 2.29 - "No preferred signature algorithm"); 2.30 - } 2.31 - try { 2.32 - signer = signatureScheme.getSignature( 2.33 - x509Possession.popPrivateKey); 2.34 - } catch (NoSuchAlgorithmException | InvalidKeyException | 2.35 - InvalidAlgorithmParameterException nsae) { 2.36 - throw shc.conContext.fatal(Alert.INTERNAL_ERROR, 2.37 - "Unsupported signature algorithm: " + 2.38 - signatureScheme.name, nsae); 2.39 + "No supported signature algorithm for " + 2.40 + x509Possession.popPrivateKey.getAlgorithm() + 2.41 + " key"); 2.42 + } else { 2.43 + signatureScheme = schemeAndSigner.getKey(); 2.44 + signer = schemeAndSigner.getValue(); 2.45 } 2.46 } else { 2.47 signatureScheme = null; 2.48 @@ -241,7 +239,7 @@ 2.49 Signature signer; 2.50 if (useExplicitSigAlgorithm) { 2.51 try { 2.52 - signer = signatureScheme.getSignature( 2.53 + signer = signatureScheme.getVerifier( 2.54 x509Credentials.popPublicKey); 2.55 } catch (NoSuchAlgorithmException | InvalidKeyException | 2.56 InvalidAlgorithmParameterException nsae) {
3.1 --- a/src/share/classes/sun/security/ssl/ECDHServerKeyExchange.java Thu Jan 10 07:54:16 2019 -0800 3.2 +++ b/src/share/classes/sun/security/ssl/ECDHServerKeyExchange.java Wed Nov 06 09:45:04 2019 -0800 3.3 @@ -45,6 +45,7 @@ 3.4 import java.text.MessageFormat; 3.5 import java.util.EnumSet; 3.6 import java.util.Locale; 3.7 +import java.util.Map; 3.8 import sun.security.ssl.ECDHKeyExchange.ECDHECredentials; 3.9 import sun.security.ssl.ECDHKeyExchange.ECDHEPossession; 3.10 import sun.security.ssl.SSLHandshake.HandshakeMessage; 3.11 @@ -139,26 +140,21 @@ 3.12 shc.negotiatedProtocol.useTLS12PlusSpec(); 3.13 Signature signer = null; 3.14 if (useExplicitSigAlgorithm) { 3.15 - signatureScheme = SignatureScheme.getPreferableAlgorithm( 3.16 - shc.peerRequestedSignatureSchemes, 3.17 - x509Possession, 3.18 - shc.negotiatedProtocol); 3.19 - if (signatureScheme == null) { 3.20 + Map.Entry<SignatureScheme, Signature> schemeAndSigner = 3.21 + SignatureScheme.getSignerOfPreferableAlgorithm( 3.22 + shc.peerRequestedSignatureSchemes, 3.23 + x509Possession, 3.24 + shc.negotiatedProtocol); 3.25 + if (schemeAndSigner == null) { 3.26 // Unlikely, the credentials generator should have 3.27 // selected the preferable signature algorithm properly. 3.28 throw shc.conContext.fatal(Alert.INTERNAL_ERROR, 3.29 - "No preferred signature algorithm for " + 3.30 + "No supported signature algorithm for " + 3.31 x509Possession.popPrivateKey.getAlgorithm() + 3.32 " key"); 3.33 - } 3.34 - try { 3.35 - signer = signatureScheme.getSignature( 3.36 - x509Possession.popPrivateKey); 3.37 - } catch (NoSuchAlgorithmException | InvalidKeyException | 3.38 - InvalidAlgorithmParameterException nsae) { 3.39 - throw shc.conContext.fatal(Alert.INTERNAL_ERROR, 3.40 - "Unsupported signature algorithm: " + 3.41 - signatureScheme.name, nsae); 3.42 + } else { 3.43 + signatureScheme = schemeAndSigner.getKey(); 3.44 + signer = schemeAndSigner.getValue(); 3.45 } 3.46 } else { 3.47 signatureScheme = null; 3.48 @@ -295,7 +291,7 @@ 3.49 Signature signer; 3.50 if (useExplicitSigAlgorithm) { 3.51 try { 3.52 - signer = signatureScheme.getSignature( 3.53 + signer = signatureScheme.getVerifier( 3.54 x509Credentials.popPublicKey); 3.55 } catch (NoSuchAlgorithmException | InvalidKeyException | 3.56 InvalidAlgorithmParameterException nsae) {
4.1 --- a/src/share/classes/sun/security/ssl/SignatureScheme.java Thu Jan 10 07:54:16 2019 -0800 4.2 +++ b/src/share/classes/sun/security/ssl/SignatureScheme.java Wed Nov 06 09:45:04 2019 -0800 4.3 @@ -31,6 +31,7 @@ 4.4 import java.security.spec.ECParameterSpec; 4.5 import java.security.spec.MGF1ParameterSpec; 4.6 import java.security.spec.PSSParameterSpec; 4.7 +import java.util.AbstractMap.SimpleImmutableEntry; 4.8 import java.util.ArrayList; 4.9 import java.util.Arrays; 4.10 import java.util.Collection; 4.11 @@ -38,6 +39,7 @@ 4.12 import java.util.EnumSet; 4.13 import java.util.LinkedList; 4.14 import java.util.List; 4.15 +import java.util.Map; 4.16 import java.util.Set; 4.17 import sun.security.ssl.SupportedGroupsExtension.NamedGroup; 4.18 import sun.security.ssl.SupportedGroupsExtension.NamedGroupType; 4.19 @@ -427,7 +429,7 @@ 4.20 return null; 4.21 } 4.22 4.23 - static SignatureScheme getPreferableAlgorithm( 4.24 + static Map.Entry<SignatureScheme, Signature> getSignerOfPreferableAlgorithm( 4.25 List<SignatureScheme> schemes, 4.26 X509Possession x509Possession, 4.27 ProtocolVersion version) { 4.28 @@ -452,7 +454,10 @@ 4.29 x509Possession.getECParameterSpec(); 4.30 if (params != null && 4.31 ss.namedGroup == NamedGroup.valueOf(params)) { 4.32 - return ss; 4.33 + Signature signer = ss.getSigner(signingKey); 4.34 + if (signer != null) { 4.35 + return new SimpleImmutableEntry<>(ss, signer); 4.36 + } 4.37 } 4.38 4.39 if (SSLLogger.isOn && 4.40 @@ -477,7 +482,10 @@ 4.41 NamedGroup keyGroup = NamedGroup.valueOf(params); 4.42 if (keyGroup != null && 4.43 SupportedGroups.isSupported(keyGroup)) { 4.44 - return ss; 4.45 + Signature signer = ss.getSigner(signingKey); 4.46 + if (signer != null) { 4.47 + return new SimpleImmutableEntry<>(ss, signer); 4.48 + } 4.49 } 4.50 } 4.51 4.52 @@ -488,7 +496,10 @@ 4.53 "), unsupported EC parameter spec: " + params); 4.54 } 4.55 } else { 4.56 - return ss; 4.57 + Signature signer = ss.getSigner(signingKey); 4.58 + if (signer != null) { 4.59 + return new SimpleImmutableEntry<>(ss, signer); 4.60 + } 4.61 } 4.62 } 4.63 } 4.64 @@ -509,21 +520,48 @@ 4.65 return new String[0]; 4.66 } 4.67 4.68 - Signature getSignature(Key key) throws NoSuchAlgorithmException, 4.69 + // This method is used to get the signature instance of this signature 4.70 + // scheme for the specific public key. Unlike getSigner(), the exception 4.71 + // is bubbled up. If the public key does not support this signature 4.72 + // scheme, it normally means the TLS handshaking cannot continue and 4.73 + // the connection should be terminated. 4.74 + Signature getVerifier(PublicKey publicKey) throws NoSuchAlgorithmException, 4.75 InvalidAlgorithmParameterException, InvalidKeyException { 4.76 if (!isAvailable) { 4.77 return null; 4.78 } 4.79 4.80 - Signature signer = JsseJce.getSignature(algorithm); 4.81 - if (key instanceof PublicKey) { 4.82 - SignatureUtil.initVerifyWithParam(signer, (PublicKey)key, 4.83 - signAlgParameter); 4.84 - } else { 4.85 - SignatureUtil.initSignWithParam(signer, (PrivateKey)key, 4.86 - signAlgParameter, null); 4.87 + Signature verifier = Signature.getInstance(algorithm); 4.88 + SignatureUtil.initVerifyWithParam(verifier, publicKey, signAlgParameter); 4.89 + 4.90 + return verifier; 4.91 + } 4.92 + 4.93 + // This method is also used to choose preferable signature scheme for the 4.94 + // specific private key. If the private key does not support the signature 4.95 + // scheme, {@code null} is returned, and the caller may fail back to next 4.96 + // available signature scheme. 4.97 + private Signature getSigner(PrivateKey privateKey) { 4.98 + if (!isAvailable) { 4.99 + return null; 4.100 } 4.101 4.102 - return signer; 4.103 + try { 4.104 + Signature signer = Signature.getInstance(algorithm); 4.105 + SignatureUtil.initSignWithParam(signer, privateKey, 4.106 + signAlgParameter, 4.107 + null); 4.108 + return signer; 4.109 + } catch (NoSuchAlgorithmException | InvalidKeyException | 4.110 + InvalidAlgorithmParameterException nsae) { 4.111 + if (SSLLogger.isOn && 4.112 + SSLLogger.isOn("ssl,handshake,verbose")) { 4.113 + SSLLogger.finest( 4.114 + "Ignore unsupported signature algorithm (" + 4.115 + this.name + ")", nsae); 4.116 + } 4.117 + } 4.118 + 4.119 + return null; 4.120 } 4.121 }