1/* 2 * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27package sun.security.ssl; 28 29import java.io.*; 30import java.security.*; 31 32import javax.crypto.*; 33 34import javax.net.ssl.*; 35 36import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; 37import sun.security.util.KeyUtil; 38 39/** 40 * This is the client key exchange message (CLIENT --> SERVER) used with 41 * all RSA key exchanges; it holds the RSA-encrypted pre-master secret. 42 * 43 * The message is encrypted using PKCS #1 block type 02 encryption with the 44 * server's public key. The padding and resulting message size is a function 45 * of this server's public key modulus size, but the pre-master secret is 46 * always exactly 48 bytes. 47 * 48 */ 49final class RSAClientKeyExchange extends HandshakeMessage { 50 51 /* 52 * The following field values were encrypted with the server's public 53 * key (or temp key from server key exchange msg) and are presented 54 * here in DECRYPTED form. 55 */ 56 private ProtocolVersion protocolVersion; // preMaster [0,1] 57 SecretKey preMaster; 58 private byte[] encrypted; // same size as public modulus 59 60 /* 61 * Client randomly creates a pre-master secret and encrypts it 62 * using the server's RSA public key; only the server can decrypt 63 * it, using its RSA private key. Result is the same size as the 64 * server's public key, and uses PKCS #1 block format 02. 65 */ 66 @SuppressWarnings("deprecation") 67 RSAClientKeyExchange(ProtocolVersion protocolVersion, 68 ProtocolVersion maxVersion, 69 SecureRandom generator, PublicKey publicKey) throws IOException { 70 if (publicKey.getAlgorithm().equals("RSA") == false) { 71 throw new SSLKeyException("Public key not of type RSA: " + 72 publicKey.getAlgorithm()); 73 } 74 this.protocolVersion = protocolVersion; 75 76 try { 77 String s = protocolVersion.useTLS12PlusSpec() ? 78 "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret"; 79 KeyGenerator kg = JsseJce.getKeyGenerator(s); 80 kg.init(new TlsRsaPremasterSecretParameterSpec( 81 maxVersion.v, protocolVersion.v), generator); 82 preMaster = kg.generateKey(); 83 84 Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); 85 cipher.init(Cipher.WRAP_MODE, publicKey, generator); 86 encrypted = cipher.wrap(preMaster); 87 } catch (GeneralSecurityException e) { 88 throw (SSLKeyException)new SSLKeyException 89 ("RSA premaster secret error").initCause(e); 90 } 91 } 92 93 /* 94 * Retrieving the cipher's provider name for the debug purposes 95 * can throw an exception by itself. 96 */ 97 private static String safeProviderName(Cipher cipher) { 98 try { 99 return cipher.getProvider().toString(); 100 } catch (Exception e) { 101 if (debug != null && Debug.isOn("handshake")) { 102 System.out.println("Retrieving The Cipher provider name" + 103 " caused exception " + e.getMessage()); 104 } 105 } 106 try { 107 return cipher.toString() + " (provider name not available)"; 108 } catch (Exception e) { 109 if (debug != null && Debug.isOn("handshake")) { 110 System.out.println("Retrieving The Cipher name" + 111 " caused exception " + e.getMessage()); 112 } 113 } 114 return "(cipher/provider names not available)"; 115 } 116 117 /* 118 * Server gets the PKCS #1 (block format 02) data, decrypts 119 * it with its private key. 120 */ 121 @SuppressWarnings("deprecation") 122 RSAClientKeyExchange(ProtocolVersion currentVersion, 123 ProtocolVersion maxVersion, 124 SecureRandom generator, HandshakeInStream input, 125 int messageSize, PrivateKey privateKey) throws IOException { 126 127 if (privateKey.getAlgorithm().equals("RSA") == false) { 128 throw new SSLKeyException("Private key not of type RSA: " + 129 privateKey.getAlgorithm()); 130 } 131 132 if (currentVersion.useTLS10PlusSpec()) { 133 encrypted = input.getBytes16(); 134 } else { 135 encrypted = new byte [messageSize]; 136 if (input.read(encrypted) != messageSize) { 137 throw new SSLProtocolException( 138 "SSL: read PreMasterSecret: short read"); 139 } 140 } 141 142 byte[] encoded = null; 143 try { 144 boolean needFailover = false; 145 Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); 146 try { 147 // Try UNWRAP_MODE mode firstly. 148 cipher.init(Cipher.UNWRAP_MODE, privateKey, 149 new TlsRsaPremasterSecretParameterSpec( 150 maxVersion.v, currentVersion.v), 151 generator); 152 153 // The provider selection can be delayed, please don't call 154 // any Cipher method before the call to Cipher.init(). 155 needFailover = !KeyUtil.isOracleJCEProvider( 156 cipher.getProvider().getName()); 157 } catch (InvalidKeyException | UnsupportedOperationException iue) { 158 if (debug != null && Debug.isOn("handshake")) { 159 System.out.println("The Cipher provider " 160 + safeProviderName(cipher) 161 + " caused exception: " + iue.getMessage()); 162 } 163 164 needFailover = true; 165 } 166 167 if (needFailover) { 168 // The cipher might be spoiled by unsuccessful call to init(), 169 // so request a fresh instance 170 cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); 171 172 // Use DECRYPT_MODE and dispose the previous initialization. 173 cipher.init(Cipher.DECRYPT_MODE, privateKey); 174 boolean failed = false; 175 try { 176 encoded = cipher.doFinal(encrypted); 177 } catch (BadPaddingException bpe) { 178 // Note: encoded == null 179 failed = true; 180 } 181 encoded = KeyUtil.checkTlsPreMasterSecretKey( 182 maxVersion.v, currentVersion.v, 183 generator, encoded, failed); 184 preMaster = generatePreMasterSecret( 185 maxVersion.v, currentVersion.v, 186 encoded, generator); 187 } else { 188 // the cipher should have been initialized 189 preMaster = (SecretKey)cipher.unwrap(encrypted, 190 "TlsRsaPremasterSecret", Cipher.SECRET_KEY); 191 } 192 } catch (InvalidKeyException ibk) { 193 // the message is too big to process with RSA 194 throw new SSLException( 195 "Unable to process PreMasterSecret", ibk); 196 } catch (Exception e) { 197 // unlikely to happen, otherwise, must be a provider exception 198 if (debug != null && Debug.isOn("handshake")) { 199 System.out.println("RSA premaster secret decryption error:"); 200 e.printStackTrace(System.out); 201 } 202 throw new RuntimeException("Could not generate dummy secret", e); 203 } 204 } 205 206 // generate a premaster secret with the specified version number 207 @SuppressWarnings("deprecation") 208 private static SecretKey generatePreMasterSecret( 209 int clientVersion, int serverVersion, 210 byte[] encodedSecret, SecureRandom generator) { 211 212 if (debug != null && Debug.isOn("handshake")) { 213 System.out.println("Generating a premaster secret"); 214 } 215 216 try { 217 String s = ((clientVersion >= ProtocolVersion.TLS12.v) ? 218 "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret"); 219 KeyGenerator kg = JsseJce.getKeyGenerator(s); 220 kg.init(new TlsRsaPremasterSecretParameterSpec( 221 clientVersion, serverVersion, encodedSecret), 222 generator); 223 return kg.generateKey(); 224 } catch (InvalidAlgorithmParameterException | 225 NoSuchAlgorithmException iae) { 226 // unlikely to happen, otherwise, must be a provider exception 227 if (debug != null && Debug.isOn("handshake")) { 228 System.out.println("RSA premaster secret generation error:"); 229 iae.printStackTrace(System.out); 230 } 231 throw new RuntimeException("Could not generate premaster secret", iae); 232 } 233 } 234 235 @Override 236 int messageType() { 237 return ht_client_key_exchange; 238 } 239 240 @Override 241 int messageLength() { 242 if (protocolVersion.useTLS10PlusSpec()) { 243 return encrypted.length + 2; 244 } else { 245 return encrypted.length; 246 } 247 } 248 249 @Override 250 void send(HandshakeOutStream s) throws IOException { 251 if (protocolVersion.useTLS10PlusSpec()) { 252 s.putBytes16(encrypted); 253 } else { 254 s.write(encrypted); 255 } 256 } 257 258 @Override 259 void print(PrintStream s) throws IOException { 260 String version = "version not available/extractable"; 261 262 byte[] ba = preMaster.getEncoded(); 263 if (ba != null && ba.length >= 2) { 264 version = ProtocolVersion.valueOf(ba[0], ba[1]).name; 265 } 266 267 s.println("*** ClientKeyExchange, RSA PreMasterSecret, " + version); 268 } 269} 270