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 }