• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 1996, 2012, 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 
27 package sun.security.ssl;
28 
29 import java.io.*;
30 import java.security.*;
31 import java.security.interfaces.*;
32 
33 import javax.crypto.*;
34 import javax.crypto.spec.*;
35 
36 import javax.net.ssl.*;
37 
38 import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
39 import sun.security.util.KeyUtil;
40 
41 /**
42  * This is the client key exchange message (CLIENT --> SERVER) used with
43  * all RSA key exchanges; it holds the RSA-encrypted pre-master secret.
44  *
45  * The message is encrypted using PKCS #1 block type 02 encryption with the
46  * server's public key.  The padding and resulting message size is a function
47  * of this server's public key modulus size, but the pre-master secret is
48  * always exactly 48 bytes.
49  *
50  */
51 final class RSAClientKeyExchange extends HandshakeMessage {
52 
53     /**
54      * The TLS spec says that the version in the RSA premaster secret must
55      * be the maximum version supported by the client (i.e. the version it
56      * requested in its client hello version). However, we (and other
57      * implementations) used to send the active negotiated version. The
58      * system property below allows to toggle the behavior.
59      */
60     private final static String PROP_NAME =
61                                 "com.sun.net.ssl.rsaPreMasterSecretFix";
62 
63     /*
64      * Default is "false" (old behavior) for compatibility reasons in
65      * SSLv3/TLSv1.  Later protocols (TLSv1.1+) do not use this property.
66      */
67     private final static boolean rsaPreMasterSecretFix =
68                                 Debug.getBooleanProperty(PROP_NAME, false);
69 
70     /*
71      * The following field values were encrypted with the server's public
72      * key (or temp key from server key exchange msg) and are presented
73      * here in DECRYPTED form.
74      */
75     private ProtocolVersion protocolVersion; // preMaster [0,1]
76     SecretKey preMaster;
77     private byte[] encrypted;           // same size as public modulus
78 
79     /*
80      * Client randomly creates a pre-master secret and encrypts it
81      * using the server's RSA public key; only the server can decrypt
82      * it, using its RSA private key.  Result is the same size as the
83      * server's public key, and uses PKCS #1 block format 02.
84      */
RSAClientKeyExchange(ProtocolVersion protocolVersion, ProtocolVersion maxVersion, SecureRandom generator, PublicKey publicKey)85     RSAClientKeyExchange(ProtocolVersion protocolVersion,
86             ProtocolVersion maxVersion,
87             SecureRandom generator, PublicKey publicKey) throws IOException {
88         if (publicKey.getAlgorithm().equals("RSA") == false) {
89             throw new SSLKeyException("Public key not of type RSA");
90         }
91         this.protocolVersion = protocolVersion;
92 
93         int major, minor;
94 
95         if (rsaPreMasterSecretFix || maxVersion.v >= ProtocolVersion.TLS11.v) {
96             major = maxVersion.major;
97             minor = maxVersion.minor;
98         } else {
99             major = protocolVersion.major;
100             minor = protocolVersion.minor;
101         }
102 
103         try {
104             String s = ((protocolVersion.v >= ProtocolVersion.TLS12.v) ?
105                 "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret");
106             KeyGenerator kg = JsseJce.getKeyGenerator(s);
107             kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor),
108                     generator);
109             preMaster = kg.generateKey();
110 
111             Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
112             cipher.init(Cipher.WRAP_MODE, publicKey, generator);
113             encrypted = cipher.wrap(preMaster);
114         } catch (GeneralSecurityException e) {
115             throw (SSLKeyException)new SSLKeyException
116                                 ("RSA premaster secret error").initCause(e);
117         }
118     }
119 
120     /*
121      * Server gets the PKCS #1 (block format 02) data, decrypts
122      * it with its private key.
123      */
RSAClientKeyExchange(ProtocolVersion currentVersion, ProtocolVersion maxVersion, SecureRandom generator, HandshakeInStream input, int messageSize, PrivateKey privateKey)124     RSAClientKeyExchange(ProtocolVersion currentVersion,
125             ProtocolVersion maxVersion,
126             SecureRandom generator, HandshakeInStream input,
127             int messageSize, PrivateKey privateKey) throws IOException {
128 
129         if (privateKey.getAlgorithm().equals("RSA") == false) {
130             throw new SSLKeyException("Private key not of type RSA");
131         }
132 
133         if (currentVersion.v >= ProtocolVersion.TLS10.v) {
134             encrypted = input.getBytes16();
135         } else {
136             encrypted = new byte [messageSize];
137             if (input.read(encrypted) != messageSize) {
138                 throw new SSLProtocolException
139                         ("SSL: read PreMasterSecret: short read");
140             }
141         }
142 
143         try {
144             Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
145             cipher.init(Cipher.UNWRAP_MODE, privateKey);
146             preMaster = (SecretKey)cipher.unwrap(encrypted,
147                                 "TlsRsaPremasterSecret", Cipher.SECRET_KEY);
148 
149             // polish the premaster secret
150             preMaster = polishPreMasterSecretKey(currentVersion, maxVersion,
151                                                 generator, preMaster, null);
152         } catch (Exception e) {
153             // polish the premaster secret
154             preMaster =
155                     polishPreMasterSecretKey(currentVersion, maxVersion,
156                                                 generator, null, e);
157         }
158     }
159 
160     /**
161      * To avoid vulnerabilities described by section 7.4.7.1, RFC 5246,
162      * treating incorrectly formatted message blocks and/or mismatched
163      * version numbers in a manner indistinguishable from correctly
164      * formatted RSA blocks.
165      *
166      * RFC 5246 describes the approach as :
167      *
168      *  1. Generate a string R of 46 random bytes
169      *
170      *  2. Decrypt the message to recover the plaintext M
171      *
172      *  3. If the PKCS#1 padding is not correct, or the length of message
173      *     M is not exactly 48 bytes:
174      *        pre_master_secret = ClientHello.client_version || R
175      *     else If ClientHello.client_version <= TLS 1.0, and version
176      *     number check is explicitly disabled:
177      *        pre_master_secret = M
178      *     else:
179      *        pre_master_secret = ClientHello.client_version || M[2..47]
180      */
polishPreMasterSecretKey(ProtocolVersion currentVersion, ProtocolVersion clientHelloVersion, SecureRandom generator, SecretKey secretKey, Exception failoverException)181     private SecretKey polishPreMasterSecretKey(ProtocolVersion currentVersion,
182             ProtocolVersion clientHelloVersion, SecureRandom generator,
183             SecretKey secretKey, Exception failoverException) {
184 
185         this.protocolVersion = clientHelloVersion;
186 
187         if (failoverException == null && secretKey != null) {
188             // check the length
189             byte[] encoded = secretKey.getEncoded();
190             if (encoded == null) {      // unable to get the encoded key
191                 if (debug != null && Debug.isOn("handshake")) {
192                     System.out.println(
193                         "unable to get the plaintext of the premaster secret");
194                 }
195 
196                 int keySize = KeyUtil.getKeySize(secretKey);
197                 if (keySize > 0 && keySize != 384) {       // 384 = 48 * 8
198                     if (debug != null && Debug.isOn("handshake")) {
199                         System.out.println(
200                             "incorrect length of premaster secret: " +
201                             (keySize/8));
202                     }
203 
204                     return generateDummySecret(clientHelloVersion);
205                 }
206 
207                 // The key size is exactly 48 bytes or not accessible.
208                 //
209                 // Conservatively, pass the checking to master secret
210                 // calculation.
211                 return secretKey;
212             } else if (encoded.length == 48) {
213                 // check the version
214                 if (clientHelloVersion.major == encoded[0] &&
215                     clientHelloVersion.minor == encoded[1]) {
216 
217                     return secretKey;
218                 } else if (clientHelloVersion.v <= ProtocolVersion.TLS10.v &&
219                            currentVersion.major == encoded[0] &&
220                            currentVersion.minor == encoded[1]) {
221                     /*
222                      * For compatibility, we maintain the behavior that the
223                      * version in pre_master_secret can be the negotiated
224                      * version for TLS v1.0 and SSL v3.0.
225                      */
226                     this.protocolVersion = currentVersion;
227                     return secretKey;
228                 }
229 
230                 if (debug != null && Debug.isOn("handshake")) {
231                     System.out.println("Mismatching Protocol Versions, " +
232                         "ClientHello.client_version is " + clientHelloVersion +
233                         ", while PreMasterSecret.client_version is " +
234                         ProtocolVersion.valueOf(encoded[0], encoded[1]));
235                 }
236 
237                 return generateDummySecret(clientHelloVersion);
238             } else {
239                 if (debug != null && Debug.isOn("handshake")) {
240                     System.out.println(
241                         "incorrect length of premaster secret: " +
242                         encoded.length);
243                 }
244 
245                 return generateDummySecret(clientHelloVersion);
246             }
247         }
248 
249         if (debug != null && Debug.isOn("handshake") &&
250                     failoverException != null) {
251             System.out.println("Error decrypting premaster secret:");
252             failoverException.printStackTrace(System.out);
253         }
254 
255         return generateDummySecret(clientHelloVersion);
256     }
257 
258     // generate a premaster secret with the specified version number
generateDummySecret(ProtocolVersion version)259     static SecretKey generateDummySecret(ProtocolVersion version) {
260         if (debug != null && Debug.isOn("handshake")) {
261             System.out.println("Generating a random fake premaster secret");
262         }
263 
264         try {
265             String s = ((version.v >= ProtocolVersion.TLS12.v) ?
266                 "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret");
267             KeyGenerator kg = JsseJce.getKeyGenerator(s);
268             kg.init(new TlsRsaPremasterSecretParameterSpec
269                     (version.major, version.minor));
270             return kg.generateKey();
271         } catch (GeneralSecurityException e) {
272             throw new RuntimeException("Could not generate dummy secret", e);
273         }
274     }
275 
276     @Override
messageType()277     int messageType() {
278         return ht_client_key_exchange;
279     }
280 
281     @Override
messageLength()282     int messageLength() {
283         if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
284             return encrypted.length + 2;
285         } else {
286             return encrypted.length;
287         }
288     }
289 
290     @Override
send(HandshakeOutStream s)291     void send(HandshakeOutStream s) throws IOException {
292         if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
293             s.putBytes16(encrypted);
294         } else {
295             s.write(encrypted);
296         }
297     }
298 
299     @Override
print(PrintStream s)300     void print(PrintStream s) throws IOException {
301         s.println("*** ClientKeyExchange, RSA PreMasterSecret, " +
302                                                         protocolVersion);
303     }
304 }
305