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