blob: c2c45d8afaf7c7458efb0217f0ff5ea382b15c3e [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1996-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26
27package sun.security.ssl;
28
29import java.io.*;
30import java.security.*;
31import java.security.interfaces.*;
32
33import javax.crypto.*;
34import javax.crypto.spec.*;
35
36import javax.net.ssl.*;
37
38import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
39
40/**
41 * This is the client key exchange message (CLIENT --> SERVER) used with
42 * all RSA key exchanges; it holds the RSA-encrypted pre-master secret.
43 *
44 * The message is encrypted using PKCS #1 block type 02 encryption with the
45 * server's public key. The padding and resulting message size is a function
46 * of this server's public key modulus size, but the pre-master secret is
47 * always exactly 48 bytes.
48 *
49 */
50final class RSAClientKeyExchange extends HandshakeMessage {
51
52 /**
53 * The TLS spec says that the version in the RSA premaster secret must
54 * be the maximum version supported by the client (i.e. the version it
55 * requested in its client hello version). However, we (and other
56 * implementations) used to send the active negotiated version. The
57 * system property below allows to toggle the behavior.
58 *
59 * Default is "false" (old behavior) for compatibility reasons. This
60 * will be changed in the future.
61 */
62 private final static String PROP_NAME =
63 "com.sun.net.ssl.rsaPreMasterSecretFix";
64
65 private final static boolean rsaPreMasterSecretFix =
66 Debug.getBooleanProperty(PROP_NAME, false);
67
68 int messageType() {
69 return ht_client_key_exchange;
70 }
71
72 /*
73 * The following field values were encrypted with the server's public
74 * key (or temp key from server key exchange msg) and are presented
75 * here in DECRYPTED form.
76 */
77 private ProtocolVersion protocolVersion; // preMaster [0,1]
78 SecretKey preMaster;
79 private byte[] encrypted; // same size as public modulus
80
81
82 /*
83 * Client randomly creates a pre-master secret and encrypts it
84 * using the server's RSA public key; only the server can decrypt
85 * it, using its RSA private key. Result is the same size as the
86 * server's public key, and uses PKCS #1 block format 02.
87 */
88 RSAClientKeyExchange(ProtocolVersion protocolVersion, ProtocolVersion maxVersion,
89 SecureRandom generator, PublicKey publicKey) throws IOException {
90 if (publicKey.getAlgorithm().equals("RSA") == false) {
91 throw new SSLKeyException("Public key not of type RSA");
92 }
93 this.protocolVersion = protocolVersion;
94
95 int major, minor;
96
97 if (rsaPreMasterSecretFix) {
98 major = maxVersion.major;
99 minor = maxVersion.minor;
100 } else {
101 major = protocolVersion.major;
102 minor = protocolVersion.minor;
103 }
104
105 try {
106 KeyGenerator kg = JsseJce.getKeyGenerator("SunTlsRsaPremasterSecret");
107 kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor));
108 preMaster = kg.generateKey();
109
110 Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
111 cipher.init(Cipher.WRAP_MODE, publicKey, generator);
112 encrypted = cipher.wrap(preMaster);
113 } catch (GeneralSecurityException e) {
114 throw (SSLKeyException)new SSLKeyException
115 ("RSA premaster secret error").initCause(e);
116 }
117 }
118
119 /*
120 * Server gets the PKCS #1 (block format 02) data, decrypts
121 * it with its private key.
122 */
123 RSAClientKeyExchange(ProtocolVersion currentVersion, HandshakeInStream input,
124 int messageSize, PrivateKey privateKey) throws IOException {
125
126 if (privateKey.getAlgorithm().equals("RSA") == false) {
127 throw new SSLKeyException("Private key not of type RSA");
128 }
129
130 this.protocolVersion = currentVersion;
131 if (currentVersion.v >= ProtocolVersion.TLS10.v) {
132 encrypted = input.getBytes16();
133 } else {
134 encrypted = new byte [messageSize];
135 if (input.read(encrypted) != messageSize) {
136 throw new SSLProtocolException
137 ("SSL: read PreMasterSecret: short read");
138 }
139 }
140
141 try {
142 Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
143 cipher.init(Cipher.UNWRAP_MODE, privateKey);
144 preMaster = (SecretKey)cipher.unwrap(encrypted,
145 "TlsRsaPremasterSecret", Cipher.SECRET_KEY);
146 } catch (Exception e) {
147 /*
148 * Bogus decrypted ClientKeyExchange? If so, conjure a
149 * a random preMaster secret that will fail later during
150 * Finished message processing. This is a countermeasure against
151 * the "interactive RSA PKCS#1 encryption envelop attack" reported
152 * in June 1998. Preserving the executation path will
153 * mitigate timing attacks and force consistent error handling
154 * that will prevent an attacking client from differentiating
155 * different kinds of decrypted ClientKeyExchange bogosities.
156 */
157 if (debug != null && Debug.isOn("handshake")) {
158 System.out.println("Error decrypting premaster secret:");
159 e.printStackTrace(System.out);
160 System.out.println("Generating random secret");
161 }
162 preMaster = generateDummySecret(currentVersion);
163 }
164 }
165
166 // generate a premaster secret with the specified version number
167 static SecretKey generateDummySecret(ProtocolVersion version) {
168 try {
169 KeyGenerator kg =
170 JsseJce.getKeyGenerator("SunTlsRsaPremasterSecret");
171 kg.init(new TlsRsaPremasterSecretParameterSpec
172 (version.major, version.minor));
173 return kg.generateKey();
174 } catch (GeneralSecurityException e) {
175 throw new RuntimeException("Could not generate dummy secret", e);
176 }
177 }
178
179 int messageLength() {
180 if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
181 return encrypted.length + 2;
182 } else {
183 return encrypted.length;
184 }
185 }
186
187 void send(HandshakeOutStream s) throws IOException {
188 if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
189 s.putBytes16(encrypted);
190 } else {
191 s.write(encrypted);
192 }
193 }
194
195 void print(PrintStream s) throws IOException {
196 s.println("*** ClientKeyExchange, RSA PreMasterSecret, " + protocolVersion);
197 }
198}