RSAClientKeyExchange.java revision 12072:6721ff11d592
1/*
2 * Copyright (c) 1996, 2014, 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        }
73        this.protocolVersion = protocolVersion;
74
75        try {
76            String s = protocolVersion.useTLS12PlusSpec() ?
77                "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret";
78            KeyGenerator kg = JsseJce.getKeyGenerator(s);
79            kg.init(new TlsRsaPremasterSecretParameterSpec(
80                    maxVersion.v, protocolVersion.v), generator);
81            preMaster = kg.generateKey();
82
83            Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
84            cipher.init(Cipher.WRAP_MODE, publicKey, generator);
85            encrypted = cipher.wrap(preMaster);
86        } catch (GeneralSecurityException e) {
87            throw (SSLKeyException)new SSLKeyException
88                                ("RSA premaster secret error").initCause(e);
89        }
90    }
91
92    /*
93     * Server gets the PKCS #1 (block format 02) data, decrypts
94     * it with its private key.
95     */
96    @SuppressWarnings("deprecation")
97    RSAClientKeyExchange(ProtocolVersion currentVersion,
98            ProtocolVersion maxVersion,
99            SecureRandom generator, HandshakeInStream input,
100            int messageSize, PrivateKey privateKey) throws IOException {
101
102        if (privateKey.getAlgorithm().equals("RSA") == false) {
103            throw new SSLKeyException("Private key not of type RSA");
104        }
105
106        if (currentVersion.useTLS10PlusSpec()) {
107            encrypted = input.getBytes16();
108        } else {
109            encrypted = new byte [messageSize];
110            if (input.read(encrypted) != messageSize) {
111                throw new SSLProtocolException(
112                        "SSL: read PreMasterSecret: short read");
113            }
114        }
115
116        try {
117            Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
118            cipher.init(Cipher.UNWRAP_MODE, privateKey,
119                    new TlsRsaPremasterSecretParameterSpec(
120                            maxVersion.v, currentVersion.v),
121                    generator);
122            preMaster = (SecretKey)cipher.unwrap(encrypted,
123                                "TlsRsaPremasterSecret", Cipher.SECRET_KEY);
124        } catch (InvalidKeyException ibk) {
125            // the message is too big to process with RSA
126            throw new SSLProtocolException(
127                "Unable to process PreMasterSecret, may be too big");
128        } catch (Exception e) {
129            // unlikely to happen, otherwise, must be a provider exception
130            if (debug != null && Debug.isOn("handshake")) {
131                System.out.println("RSA premaster secret decryption error:");
132                e.printStackTrace(System.out);
133            }
134            throw new RuntimeException("Could not generate dummy secret", e);
135        }
136    }
137
138    @Override
139    int messageType() {
140        return ht_client_key_exchange;
141    }
142
143    @Override
144    int messageLength() {
145        if (protocolVersion.useTLS10PlusSpec()) {
146            return encrypted.length + 2;
147        } else {
148            return encrypted.length;
149        }
150    }
151
152    @Override
153    void send(HandshakeOutStream s) throws IOException {
154        if (protocolVersion.useTLS10PlusSpec()) {
155            s.putBytes16(encrypted);
156        } else {
157            s.write(encrypted);
158        }
159    }
160
161    @Override
162    void print(PrintStream s) throws IOException {
163        s.println("*** ClientKeyExchange, RSA PreMasterSecret, " +
164                                                        protocolVersion);
165    }
166}
167