21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
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 |
22 * or visit www.oracle.com if you need additional information or have any |
23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 |
|
27 package sun.security.ssl; |
26 package sun.security.ssl; |
28 |
27 |
29 import java.io.*; |
28 import java.io.IOException; |
30 import java.security.*; |
29 import java.nio.ByteBuffer; |
31 |
30 import java.security.GeneralSecurityException; |
32 import javax.crypto.*; |
31 import java.security.PrivateKey; |
33 |
32 import java.security.PublicKey; |
34 import javax.net.ssl.*; |
33 import java.text.MessageFormat; |
35 |
34 import java.util.Locale; |
36 import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; |
35 import javax.crypto.SecretKey; |
37 import sun.security.util.KeyUtil; |
36 import sun.security.ssl.RSAKeyExchange.EphemeralRSACredentials; |
|
37 import sun.security.ssl.RSAKeyExchange.EphemeralRSAPossession; |
|
38 import sun.security.ssl.RSAKeyExchange.RSAPremasterSecret; |
|
39 import sun.security.ssl.SSLHandshake.HandshakeMessage; |
|
40 import sun.security.ssl.X509Authentication.X509Credentials; |
|
41 import sun.security.ssl.X509Authentication.X509Possession; |
|
42 import sun.security.util.HexDumpEncoder; |
38 |
43 |
39 /** |
44 /** |
40 * This is the client key exchange message (CLIENT --> SERVER) used with |
45 * Pack of the "ClientKeyExchange" handshake message. |
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 */ |
46 */ |
49 final class RSAClientKeyExchange extends HandshakeMessage { |
47 final class RSAClientKeyExchange { |
50 |
48 static final SSLConsumer rsaHandshakeConsumer = |
51 /* |
49 new RSAClientKeyExchangeConsumer(); |
52 * The following field values were encrypted with the server's public |
50 static final HandshakeProducer rsaHandshakeProducer = |
53 * key (or temp key from server key exchange msg) and are presented |
51 new RSAClientKeyExchangeProducer(); |
54 * here in DECRYPTED form. |
52 |
|
53 /** |
|
54 * The RSA ClientKeyExchange handshake message. |
55 */ |
55 */ |
56 private ProtocolVersion protocolVersion; // preMaster [0,1] |
56 private static final |
57 SecretKey preMaster; |
57 class RSAClientKeyExchangeMessage extends HandshakeMessage { |
58 private byte[] encrypted; // same size as public modulus |
58 final int protocolVersion; |
59 |
59 final boolean useTLS10PlusSpec; |
60 /* |
60 final byte[] encrypted; |
61 * Client randomly creates a pre-master secret and encrypts it |
61 |
62 * using the server's RSA public key; only the server can decrypt |
62 RSAClientKeyExchangeMessage(HandshakeContext context, |
63 * it, using its RSA private key. Result is the same size as the |
63 RSAPremasterSecret premaster, |
64 * server's public key, and uses PKCS #1 block format 02. |
64 PublicKey publicKey) throws GeneralSecurityException { |
|
65 super(context); |
|
66 this.protocolVersion = context.clientHelloVersion; |
|
67 this.encrypted = premaster.getEncoded( |
|
68 publicKey, context.sslContext.getSecureRandom()); |
|
69 this.useTLS10PlusSpec = ProtocolVersion.useTLS10PlusSpec( |
|
70 protocolVersion, context.sslContext.isDTLS()); |
|
71 } |
|
72 |
|
73 RSAClientKeyExchangeMessage(HandshakeContext context, |
|
74 ByteBuffer m) throws IOException { |
|
75 super(context); |
|
76 |
|
77 if (m.remaining() < 2) { |
|
78 context.conContext.fatal(Alert.HANDSHAKE_FAILURE, |
|
79 "Invalid RSA ClientKeyExchange message: insufficient data"); |
|
80 } |
|
81 |
|
82 this.protocolVersion = context.clientHelloVersion; |
|
83 this.useTLS10PlusSpec = ProtocolVersion.useTLS10PlusSpec( |
|
84 protocolVersion, context.sslContext.isDTLS()); |
|
85 if (useTLS10PlusSpec) { |
|
86 this.encrypted = Record.getBytes16(m); |
|
87 } else { // SSL 3.0 |
|
88 this.encrypted = new byte[m.remaining()]; |
|
89 m.get(encrypted); |
|
90 } |
|
91 } |
|
92 |
|
93 @Override |
|
94 public SSLHandshake handshakeType() { |
|
95 return SSLHandshake.CLIENT_KEY_EXCHANGE; |
|
96 } |
|
97 |
|
98 @Override |
|
99 public int messageLength() { |
|
100 if (useTLS10PlusSpec) { |
|
101 return encrypted.length + 2; |
|
102 } else { |
|
103 return encrypted.length; |
|
104 } |
|
105 } |
|
106 |
|
107 @Override |
|
108 public void send(HandshakeOutStream hos) throws IOException { |
|
109 if (useTLS10PlusSpec) { |
|
110 hos.putBytes16(encrypted); |
|
111 } else { |
|
112 hos.write(encrypted); |
|
113 } |
|
114 } |
|
115 |
|
116 @Override |
|
117 public String toString() { |
|
118 MessageFormat messageFormat = new MessageFormat( |
|
119 "\"RSA ClientKeyExchange\": '{'\n" + |
|
120 " \"client_version\": {0}\n" + |
|
121 " \"encncrypted\": '{'\n" + |
|
122 "{1}\n" + |
|
123 " '}'\n" + |
|
124 "'}'", |
|
125 Locale.ENGLISH); |
|
126 |
|
127 HexDumpEncoder hexEncoder = new HexDumpEncoder(); |
|
128 Object[] messageFields = { |
|
129 ProtocolVersion.nameOf(protocolVersion), |
|
130 Utilities.indent( |
|
131 hexEncoder.encodeBuffer(encrypted), " "), |
|
132 }; |
|
133 return messageFormat.format(messageFields); |
|
134 } |
|
135 } |
|
136 |
|
137 /** |
|
138 * The RSA "ClientKeyExchange" handshake message producer. |
65 */ |
139 */ |
66 @SuppressWarnings("deprecation") |
140 private static final |
67 RSAClientKeyExchange(ProtocolVersion protocolVersion, |
141 class RSAClientKeyExchangeProducer implements HandshakeProducer { |
68 ProtocolVersion maxVersion, |
142 // Prevent instantiation of this class. |
69 SecureRandom generator, PublicKey publicKey) throws IOException { |
143 private RSAClientKeyExchangeProducer() { |
70 if (publicKey.getAlgorithm().equals("RSA") == false) { |
144 // blank |
71 throw new SSLKeyException("Public key not of type RSA: " + |
145 } |
72 publicKey.getAlgorithm()); |
146 |
73 } |
147 @Override |
74 this.protocolVersion = protocolVersion; |
148 public byte[] produce(ConnectionContext context, |
75 |
149 HandshakeMessage message) throws IOException { |
76 try { |
150 // This happens in client side only. |
77 String s = protocolVersion.useTLS12PlusSpec() ? |
151 ClientHandshakeContext chc = (ClientHandshakeContext)context; |
78 "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret"; |
152 |
79 KeyGenerator kg = JsseJce.getKeyGenerator(s); |
153 EphemeralRSACredentials rsaCredentials = null; |
80 kg.init(new TlsRsaPremasterSecretParameterSpec( |
154 X509Credentials x509Credentials = null; |
81 maxVersion.v, protocolVersion.v), generator); |
155 for (SSLCredentials credential : chc.handshakeCredentials) { |
82 preMaster = kg.generateKey(); |
156 if (credential instanceof EphemeralRSACredentials) { |
83 |
157 rsaCredentials = (EphemeralRSACredentials)credential; |
84 Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); |
158 if (x509Credentials != null) { |
85 cipher.init(Cipher.WRAP_MODE, publicKey, generator); |
159 break; |
86 encrypted = cipher.wrap(preMaster); |
160 } |
87 } catch (GeneralSecurityException e) { |
161 } else if (credential instanceof X509Credentials) { |
88 throw (SSLKeyException)new SSLKeyException |
162 x509Credentials = (X509Credentials)credential; |
89 ("RSA premaster secret error").initCause(e); |
163 if (rsaCredentials != null) { |
|
164 break; |
|
165 } |
|
166 } |
|
167 } |
|
168 |
|
169 if (rsaCredentials == null && x509Credentials == null) { |
|
170 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, |
|
171 "No RSA credentials negotiated for client key exchange"); |
|
172 } |
|
173 |
|
174 PublicKey publicKey = (rsaCredentials != null) ? |
|
175 rsaCredentials.popPublicKey : x509Credentials.popPublicKey; |
|
176 if (!publicKey.getAlgorithm().equals("RSA")) { // unlikely |
|
177 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, |
|
178 "Not RSA public key for client key exchange"); |
|
179 } |
|
180 |
|
181 RSAPremasterSecret premaster; |
|
182 RSAClientKeyExchangeMessage ckem; |
|
183 try { |
|
184 premaster = RSAPremasterSecret.createPremasterSecret(chc); |
|
185 chc.handshakePossessions.add(premaster); |
|
186 ckem = new RSAClientKeyExchangeMessage( |
|
187 chc, premaster, publicKey); |
|
188 } catch (GeneralSecurityException gse) { |
|
189 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, |
|
190 "Cannot generate RSA premaster secret", gse); |
|
191 |
|
192 return null; // make the compiler happy |
|
193 } |
|
194 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
|
195 SSLLogger.fine( |
|
196 "Produced RSA ClientKeyExchange handshake message", ckem); |
|
197 } |
|
198 |
|
199 // Output the handshake message. |
|
200 ckem.write(chc.handshakeOutput); |
|
201 chc.handshakeOutput.flush(); |
|
202 |
|
203 // update the states |
|
204 SSLKeyExchange ke = SSLKeyExchange.valueOf( |
|
205 chc.negotiatedCipherSuite.keyExchange, |
|
206 chc.negotiatedProtocol); |
|
207 if (ke == null) { // unlikely |
|
208 chc.conContext.fatal(Alert.INTERNAL_ERROR, |
|
209 "Not supported key exchange type"); |
|
210 } else { |
|
211 SSLKeyDerivation masterKD = ke.createKeyDerivation(chc); |
|
212 SecretKey masterSecret = |
|
213 masterKD.deriveKey("MasterSecret", null); |
|
214 |
|
215 // update the states |
|
216 chc.handshakeSession.setMasterSecret(masterSecret); |
|
217 SSLTrafficKeyDerivation kd = |
|
218 SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol); |
|
219 if (kd == null) { // unlikely |
|
220 chc.conContext.fatal(Alert.INTERNAL_ERROR, |
|
221 "Not supported key derivation: " + |
|
222 chc.negotiatedProtocol); |
|
223 } else { |
|
224 chc.handshakeKeyDerivation = |
|
225 kd.createKeyDerivation(chc, masterSecret); |
|
226 } |
|
227 } |
|
228 |
|
229 // The handshake message has been delivered. |
|
230 return null; |
90 } |
231 } |
91 } |
232 } |
92 |
233 |
93 /* |
234 /** |
94 * Retrieving the cipher's provider name for the debug purposes |
235 * The RSA "ClientKeyExchange" handshake message consumer. |
95 * can throw an exception by itself. |
|
96 */ |
236 */ |
97 private static String safeProviderName(Cipher cipher) { |
237 private static final |
98 try { |
238 class RSAClientKeyExchangeConsumer implements SSLConsumer { |
99 return cipher.getProvider().toString(); |
239 // Prevent instantiation of this class. |
100 } catch (Exception e) { |
240 private RSAClientKeyExchangeConsumer() { |
101 if (debug != null && Debug.isOn("handshake")) { |
241 // blank |
102 System.out.println("Retrieving The Cipher provider name" + |
242 } |
103 " caused exception " + e.getMessage()); |
243 |
104 } |
244 @Override |
105 } |
245 public void consume(ConnectionContext context, |
106 try { |
246 ByteBuffer message) throws IOException { |
107 return cipher.toString() + " (provider name not available)"; |
247 // The consuming happens in server side only. |
108 } catch (Exception e) { |
248 ServerHandshakeContext shc = (ServerHandshakeContext)context; |
109 if (debug != null && Debug.isOn("handshake")) { |
249 |
110 System.out.println("Retrieving The Cipher name" + |
250 EphemeralRSAPossession rsaPossession = null; |
111 " caused exception " + e.getMessage()); |
251 X509Possession x509Possession = null; |
112 } |
252 for (SSLPossession possession : shc.handshakePossessions) { |
113 } |
253 if (possession instanceof EphemeralRSAPossession) { |
114 return "(cipher/provider names not available)"; |
254 rsaPossession = (EphemeralRSAPossession)possession; |
115 } |
255 break; |
116 |
256 } else if (possession instanceof X509Possession) { |
117 /* |
257 x509Possession = (X509Possession)possession; |
118 * Server gets the PKCS #1 (block format 02) data, decrypts |
258 if (rsaPossession != null) { |
119 * it with its private key. |
259 break; |
120 */ |
260 } |
121 @SuppressWarnings("deprecation") |
261 } |
122 RSAClientKeyExchange(ProtocolVersion currentVersion, |
262 } |
123 ProtocolVersion maxVersion, |
263 |
124 SecureRandom generator, HandshakeInStream input, |
264 if (rsaPossession == null && x509Possession == null) { // unlikely |
125 int messageSize, PrivateKey privateKey) throws IOException { |
265 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, |
126 |
266 "No RSA possessions negotiated for client key exchange"); |
127 if (privateKey.getAlgorithm().equals("RSA") == false) { |
267 } |
128 throw new SSLKeyException("Private key not of type RSA: " + |
268 |
129 privateKey.getAlgorithm()); |
269 PrivateKey privateKey = (rsaPossession != null) ? |
130 } |
270 rsaPossession.popPrivateKey : x509Possession.popPrivateKey; |
131 |
271 if (!privateKey.getAlgorithm().equals("RSA")) { // unlikely |
132 if (currentVersion.useTLS10PlusSpec()) { |
272 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, |
133 encrypted = input.getBytes16(); |
273 "Not RSA private key for client key exchange"); |
134 } else { |
274 } |
135 encrypted = new byte [messageSize]; |
275 |
136 if (input.read(encrypted) != messageSize) { |
276 RSAClientKeyExchangeMessage ckem = |
137 throw new SSLProtocolException( |
277 new RSAClientKeyExchangeMessage(shc, message); |
138 "SSL: read PreMasterSecret: short read"); |
278 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
139 } |
279 SSLLogger.fine( |
140 } |
280 "Consuming RSA ClientKeyExchange handshake message", ckem); |
141 |
281 } |
142 byte[] encoded = null; |
282 |
143 try { |
283 // create the credentials |
144 boolean needFailover = false; |
284 RSAPremasterSecret premaster; |
145 Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); |
|
146 try { |
285 try { |
147 // Try UNWRAP_MODE mode firstly. |
286 premaster = |
148 cipher.init(Cipher.UNWRAP_MODE, privateKey, |
287 RSAPremasterSecret.decode(shc, privateKey, ckem.encrypted); |
149 new TlsRsaPremasterSecretParameterSpec( |
288 shc.handshakeCredentials.add(premaster); |
150 maxVersion.v, currentVersion.v), |
289 } catch (GeneralSecurityException gse) { |
151 generator); |
290 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, |
152 |
291 "Cannot decode RSA premaster secret", gse); |
153 // The provider selection can be delayed, please don't call |
292 } |
154 // any Cipher method before the call to Cipher.init(). |
293 |
155 needFailover = !KeyUtil.isOracleJCEProvider( |
294 // update the states |
156 cipher.getProvider().getName()); |
295 SSLKeyExchange ke = SSLKeyExchange.valueOf( |
157 } catch (InvalidKeyException | UnsupportedOperationException iue) { |
296 shc.negotiatedCipherSuite.keyExchange, |
158 if (debug != null && Debug.isOn("handshake")) { |
297 shc.negotiatedProtocol); |
159 System.out.println("The Cipher provider " |
298 if (ke == null) { // unlikely |
160 + safeProviderName(cipher) |
299 shc.conContext.fatal(Alert.INTERNAL_ERROR, |
161 + " caused exception: " + iue.getMessage()); |
300 "Not supported key exchange type"); |
|
301 } else { |
|
302 SSLKeyDerivation masterKD = ke.createKeyDerivation(shc); |
|
303 SecretKey masterSecret = |
|
304 masterKD.deriveKey("MasterSecret", null); |
|
305 |
|
306 // update the states |
|
307 shc.handshakeSession.setMasterSecret(masterSecret); |
|
308 SSLTrafficKeyDerivation kd = |
|
309 SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol); |
|
310 if (kd == null) { // unlikely |
|
311 shc.conContext.fatal(Alert.INTERNAL_ERROR, |
|
312 "Not supported key derivation: " + |
|
313 shc.negotiatedProtocol); |
|
314 } else { |
|
315 shc.handshakeKeyDerivation = |
|
316 kd.createKeyDerivation(shc, masterSecret); |
162 } |
317 } |
163 |
318 } |
164 needFailover = true; |
319 } |
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 } |
320 } |
269 } |
321 } |