OpenJDK / bsd-port / jdk9 / jdk
changeset 13509:927f285009b6
8081297: SSL Problem with Tomcat
Reviewed-by: xuelei, jnimeh, ahgross
author | igerasim |
---|---|
date | Sat, 11 Jul 2015 14:54:07 +0300 |
parents | 09eca0dfafd6 |
children | 7abc461969c3 |
files | src/java.base/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java src/java.base/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java src/java.base/share/classes/sun/security/util/KeyUtil.java |
diffstat | 4 files changed, 112 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/src/java.base/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java Wed Jan 20 07:36:42 2016 -0500 +++ b/src/java.base/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java Sat Jul 11 14:54:07 2015 +0300 @@ -76,11 +76,14 @@ "TlsRsaPremasterSecretGenerator must be initialized"); } - if (random == null) { - random = new SecureRandom(); + byte[] b = spec.getEncodedSecret(); + if (b == null) { + if (random == null) { + random = new SecureRandom(); + } + b = new byte[48]; + random.nextBytes(b); } - byte[] b = new byte[48]; - random.nextBytes(b); b[0] = (byte)spec.getMajorVersion(); b[1] = (byte)spec.getMinorVersion();
--- a/src/java.base/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java Wed Jan 20 07:36:42 2016 -0500 +++ b/src/java.base/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java Sat Jul 11 14:54:07 2015 +0300 @@ -43,6 +43,8 @@ public class TlsRsaPremasterSecretParameterSpec implements AlgorithmParameterSpec { + private final byte[] encodedSecret; + /* * The TLS spec says that the version in the RSA premaster secret must * be the maximum version supported by the client (i.e. the version it @@ -89,6 +91,33 @@ this.clientVersion = checkVersion(clientVersion); this.serverVersion = checkVersion(serverVersion); + this.encodedSecret = null; + } + + /** + * Constructs a new TlsRsaPremasterSecretParameterSpec. + * + * @param clientVersion the version of the TLS protocol by which the + * client wishes to communicate during this session + * @param serverVersion the negotiated version of the TLS protocol which + * contains the lower of that suggested by the client in the client + * hello and the highest supported by the server. + * @param encodedSecret the encoded secret key + * + * @throws IllegalArgumentException if clientVersion or serverVersion are + * negative or larger than (2^16 - 1) or if encodedSecret is not + * exactly 48 bytes + */ + public TlsRsaPremasterSecretParameterSpec( + int clientVersion, int serverVersion, byte[] encodedSecret) { + + this.clientVersion = checkVersion(clientVersion); + this.serverVersion = checkVersion(serverVersion); + if (encodedSecret == null || encodedSecret.length != 48) { + throw new IllegalArgumentException( + "Encoded secret is not exactly 48 bytes"); + } + this.encodedSecret = encodedSecret.clone(); } /** @@ -147,4 +176,13 @@ } return version; } + + /** + * Returns the encoded secret. + * + * @return the encoded secret, may be null if no encoded secret. + */ + public byte[] getEncodedSecret() { + return encodedSecret == null ? null : encodedSecret.clone(); + } }
--- a/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java Wed Jan 20 07:36:42 2016 -0500 +++ b/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java Sat Jul 11 14:54:07 2015 +0300 @@ -113,14 +113,41 @@ } } + boolean needFailover = false; + byte[] encoded = null; try { Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); - cipher.init(Cipher.UNWRAP_MODE, privateKey, - new TlsRsaPremasterSecretParameterSpec( - maxVersion.v, currentVersion.v), - generator); - preMaster = (SecretKey)cipher.unwrap(encrypted, - "TlsRsaPremasterSecret", Cipher.SECRET_KEY); + needFailover = !KeyUtil.isOracleJCEProvider( + cipher.getProvider().getName()); + if (needFailover) { + cipher.init(Cipher.DECRYPT_MODE, privateKey); + encoded = cipher.doFinal(encrypted); + encoded = KeyUtil.checkTlsPreMasterSecretKey( + maxVersion.v, currentVersion.v, + generator, encoded, false); + preMaster = generatePreMasterSecret( + maxVersion.v, currentVersion.v, + encoded, generator); + } else { + cipher.init(Cipher.UNWRAP_MODE, privateKey, + new TlsRsaPremasterSecretParameterSpec( + maxVersion.v, currentVersion.v), + generator); + preMaster = (SecretKey)cipher.unwrap(encrypted, + "TlsRsaPremasterSecret", Cipher.SECRET_KEY); + } + } catch (BadPaddingException bpe) { + if (needFailover) { + encoded = KeyUtil.checkTlsPreMasterSecretKey( + maxVersion.v, currentVersion.v, + generator, null, false); + preMaster = generatePreMasterSecret( + maxVersion.v, currentVersion.v, + encoded, generator); + } else { + // Otherwise, unlikely to happen + throw new RuntimeException("Unexpected exception", bpe); + } } catch (InvalidKeyException ibk) { // the message is too big to process with RSA throw new SSLProtocolException( @@ -135,6 +162,35 @@ } } + // generate a premaster secret with the specified version number + @SuppressWarnings("deprecation") + private static SecretKey generatePreMasterSecret( + int clientVersion, int serverVersion, + byte[] encodedSecret, SecureRandom generator) { + + if (debug != null && Debug.isOn("handshake")) { + System.out.println("Generating a premaster secret"); + } + + try { + String s = ((clientVersion >= ProtocolVersion.TLS12.v) ? + "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret"); + KeyGenerator kg = JsseJce.getKeyGenerator(s); + kg.init(new TlsRsaPremasterSecretParameterSpec( + clientVersion, serverVersion, encodedSecret), + generator); + return kg.generateKey(); + } catch (InvalidAlgorithmParameterException | + NoSuchAlgorithmException iae) { + // unlikely to happen, otherwise, must be a provider exception + if (debug != null && Debug.isOn("handshake")) { + System.out.println("RSA premaster secret generation error:"); + iae.printStackTrace(System.out); + } + throw new RuntimeException("Could not generate premaster secret", iae); + } + } + @Override int messageType() { return ht_client_key_exchange;
--- a/src/java.base/share/classes/sun/security/util/KeyUtil.java Wed Jan 20 07:36:42 2016 -0500 +++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java Sat Jul 11 14:54:07 2015 +0300 @@ -143,8 +143,6 @@ /** * Returns whether the specified provider is Oracle provider or not. - * <P> - * Note that this method is only apply to SunJCE and SunPKCS11 at present. * * @param providerName * the provider name @@ -152,8 +150,11 @@ * {@code providerName} is Oracle provider */ public static final boolean isOracleJCEProvider(String providerName) { - return providerName != null && (providerName.equals("SunJCE") || - providerName.startsWith("SunPKCS11")); + return providerName != null && + (providerName.equals("SunJCE") || + providerName.equals("SunMSCAPI") || + providerName.equals("OracleUcrypto") || + providerName.startsWith("SunPKCS11")); } /**