1 /*
   2  * Copyright (c) 2003, 2018, 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 package sun.security.ssl;
  27 
  28 import java.io.IOException;
  29 import java.nio.ByteBuffer;
  30 import java.security.GeneralSecurityException;
  31 import java.security.PrivateKey;
  32 import java.security.PublicKey;
  33 import java.text.MessageFormat;
  34 import java.util.Locale;
  35 import javax.crypto.SecretKey;
  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;
  43 
  44 /**
  45  * Pack of the "ClientKeyExchange" handshake message.
  46  */
  47 final class RSAClientKeyExchange {
  48     static final SSLConsumer rsaHandshakeConsumer =
  49         new RSAClientKeyExchangeConsumer();
  50     static final HandshakeProducer rsaHandshakeProducer =
  51         new RSAClientKeyExchangeProducer();
  52 
  53     /**
  54      * The RSA ClientKeyExchange handshake message.
  55      */
  56     private static final
  57             class RSAClientKeyExchangeMessage extends HandshakeMessage {
  58         final int protocolVersion;
  59         final boolean useTLS10PlusSpec;
  60         final byte[] encrypted;
  61 
  62         RSAClientKeyExchangeMessage(HandshakeContext context,
  63                 RSAPremasterSecret premaster,
  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             // This happens in server side only.
  77             ServerHandshakeContext shc =
  78                     (ServerHandshakeContext)handshakeContext;
  79 
  80             if (m.remaining() < 2) {
  81                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
  82                     "Invalid RSA ClientKeyExchange message: insufficient data");
  83             }
  84 
  85             this.protocolVersion = context.clientHelloVersion;
  86             this.useTLS10PlusSpec = ProtocolVersion.useTLS10PlusSpec(
  87                     protocolVersion, context.sslContext.isDTLS());
  88             if (useTLS10PlusSpec) {
  89                 this.encrypted = Record.getBytes16(m);
  90             } else {    //  SSL 3.0
  91                 this.encrypted = new byte[m.remaining()];
  92                 m.get(encrypted);
  93             }
  94         }
  95 
  96         @Override
  97         public SSLHandshake handshakeType() {
  98             return SSLHandshake.CLIENT_KEY_EXCHANGE;
  99         }
 100 
 101         @Override
 102         public int messageLength() {
 103             if (useTLS10PlusSpec) {
 104                 return encrypted.length + 2;
 105             } else {
 106                 return encrypted.length;
 107             }
 108         }
 109 
 110         @Override
 111         public void send(HandshakeOutStream hos) throws IOException {
 112             if (useTLS10PlusSpec) {
 113                 hos.putBytes16(encrypted);
 114             } else {
 115                 hos.write(encrypted);
 116             }
 117         }
 118 
 119         @Override
 120         public String toString() {
 121             MessageFormat messageFormat = new MessageFormat(
 122                 "\"RSA ClientKeyExchange\": '{'\n" +
 123                 "  \"client_version\":  {0}\n" +
 124                 "  \"encncrypted\": '{'\n" +
 125                 "{1}\n" +
 126                 "  '}'\n" +
 127                 "'}'",
 128                 Locale.ENGLISH);
 129 
 130             HexDumpEncoder hexEncoder = new HexDumpEncoder();
 131             Object[] messageFields = {
 132                 ProtocolVersion.nameOf(protocolVersion),
 133                 Utilities.indent(
 134                         hexEncoder.encodeBuffer(encrypted), "    "),
 135             };
 136             return messageFormat.format(messageFields);
 137         }
 138     }
 139 
 140     /**
 141      * The RSA "ClientKeyExchange" handshake message producer.
 142      */
 143     private static final
 144             class RSAClientKeyExchangeProducer implements HandshakeProducer {
 145         // Prevent instantiation of this class.
 146         private RSAClientKeyExchangeProducer() {
 147             // blank
 148         }
 149 
 150         @Override
 151         public byte[] produce(ConnectionContext context,
 152                 HandshakeMessage message) throws IOException {
 153             // This happens in client side only.
 154             ClientHandshakeContext chc = (ClientHandshakeContext)context;
 155 
 156             EphemeralRSACredentials rsaCredentials = null;
 157             X509Credentials x509Credentials = null;
 158             for (SSLCredentials credential : chc.handshakeCredentials) {
 159                 if (credential instanceof EphemeralRSACredentials) {
 160                     rsaCredentials = (EphemeralRSACredentials)credential;
 161                     if (x509Credentials != null) {
 162                         break;
 163                     }
 164                 } else if (credential instanceof X509Credentials) {
 165                     x509Credentials = (X509Credentials)credential;
 166                     if (rsaCredentials != null) {
 167                         break;
 168                     }
 169                 }
 170             }
 171 
 172             if (rsaCredentials == null && x509Credentials == null) {
 173                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 174                     "No RSA credentials negotiated for client key exchange");
 175             }
 176 
 177             PublicKey publicKey = (rsaCredentials != null) ?
 178                     rsaCredentials.popPublicKey : x509Credentials.popPublicKey;
 179             if (!publicKey.getAlgorithm().equals("RSA")) {      // unlikely
 180                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 181                     "Not RSA public key for client key exchange");
 182             }
 183 
 184             RSAPremasterSecret premaster;
 185             RSAClientKeyExchangeMessage ckem;
 186             try {
 187                 premaster = RSAPremasterSecret.createPremasterSecret(chc);
 188                 chc.handshakePossessions.add(premaster);
 189                 ckem = new RSAClientKeyExchangeMessage(
 190                         chc, premaster, publicKey);
 191             } catch (GeneralSecurityException gse) {
 192                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 193                     "Cannot generate RSA premaster secret", gse);
 194 
 195                 return null;    // make the compiler happy
 196             }
 197             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 198                 SSLLogger.fine(
 199                     "Produced RSA ClientKeyExchange handshake message", ckem);
 200             }
 201 
 202             // Output the handshake message.
 203             ckem.write(chc.handshakeOutput);
 204             chc.handshakeOutput.flush();
 205 
 206             // update the states
 207             SSLKeyExchange ke =
 208                 SSLKeyExchange.valueOf(chc.negotiatedCipherSuite.keyExchange);
 209             if (ke == null) {   // unlikely
 210                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
 211                         "Not supported key exchange type");
 212             } else {
 213                 SSLKeyDerivation masterKD = ke.createKeyDerivation(chc);
 214                 SecretKey masterSecret = masterKD.deriveKey("TODO", null);
 215 
 216                 // update the states
 217                 chc.handshakeSession.setMasterSecret(masterSecret);
 218                 SSLTrafficKeyDerivation kd =
 219                         SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);
 220                 if (kd == null) {   // unlikely
 221                     chc.conContext.fatal(Alert.INTERNAL_ERROR,
 222                             "Not supported key derivation: " +
 223                             chc.negotiatedProtocol);
 224                 } else {
 225                     chc.handshakeKeyDerivation =
 226                         kd.createKeyDerivation(chc, masterSecret);
 227                 }
 228             }
 229 
 230             // The handshake message has been delivered.
 231             return null;
 232         }
 233     }
 234 
 235     /**
 236      * The RSA "ClientKeyExchange" handshake message consumer.
 237      */
 238     private static final
 239             class RSAClientKeyExchangeConsumer implements SSLConsumer {
 240         // Prevent instantiation of this class.
 241         private RSAClientKeyExchangeConsumer() {
 242             // blank
 243         }
 244 
 245         @Override
 246         public void consume(ConnectionContext context,
 247                 ByteBuffer message) throws IOException {
 248             // The consuming happens in server side only.
 249             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 250 
 251             EphemeralRSAPossession rsaPossession = null;
 252             X509Possession x509Possession = null;
 253             for (SSLPossession possession : shc.handshakePossessions) {
 254                 if (possession instanceof EphemeralRSAPossession) {
 255                     rsaPossession = (EphemeralRSAPossession)possession;
 256                     break;
 257                 } else if (possession instanceof X509Possession) {
 258                     x509Possession = (X509Possession)possession;
 259                     if (rsaPossession != null) {
 260                         break;
 261                     }
 262                 }
 263             }
 264 
 265             if (rsaPossession == null && x509Possession == null) {  // unlikely
 266                 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 267                     "No RSA possessions negotiated for client key exchange");
 268             }
 269 
 270             PrivateKey privateKey = (rsaPossession != null) ?
 271                     rsaPossession.popPrivateKey : x509Possession.popPrivateKey;
 272             if (!privateKey.getAlgorithm().equals("RSA")) {     // unlikely
 273                 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 274                     "Not RSA private key for client key exchange");
 275             }
 276 
 277             RSAClientKeyExchangeMessage ckem =
 278                     new RSAClientKeyExchangeMessage(shc, message);
 279             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 280                 SSLLogger.fine(
 281                     "Consuming RSA ClientKeyExchange handshake message", ckem);
 282             }
 283 
 284             // create the credentials
 285             RSAPremasterSecret premaster;
 286             try {
 287                 premaster =
 288                     RSAPremasterSecret.decode(shc, privateKey, ckem.encrypted);
 289                 shc.handshakeCredentials.add(premaster);
 290             } catch (GeneralSecurityException gse) {
 291                 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 292                     "Cannot decode RSA premaster secret", gse);
 293             }
 294 
 295             // update the states
 296             SSLKeyExchange ke =
 297                 SSLKeyExchange.valueOf(shc.negotiatedCipherSuite.keyExchange);
 298             if (ke == null) {   // unlikely
 299                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
 300                         "Not supported key exchange type");
 301             } else {
 302                 SSLKeyDerivation masterKD = ke.createKeyDerivation(shc);
 303                 SecretKey masterSecret = masterKD.deriveKey("TODO", null);
 304 
 305                 // update the states
 306                 shc.handshakeSession.setMasterSecret(masterSecret);
 307                 SSLTrafficKeyDerivation kd =
 308                         SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);
 309                 if (kd == null) {       // unlikely
 310                     shc.conContext.fatal(Alert.INTERNAL_ERROR,
 311                             "Not supported key derivation: " +
 312                             shc.negotiatedProtocol);
 313                 } else {
 314                     shc.handshakeKeyDerivation =
 315                         kd.createKeyDerivation(shc, masterSecret);
 316                 }
 317             }
 318         }
 319     }
 320 }