Showing the changes to java/pkg/sun/security/ssl/ClientHandshaker.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,1341 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1996, 2011, 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.*; | ||
| 29 | import java.math.BigInteger; | ||
| 30 | import java.security.*; | ||
| 31 | import java.util.*; | ||
| 32 | |||
| 33 | import java.security.interfaces.ECPublicKey; | ||
| 34 | import java.security.interfaces.RSAPublicKey; | ||
| 35 | import java.security.spec.ECParameterSpec; | ||
| 36 | |||
| 37 | import java.security.cert.X509Certificate; | ||
| 38 | import java.security.cert.CertificateException; | ||
| 39 | |||
| 40 | import javax.crypto.SecretKey; | ||
| 41 | import javax.crypto.spec.SecretKeySpec; | ||
| 42 | |||
| 43 | import javax.net.ssl.*; | ||
| 44 | |||
| 45 | import javax.security.auth.Subject; | ||
| 46 | |||
| 47 | import sun.security.ssl.HandshakeMessage.*; | ||
| 48 | import sun.security.ssl.CipherSuite.*; | ||
| 49 | import static sun.security.ssl.CipherSuite.KeyExchange.*; | ||
| 50 | |||
| 51 | import sun.net.util.IPAddressUtil; | ||
| 52 | |||
| 53 | /** | ||
| 54 | * ClientHandshaker does the protocol handshaking from the point | ||
| 55 | * of view of a client. It is driven asychronously by handshake messages | ||
| 56 | * as delivered by the parent Handshaker class, and also uses | ||
| 57 | * common functionality (e.g. key generation) that is provided there. | ||
| 58 | * | ||
| 59 | * @author David Brownell | ||
| 60 | */ | ||
| 61 | final class ClientHandshaker extends Handshaker { | ||
| 62 | |||
| 63 | // the server's public key from its certificate. | ||
| 64 | private PublicKey serverKey; | ||
| 65 | |||
| 66 | // the server's ephemeral public key from the server key exchange message | ||
| 67 | // for ECDHE/ECDH_anon and RSA_EXPORT. | ||
| 68 | private PublicKey ephemeralServerKey; | ||
| 69 | |||
| 70 | // server's ephemeral public value for DHE/DH_anon key exchanges | ||
| 71 | private BigInteger serverDH; | ||
| 72 | |||
| 73 | private DHCrypt dh; | ||
| 74 | |||
| 75 | private ECDHCrypt ecdh; | ||
| 76 | |||
| 77 | private CertificateRequest certRequest; | ||
| 78 | |||
| 79 | private boolean serverKeyExchangeReceived; | ||
| 80 | |||
| 81 | /* | ||
| 82 | * The RSA PreMasterSecret needs to know the version of | ||
| 83 | * ClientHello that was used on this handshake. This represents | ||
| 84 | * the "max version" this client is supporting. In the | ||
| 85 | * case of an initial handshake, it's the max version enabled, | ||
| 86 | * but in the case of a resumption attempt, it's the version | ||
| 87 | * of the session we're trying to resume. | ||
| 88 | */ | ||
| 89 | private ProtocolVersion maxProtocolVersion; | ||
| 90 | |||
| 91 | // To switch off the SNI extension. | ||
| 92 | private final static boolean enableSNIExtension = | ||
| 93 | Debug.getBooleanProperty("jsse.enableSNIExtension", true); | ||
| 94 | |||
| 95 | /* | ||
| 96 | * Constructors | ||
| 97 | */ | ||
| 98 | ClientHandshaker(SSLSocketImpl socket, SSLContextImpl context, | ||
| 99 | ProtocolList enabledProtocols, | ||
| 100 | ProtocolVersion activeProtocolVersion, | ||
| 101 | boolean isInitialHandshake, boolean secureRenegotiation, | ||
| 102 | byte[] clientVerifyData, byte[] serverVerifyData) { | ||
| 103 | |||
| 104 | super(socket, context, enabledProtocols, true, true, | ||
| 105 | activeProtocolVersion, isInitialHandshake, secureRenegotiation, | ||
| 106 | clientVerifyData, serverVerifyData); | ||
| 107 | } | ||
| 108 | |||
| 109 | ClientHandshaker(SSLEngineImpl engine, SSLContextImpl context, | ||
| 110 | ProtocolList enabledProtocols, | ||
| 111 | ProtocolVersion activeProtocolVersion, | ||
| 112 | boolean isInitialHandshake, boolean secureRenegotiation, | ||
| 113 | byte[] clientVerifyData, byte[] serverVerifyData) { | ||
| 114 | |||
| 115 | super(engine, context, enabledProtocols, true, true, | ||
| 116 | activeProtocolVersion, isInitialHandshake, secureRenegotiation, | ||
| 117 | clientVerifyData, serverVerifyData); | ||
| 118 | } | ||
| 119 | |||
| 120 | /* | ||
| 121 | * This routine handles all the client side handshake messages, one at | ||
| 122 | * a time. Given the message type (and in some cases the pending cipher | ||
| 123 | * spec) it parses the type-specific message. Then it calls a function | ||
| 124 | * that handles that specific message. | ||
| 125 | * | ||
| 126 | * It updates the state machine (need to verify it) as each message | ||
| 127 | * is processed, and writes responses as needed using the connection | ||
| 128 | * in the constructor. | ||
| 129 | */ | ||
| 130 | void processMessage(byte type, int messageLen) throws IOException { | ||
| 131 | if (state > type | ||
| 132 | && (type != HandshakeMessage.ht_hello_request | ||
| 133 | && state != HandshakeMessage.ht_client_hello)) { | ||
| 134 | throw new SSLProtocolException( | ||
| 135 | "Handshake message sequence violation, " + type); | ||
| 136 | } | ||
| 137 | |||
| 138 | switch (type) { | ||
| 139 | case HandshakeMessage.ht_hello_request: | ||
| 140 | this.serverHelloRequest(new HelloRequest(input)); | ||
| 141 | break; | ||
| 142 | |||
| 143 | case HandshakeMessage.ht_server_hello: | ||
| 144 | this.serverHello(new ServerHello(input, messageLen)); | ||
| 145 | break; | ||
| 146 | |||
| 147 | case HandshakeMessage.ht_certificate: | ||
| 148 | if (keyExchange == K_DH_ANON || keyExchange == K_ECDH_ANON | ||
| 149 | || keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) { | ||
| 150 | fatalSE(Alerts.alert_unexpected_message, | ||
| 151 | "unexpected server cert chain"); | ||
| 152 | // NOTREACHED | ||
| 153 | } | ||
| 154 | this.serverCertificate(new CertificateMsg(input)); | ||
| 155 | serverKey = | ||
| 156 | session.getPeerCertificates()[0].getPublicKey(); | ||
| 157 | break; | ||
| 158 | |||
| 159 | case HandshakeMessage.ht_server_key_exchange: | ||
| 160 | serverKeyExchangeReceived = true; | ||
| 161 | switch (keyExchange) { | ||
| 162 | case K_RSA_EXPORT: | ||
| 163 | /** | ||
| 164 | * The server key exchange message is sent by the server only | ||
| 165 | * when the server certificate message does not contain the | ||
| 166 | * proper amount of data to allow the client to exchange a | ||
| 167 | * premaster secret, such as when RSA_EXPORT is used and the | ||
| 168 | * public key in the server certificate is longer than 512 bits. | ||
| 169 | */ | ||
| 170 | if (serverKey == null) { | ||
| 171 | throw new SSLProtocolException | ||
| 172 | ("Server did not send certificate message"); | ||
| 173 | } | ||
| 174 | |||
| 175 | if (!(serverKey instanceof RSAPublicKey)) { | ||
| 176 | throw new SSLProtocolException("Protocol violation:" + | ||
| 177 | " the certificate type must be appropriate for the" + | ||
| 178 | " selected cipher suite's key exchange algorithm"); | ||
| 179 | } | ||
| 180 | |||
| 181 | if (JsseJce.getRSAKeyLength(serverKey) <= 512) { | ||
| 182 | throw new SSLProtocolException("Protocol violation:" + | ||
| 183 | " server sent a server key exchange message for" + | ||
| 184 | " key exchange " + keyExchange + | ||
| 185 | " when the public key in the server certificate" + | ||
| 186 | " is less than or equal to 512 bits in length"); | ||
| 187 | } | ||
| 188 | |||
| 189 | try { | ||
| 190 | this.serverKeyExchange(new RSA_ServerKeyExchange(input)); | ||
| 191 | } catch (GeneralSecurityException e) { | ||
| 192 | throwSSLException("Server key", e); | ||
| 193 | } | ||
| 194 | break; | ||
| 195 | case K_DH_ANON: | ||
| 196 | this.serverKeyExchange(new DH_ServerKeyExchange( | ||
| 197 | input, protocolVersion)); | ||
| 198 | break; | ||
| 199 | case K_DHE_DSS: | ||
| 200 | case K_DHE_RSA: | ||
| 201 | try { | ||
| 202 | this.serverKeyExchange(new DH_ServerKeyExchange( | ||
| 203 | input, serverKey, | ||
| 204 | clnt_random.random_bytes, svr_random.random_bytes, | ||
| 205 | messageLen, | ||
| 206 | localSupportedSignAlgs, protocolVersion)); | ||
| 207 | } catch (GeneralSecurityException e) { | ||
| 208 | throwSSLException("Server key", e); | ||
| 209 | } | ||
| 210 | break; | ||
| 211 | case K_ECDHE_ECDSA: | ||
| 212 | case K_ECDHE_RSA: | ||
| 213 | case K_ECDH_ANON: | ||
| 214 | try { | ||
| 215 | this.serverKeyExchange(new ECDH_ServerKeyExchange | ||
| 216 | (input, serverKey, clnt_random.random_bytes, | ||
| 217 | svr_random.random_bytes, | ||
| 218 | localSupportedSignAlgs, protocolVersion)); | ||
| 219 | } catch (GeneralSecurityException e) { | ||
| 220 | throwSSLException("Server key", e); | ||
| 221 | } | ||
| 222 | break; | ||
| 223 | case K_RSA: | ||
| 224 | case K_DH_RSA: | ||
| 225 | case K_DH_DSS: | ||
| 226 | case K_ECDH_ECDSA: | ||
| 227 | case K_ECDH_RSA: | ||
| 228 | throw new SSLProtocolException( | ||
| 229 | "Protocol violation: server sent a server key exchange" | ||
| 230 | + "message for key exchange " + keyExchange); | ||
| 231 | case K_KRB5: | ||
| 232 | case K_KRB5_EXPORT: | ||
| 233 | throw new SSLProtocolException( | ||
| 234 | "unexpected receipt of server key exchange algorithm"); | ||
| 235 | default: | ||
| 236 | throw new SSLProtocolException( | ||
| 237 | "unsupported key exchange algorithm = " | ||
| 238 | + keyExchange); | ||
| 239 | } | ||
| 240 | break; | ||
| 241 | |||
| 242 | case HandshakeMessage.ht_certificate_request: | ||
| 243 | // save for later, it's handled by serverHelloDone | ||
| 244 | if ((keyExchange == K_DH_ANON) || (keyExchange == K_ECDH_ANON)) { | ||
| 245 | throw new SSLHandshakeException( | ||
| 246 | "Client authentication requested for "+ | ||
| 247 | "anonymous cipher suite."); | ||
| 248 | } else if (keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) { | ||
| 249 | throw new SSLHandshakeException( | ||
| 250 | "Client certificate requested for "+ | ||
| 251 | "kerberos cipher suite."); | ||
| 252 | } | ||
| 253 | certRequest = new CertificateRequest(input, protocolVersion); | ||
| 254 | if (debug != null && Debug.isOn("handshake")) { | ||
| 255 | certRequest.print(System.out); | ||
| 256 | } | ||
| 257 | |||
| 258 | if (protocolVersion.v >= ProtocolVersion.TLS12.v) { | ||
| 259 | Collection<SignatureAndHashAlgorithm> peerSignAlgs = | ||
| 260 | certRequest.getSignAlgorithms(); | ||
| 261 | if (peerSignAlgs == null || peerSignAlgs.isEmpty()) { | ||
| 262 | throw new SSLHandshakeException( | ||
| 263 | "No peer supported signature algorithms"); | ||
| 264 | } | ||
| 265 | |||
| 266 | Collection<SignatureAndHashAlgorithm> supportedPeerSignAlgs = | ||
| 267 | SignatureAndHashAlgorithm.getSupportedAlgorithms( | ||
| 268 | peerSignAlgs); | ||
| 269 | if (supportedPeerSignAlgs.isEmpty()) { | ||
| 270 | throw new SSLHandshakeException( | ||
| 271 | "No supported signature and hash algorithm in common"); | ||
| 272 | } | ||
| 273 | |||
| 274 | setPeerSupportedSignAlgs(supportedPeerSignAlgs); | ||
| 275 | session.setPeerSupportedSignatureAlgorithms( | ||
| 276 | supportedPeerSignAlgs); | ||
| 277 | } | ||
| 278 | |||
| 279 | break; | ||
| 280 | |||
| 281 | case HandshakeMessage.ht_server_hello_done: | ||
| 282 | this.serverHelloDone(new ServerHelloDone(input)); | ||
| 283 | break; | ||
| 284 | |||
| 285 | case HandshakeMessage.ht_finished: | ||
| 286 | this.serverFinished( | ||
| 287 | new Finished(protocolVersion, input, cipherSuite)); | ||
| 288 | break; | ||
| 289 | |||
| 290 | default: | ||
| 291 | throw new SSLProtocolException( | ||
| 292 | "Illegal client handshake msg, " + type); | ||
| 293 | } | ||
| 294 | |||
| 295 | // | ||
| 296 | // Move state machine forward if the message handling | ||
| 297 | // code didn't already do so | ||
| 298 | // | ||
| 299 | if (state < type) { | ||
| 300 | state = type; | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | /* | ||
| 305 | * Used by the server to kickstart negotiations -- this requests a | ||
| 306 | * "client hello" to renegotiate current cipher specs (e.g. maybe lots | ||
| 307 | * of data has been encrypted with the same keys, or the server needs | ||
| 308 | * the client to present a certificate). | ||
| 309 | */ | ||
| 310 | private void serverHelloRequest(HelloRequest mesg) throws IOException { | ||
| 311 | if (debug != null && Debug.isOn("handshake")) { | ||
| 312 | mesg.print(System.out); | ||
| 313 | } | ||
| 314 | |||
| 315 | // | ||
| 316 | // Could be (e.g. at connection setup) that we already | ||
| 317 | // sent the "client hello" but the server's not seen it. | ||
| 318 | // | ||
| 319 | if (state < HandshakeMessage.ht_client_hello) { | ||
| 320 | if (!secureRenegotiation && !allowUnsafeRenegotiation) { | ||
| 321 | // renegotiation is not allowed. | ||
| 322 | if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) { | ||
| 323 | // response with a no_renegotiation warning, | ||
| 324 | warningSE(Alerts.alert_no_renegotiation); | ||
| 325 | |||
| 326 | // invalidate the handshake so that the caller can | ||
| 327 | // dispose this object. | ||
| 328 | invalidated = true; | ||
| 329 | |||
| 330 | // If there is still unread block in the handshake | ||
| 331 | // input stream, it would be truncated with the disposal | ||
| 332 | // and the next handshake message will become incomplete. | ||
| 333 | // | ||
| 334 | // However, according to SSL/TLS specifications, no more | ||
| 335 | // handshake message should immediately follow ClientHello | ||
| 336 | // or HelloRequest. So just let it be. | ||
| 337 | } else { | ||
| 338 | // For SSLv3, send the handshake_failure fatal error. | ||
| 339 | // Note that SSLv3 does not define a no_renegotiation | ||
| 340 | // alert like TLSv1. However we cannot ignore the message | ||
| 341 | // simply, otherwise the other side was waiting for a | ||
| 342 | // response that would never come. | ||
| 343 | fatalSE(Alerts.alert_handshake_failure, | ||
| 344 | "Renegotiation is not allowed"); | ||
| 345 | } | ||
| 346 | } else { | ||
| 347 | if (!secureRenegotiation) { | ||
| 348 | if (debug != null && Debug.isOn("handshake")) { | ||
| 349 | System.out.println( | ||
| 350 | "Warning: continue with insecure renegotiation"); | ||
| 351 | } | ||
| 352 | } | ||
| 353 | kickstart(); | ||
| 354 | } | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | |||
| 359 | /* | ||
| 360 | * Server chooses session parameters given options created by the | ||
| 361 | * client -- basically, cipher options, session id, and someday a | ||
| 362 | * set of compression options. | ||
| 363 | * | ||
| 364 | * There are two branches of the state machine, decided by the | ||
| 365 | * details of this message. One is the "fast" handshake, where we | ||
| 366 | * can resume the pre-existing session we asked resume. The other | ||
| 367 | * is a more expensive "full" handshake, with key exchange and | ||
| 368 | * probably authentication getting done. | ||
| 369 | */ | ||
| 370 | private void serverHello(ServerHello mesg) throws IOException { | ||
| 371 | serverKeyExchangeReceived = false; | ||
| 372 | if (debug != null && Debug.isOn("handshake")) { | ||
| 373 | mesg.print(System.out); | ||
| 374 | } | ||
| 375 | |||
| 376 | // check if the server selected protocol version is OK for us | ||
| 377 | ProtocolVersion mesgVersion = mesg.protocolVersion; | ||
| 378 | if (!isNegotiable(mesgVersion)) { | ||
| 379 | throw new SSLHandshakeException( | ||
| 380 | "Server chose " + mesgVersion + | ||
| 381 | ", but that protocol version is not enabled or not supported " + | ||
| 382 | "by the client."); | ||
| 383 | } | ||
| 384 | |||
| 385 | handshakeHash.protocolDetermined(mesgVersion); | ||
| 386 | |||
| 387 | // Set protocolVersion and propagate to SSLSocket and the | ||
| 388 | // Handshake streams | ||
| 389 | setVersion(mesgVersion); | ||
| 390 | |||
| 391 | // check the "renegotiation_info" extension | ||
| 392 | RenegotiationInfoExtension serverHelloRI = (RenegotiationInfoExtension) | ||
| 393 | mesg.extensions.get(ExtensionType.EXT_RENEGOTIATION_INFO); | ||
| 394 | if (serverHelloRI != null) { | ||
| 395 | if (isInitialHandshake) { | ||
| 396 | // verify the length of the "renegotiated_connection" field | ||
| 397 | if (!serverHelloRI.isEmpty()) { | ||
| 398 | // abort the handshake with a fatal handshake_failure alert | ||
| 399 | fatalSE(Alerts.alert_handshake_failure, | ||
| 400 | "The renegotiation_info field is not empty"); | ||
| 401 | } | ||
| 402 | |||
| 403 | secureRenegotiation = true; | ||
| 404 | } else { | ||
| 405 | // For a legacy renegotiation, the client MUST verify that | ||
| 406 | // it does not contain the "renegotiation_info" extension. | ||
| 407 | if (!secureRenegotiation) { | ||
| 408 | fatalSE(Alerts.alert_handshake_failure, | ||
| 409 | "Unexpected renegotiation indication extension"); | ||
| 410 | } | ||
| 411 | |||
| 412 | // verify the client_verify_data and server_verify_data values | ||
| 413 | byte[] verifyData = | ||
| 414 | new byte[clientVerifyData.length + serverVerifyData.length]; | ||
| 415 | System.arraycopy(clientVerifyData, 0, verifyData, | ||
| 416 | 0, clientVerifyData.length); | ||
| 417 | System.arraycopy(serverVerifyData, 0, verifyData, | ||
| 418 | clientVerifyData.length, serverVerifyData.length); | ||
| 419 | if (!Arrays.equals(verifyData, | ||
| 420 | serverHelloRI.getRenegotiatedConnection())) { | ||
| 421 | fatalSE(Alerts.alert_handshake_failure, | ||
| 422 | "Incorrect verify data in ServerHello " + | ||
| 423 | "renegotiation_info message"); | ||
| 424 | } | ||
| 425 | } | ||
| 426 | } else { | ||
| 427 | // no renegotiation indication extension | ||
| 428 | if (isInitialHandshake) { | ||
| 429 | if (!allowLegacyHelloMessages) { | ||
| 430 | // abort the handshake with a fatal handshake_failure alert | ||
| 431 | fatalSE(Alerts.alert_handshake_failure, | ||
| 432 | "Failed to negotiate the use of secure renegotiation"); | ||
| 433 | } | ||
| 434 | |||
| 435 | secureRenegotiation = false; | ||
| 436 | if (debug != null && Debug.isOn("handshake")) { | ||
| 437 | System.out.println("Warning: No renegotiation " + | ||
| 438 | "indication extension in ServerHello"); | ||
| 439 | } | ||
| 440 | } else { | ||
| 441 | // For a secure renegotiation, the client must abort the | ||
| 442 | // handshake if no "renegotiation_info" extension is present. | ||
| 443 | if (secureRenegotiation) { | ||
| 444 | fatalSE(Alerts.alert_handshake_failure, | ||
| 445 | "No renegotiation indication extension"); | ||
| 446 | } | ||
| 447 | |||
| 448 | // we have already allowed unsafe renegotation before request | ||
| 449 | // the renegotiation. | ||
| 450 | } | ||
| 451 | } | ||
| 452 | |||
| 453 | // | ||
| 454 | // Save server nonce, we always use it to compute connection | ||
| 455 | // keys and it's also used to create the master secret if we're | ||
| 456 | // creating a new session (i.e. in the full handshake). | ||
| 457 | // | ||
| 458 | svr_random = mesg.svr_random; | ||
| 459 | |||
| 460 | if (isNegotiable(mesg.cipherSuite) == false) { | ||
| 461 | fatalSE(Alerts.alert_illegal_parameter, | ||
| 462 | "Server selected improper ciphersuite " + mesg.cipherSuite); | ||
| 463 | } | ||
| 464 | |||
| 465 | setCipherSuite(mesg.cipherSuite); | ||
| 466 | if (protocolVersion.v >= ProtocolVersion.TLS12.v) { | ||
| 467 | handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg()); | ||
| 468 | } | ||
| 469 | |||
| 470 | if (mesg.compression_method != 0) { | ||
| 471 | fatalSE(Alerts.alert_illegal_parameter, | ||
| 472 | "compression type not supported, " | ||
| 473 | + mesg.compression_method); | ||
| 474 | // NOTREACHED | ||
| 475 | } | ||
| 476 | |||
| 477 | // so far so good, let's look at the session | ||
| 478 | if (session != null) { | ||
| 479 | // we tried to resume, let's see what the server decided | ||
| 480 | if (session.getSessionId().equals(mesg.sessionId)) { | ||
| 481 | // server resumed the session, let's make sure everything | ||
| 482 | // checks out | ||
| 483 | |||
| 484 | // Verify that the session ciphers are unchanged. | ||
| 485 | CipherSuite sessionSuite = session.getSuite(); | ||
| 486 | if (cipherSuite != sessionSuite) { | ||
| 487 | throw new SSLProtocolException | ||
| 488 | ("Server returned wrong cipher suite for session"); | ||
| 489 | } | ||
| 490 | |||
| 491 | // verify protocol version match | ||
| 492 | ProtocolVersion sessionVersion = session.getProtocolVersion(); | ||
| 493 | if (protocolVersion != sessionVersion) { | ||
| 494 | throw new SSLProtocolException | ||
| 495 | ("Server resumed session with wrong protocol version"); | ||
| 496 | } | ||
| 497 | |||
| 498 | // validate subject identity | ||
| 499 | if (sessionSuite.keyExchange == K_KRB5 || | ||
| 500 | sessionSuite.keyExchange == K_KRB5_EXPORT) { | ||
| 501 | Principal localPrincipal = session.getLocalPrincipal(); | ||
| 502 | |||
| 503 | Subject subject = null; | ||
| 504 | try { | ||
| 505 | subject = AccessController.doPrivileged( | ||
| 506 | new PrivilegedExceptionAction<Subject>() { | ||
| 507 | public Subject run() throws Exception { | ||
| 508 | return Krb5Helper.getClientSubject(getAccSE()); | ||
| 509 | }}); | ||
| 510 | } catch (PrivilegedActionException e) { | ||
| 511 | subject = null; | ||
| 512 | if (debug != null && Debug.isOn("session")) { | ||
| 513 | System.out.println("Attempt to obtain" + | ||
| 514 | " subject failed!"); | ||
| 515 | } | ||
| 516 | } | ||
| 517 | |||
| 518 | if (subject != null) { | ||
| 519 | // Eliminate dependency on KerberosPrincipal | ||
| 520 | Set<Principal> principals = | ||
| 521 | subject.getPrincipals(Principal.class); | ||
| 522 | if (!principals.contains(localPrincipal)) { | ||
| 523 | throw new SSLProtocolException("Server resumed" + | ||
| 524 | " session with wrong subject identity"); | ||
| 525 | } else { | ||
| 526 | if (debug != null && Debug.isOn("session")) | ||
| 527 | System.out.println("Subject identity is same"); | ||
| 528 | } | ||
| 529 | } else { | ||
| 530 | if (debug != null && Debug.isOn("session")) | ||
| 531 | System.out.println("Kerberos credentials are not" + | ||
| 532 | " present in the current Subject; check if " + | ||
| 533 | " javax.security.auth.useSubjectAsCreds" + | ||
| 534 | " system property has been set to false"); | ||
| 535 | throw new SSLProtocolException | ||
| 536 | ("Server resumed session with no subject"); | ||
| 537 | } | ||
| 538 | } | ||
| 539 | |||
| 540 | // looks fine; resume it, and update the state machine. | ||
| 541 | resumingSession = true; | ||
| 542 | state = HandshakeMessage.ht_finished - 1; | ||
| 543 | calculateConnectionKeys(session.getMasterSecret()); | ||
| 544 | if (debug != null && Debug.isOn("session")) { | ||
| 545 | System.out.println("%% Server resumed " + session); | ||
| 546 | } | ||
| 547 | } else { | ||
| 548 | // we wanted to resume, but the server refused | ||
| 549 | session = null; | ||
| 550 | if (!enableNewSession) { | ||
| 551 | throw new SSLException | ||
| 552 | ("New session creation is disabled"); | ||
| 553 | } | ||
| 554 | } | ||
| 555 | } | ||
| 556 | |||
| 557 | if (resumingSession && session != null) { | ||
| 558 | if (protocolVersion.v >= ProtocolVersion.TLS12.v) { | ||
| 559 | handshakeHash.setCertificateVerifyAlg(null); | ||
| 560 | } | ||
| 561 | |||
| 562 | setHandshakeSessionSE(session); | ||
| 563 | return; | ||
| 564 | } | ||
| 565 | |||
| 566 | // check extensions | ||
| 567 | for (HelloExtension ext : mesg.extensions.list()) { | ||
| 568 | ExtensionType type = ext.type; | ||
| 569 | if ((type != ExtensionType.EXT_ELLIPTIC_CURVES) | ||
| 570 | && (type != ExtensionType.EXT_EC_POINT_FORMATS) | ||
| 571 | && (type != ExtensionType.EXT_SERVER_NAME) | ||
| 572 | && (type != ExtensionType.EXT_RENEGOTIATION_INFO)) { | ||
| 573 | fatalSE(Alerts.alert_unsupported_extension, | ||
| 574 | "Server sent an unsupported extension: " + type); | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | // Create a new session, we need to do the full handshake | ||
| 579 | session = new SSLSessionImpl(protocolVersion, cipherSuite, | ||
| 580 | getLocalSupportedSignAlgs(), | ||
| 581 | mesg.sessionId, getHostSE(), getPortSE()); | ||
| 582 | setHandshakeSessionSE(session); | ||
| 583 | if (debug != null && Debug.isOn("handshake")) { | ||
| 584 | System.out.println("** " + cipherSuite); | ||
| 585 | } | ||
| 586 | } | ||
| 587 | |||
| 588 | /* | ||
| 589 | * Server's own key was either a signing-only key, or was too | ||
| 590 | * large for export rules ... this message holds an ephemeral | ||
| 591 | * RSA key to use for key exchange. | ||
| 592 | */ | ||
| 593 | private void serverKeyExchange(RSA_ServerKeyExchange mesg) | ||
| 594 | throws IOException, GeneralSecurityException { | ||
| 595 | if (debug != null && Debug.isOn("handshake")) { | ||
| 596 | mesg.print(System.out); | ||
| 597 | } | ||
| 598 | if (!mesg.verify(serverKey, clnt_random, svr_random)) { | ||
| 599 | fatalSE(Alerts.alert_handshake_failure, | ||
| 600 | "server key exchange invalid"); | ||
| 601 | // NOTREACHED | ||
| 602 | } | ||
| 603 | ephemeralServerKey = mesg.getPublicKey(); | ||
| 604 | } | ||
| 605 | |||
| 606 | |||
| 607 | /* | ||
| 608 | * Diffie-Hellman key exchange. We save the server public key and | ||
| 609 | * our own D-H algorithm object so we can defer key calculations | ||
| 610 | * until after we've sent the client key exchange message (which | ||
| 611 | * gives client and server some useful parallelism). | ||
| 612 | */ | ||
| 613 | private void serverKeyExchange(DH_ServerKeyExchange mesg) | ||
| 614 | throws IOException { | ||
| 615 | if (debug != null && Debug.isOn("handshake")) { | ||
| 616 | mesg.print(System.out); | ||
| 617 | } | ||
| 618 | dh = new DHCrypt(mesg.getModulus(), mesg.getBase(), | ||
| 619 | sslContext.getSecureRandom()); | ||
| 620 | serverDH = mesg.getServerPublicKey(); | ||
| 621 | } | ||
| 622 | |||
| 623 | private void serverKeyExchange(ECDH_ServerKeyExchange mesg) | ||
| 624 | throws IOException { | ||
| 625 | if (debug != null && Debug.isOn("handshake")) { | ||
| 626 | mesg.print(System.out); | ||
| 627 | } | ||
| 628 | ECPublicKey key = mesg.getPublicKey(); | ||
| 629 | ecdh = new ECDHCrypt(key.getParams(), sslContext.getSecureRandom()); | ||
| 630 | ephemeralServerKey = key; | ||
| 631 | } | ||
| 632 | |||
| 633 | /* | ||
| 634 | * The server's "Hello Done" message is the client's sign that | ||
| 635 | * it's time to do all the hard work. | ||
| 636 | */ | ||
| 637 | private void serverHelloDone(ServerHelloDone mesg) throws IOException { | ||
| 638 | if (debug != null && Debug.isOn("handshake")) { | ||
| 639 | mesg.print(System.out); | ||
| 640 | } | ||
| 641 | /* | ||
| 642 | * Always make sure the input has been digested before we | ||
| 643 | * start emitting data, to ensure the hashes are correctly | ||
| 644 | * computed for the Finished and CertificateVerify messages | ||
| 645 | * which we send (here). | ||
| 646 | */ | ||
| 647 | input.digestNow(); | ||
| 648 | |||
| 649 | /* | ||
| 650 | * FIRST ... if requested, send an appropriate Certificate chain | ||
| 651 | * to authenticate the client, and remember the associated private | ||
| 652 | * key to sign the CertificateVerify message. | ||
| 653 | */ | ||
| 654 | PrivateKey signingKey = null; | ||
| 655 | |||
| 656 | if (certRequest != null) { | ||
| 657 | X509ExtendedKeyManager km = sslContext.getX509KeyManager(); | ||
| 658 | |||
| 659 | ArrayList<String> keytypesTmp = new ArrayList<>(4); | ||
| 660 | |||
| 661 | for (int i = 0; i < certRequest.types.length; i++) { | ||
| 662 | String typeName; | ||
| 663 | |||
| 664 | switch (certRequest.types[i]) { | ||
| 665 | case CertificateRequest.cct_rsa_sign: | ||
| 666 | typeName = "RSA"; | ||
| 667 | break; | ||
| 668 | |||
| 669 | case CertificateRequest.cct_dss_sign: | ||
| 670 | typeName = "DSA"; | ||
| 671 | break; | ||
| 672 | |||
| 673 | case CertificateRequest.cct_ecdsa_sign: | ||
| 674 | // ignore if we do not have EC crypto available | ||
| 675 | typeName = JsseJce.isEcAvailable() ? "EC" : null; | ||
| 676 | break; | ||
| 677 | |||
| 678 | // Fixed DH/ECDH client authentication not supported | ||
| 679 | case CertificateRequest.cct_rsa_fixed_dh: | ||
| 680 | case CertificateRequest.cct_dss_fixed_dh: | ||
| 681 | case CertificateRequest.cct_rsa_fixed_ecdh: | ||
| 682 | case CertificateRequest.cct_ecdsa_fixed_ecdh: | ||
| 683 | // Any other values (currently not used in TLS) | ||
| 684 | case CertificateRequest.cct_rsa_ephemeral_dh: | ||
| 685 | case CertificateRequest.cct_dss_ephemeral_dh: | ||
| 686 | default: | ||
| 687 | typeName = null; | ||
| 688 | break; | ||
| 689 | } | ||
| 690 | |||
| 691 | if ((typeName != null) && (!keytypesTmp.contains(typeName))) { | ||
| 692 | keytypesTmp.add(typeName); | ||
| 693 | } | ||
| 694 | } | ||
| 695 | |||
| 696 | String alias = null; | ||
| 697 | int keytypesTmpSize = keytypesTmp.size(); | ||
| 698 | if (keytypesTmpSize != 0) { | ||
| 699 | String keytypes[] = | ||
| 700 | keytypesTmp.toArray(new String[keytypesTmpSize]); | ||
| 701 | |||
| 702 | if (conn != null) { | ||
| 703 | alias = km.chooseClientAlias(keytypes, | ||
| 704 | certRequest.getAuthorities(), conn); | ||
| 705 | } else { | ||
| 706 | alias = km.chooseEngineClientAlias(keytypes, | ||
| 707 | certRequest.getAuthorities(), engine); | ||
| 708 | } | ||
| 709 | } | ||
| 710 | |||
| 711 | CertificateMsg m1 = null; | ||
| 712 | if (alias != null) { | ||
| 713 | X509Certificate[] certs = km.getCertificateChain(alias); | ||
| 714 | if ((certs != null) && (certs.length != 0)) { | ||
| 715 | PublicKey publicKey = certs[0].getPublicKey(); | ||
| 716 | // for EC, make sure we use a supported named curve | ||
| 717 | if (publicKey instanceof ECPublicKey) { | ||
| 718 | ECParameterSpec params = | ||
| 719 | ((ECPublicKey)publicKey).getParams(); | ||
| 720 | int index = | ||
| 721 | SupportedEllipticCurvesExtension.getCurveIndex( | ||
| 722 | params); | ||
| 723 | if (!SupportedEllipticCurvesExtension.isSupported( | ||
| 724 | index)) { | ||
| 725 | publicKey = null; | ||
| 726 | } | ||
| 727 | } | ||
| 728 | if (publicKey != null) { | ||
| 729 | m1 = new CertificateMsg(certs); | ||
| 730 | signingKey = km.getPrivateKey(alias); | ||
| 731 | session.setLocalPrivateKey(signingKey); | ||
| 732 | session.setLocalCertificates(certs); | ||
| 733 | } | ||
| 734 | } | ||
| 735 | } | ||
| 736 | if (m1 == null) { | ||
| 737 | // | ||
| 738 | // No appropriate cert was found ... report this to the | ||
| 739 | // server. For SSLv3, send the no_certificate alert; | ||
| 740 | // TLS uses an empty cert chain instead. | ||
| 741 | // | ||
| 742 | if (protocolVersion.v >= ProtocolVersion.TLS10.v) { | ||
| 743 | m1 = new CertificateMsg(new X509Certificate [0]); | ||
| 744 | } else { | ||
| 745 | warningSE(Alerts.alert_no_certificate); | ||
| 746 | } | ||
| 747 | } | ||
| 748 | |||
| 749 | // | ||
| 750 | // At last ... send any client certificate chain. | ||
| 751 | // | ||
| 752 | if (m1 != null) { | ||
| 753 | if (debug != null && Debug.isOn("handshake")) { | ||
| 754 | m1.print(System.out); | ||
| 755 | } | ||
| 756 | m1.write(output); | ||
| 757 | } | ||
| 758 | } | ||
| 759 | |||
| 760 | /* | ||
| 761 | * SECOND ... send the client key exchange message. The | ||
| 762 | * procedure used is a function of the cipher suite selected; | ||
| 763 | * one is always needed. | ||
| 764 | */ | ||
| 765 | HandshakeMessage m2; | ||
| 766 | |||
| 767 | switch (keyExchange) { | ||
| 768 | |||
| 769 | case K_RSA: | ||
| 770 | case K_RSA_EXPORT: | ||
| 771 | if (serverKey == null) { | ||
| 772 | throw new SSLProtocolException | ||
| 773 | ("Server did not send certificate message"); | ||
| 774 | } | ||
| 775 | |||
| 776 | if (!(serverKey instanceof RSAPublicKey)) { | ||
| 777 | throw new SSLProtocolException | ||
| 778 | ("Server certificate does not include an RSA key"); | ||
| 779 | } | ||
| 780 | |||
| 781 | /* | ||
| 782 | * For RSA key exchange, we randomly generate a new | ||
| 783 | * pre-master secret and encrypt it with the server's | ||
| 784 | * public key. Then we save that pre-master secret | ||
| 785 | * so that we can calculate the keying data later; | ||
| 786 | * it's a performance speedup not to do that until | ||
| 787 | * the client's waiting for the server response, but | ||
| 788 | * more of a speedup for the D-H case. | ||
| 789 | * | ||
| 790 | * If the RSA_EXPORT scheme is active, when the public | ||
| 791 | * key in the server certificate is less than or equal | ||
| 792 | * to 512 bits in length, use the cert's public key, | ||
| 793 | * otherwise, the ephemeral one. | ||
| 794 | */ | ||
| 795 | PublicKey key; | ||
| 796 | if (keyExchange == K_RSA) { | ||
| 797 | key = serverKey; | ||
| 798 | } else { // K_RSA_EXPORT | ||
| 799 | if (JsseJce.getRSAKeyLength(serverKey) <= 512) { | ||
| 800 | // extraneous ephemeralServerKey check done | ||
| 801 | // above in processMessage() | ||
| 802 | key = serverKey; | ||
| 803 | } else { | ||
| 804 | if (ephemeralServerKey == null) { | ||
| 805 | throw new SSLProtocolException("Server did not send" + | ||
| 806 | " a RSA_EXPORT Server Key Exchange message"); | ||
| 807 | } | ||
| 808 | key = ephemeralServerKey; | ||
| 809 | } | ||
| 810 | } | ||
| 811 | |||
| 812 | m2 = new RSAClientKeyExchange(protocolVersion, maxProtocolVersion, | ||
| 813 | sslContext.getSecureRandom(), key); | ||
| 814 | break; | ||
| 815 | case K_DH_RSA: | ||
| 816 | case K_DH_DSS: | ||
| 817 | /* | ||
| 818 | * For DH Key exchange, we only need to make sure the server | ||
| 819 | * knows our public key, so we calculate the same pre-master | ||
| 820 | * secret. | ||
| 821 | * | ||
| 822 | * For certs that had DH keys in them, we send an empty | ||
| 823 | * handshake message (no key) ... we flag this case by | ||
| 824 | * passing a null "dhPublic" value. | ||
| 825 | * | ||
| 826 | * Otherwise we send ephemeral DH keys, unsigned. | ||
| 827 | */ | ||
| 828 | // if (useDH_RSA || useDH_DSS) | ||
| 829 | m2 = new DHClientKeyExchange(); | ||
| 830 | break; | ||
| 831 | case K_DHE_RSA: | ||
| 832 | case K_DHE_DSS: | ||
| 833 | case K_DH_ANON: | ||
| 834 | if (dh == null) { | ||
| 835 | throw new SSLProtocolException | ||
| 836 | ("Server did not send a DH Server Key Exchange message"); | ||
| 837 | } | ||
| 838 | m2 = new DHClientKeyExchange(dh.getPublicKey()); | ||
| 839 | break; | ||
| 840 | case K_ECDHE_RSA: | ||
| 841 | case K_ECDHE_ECDSA: | ||
| 842 | case K_ECDH_ANON: | ||
| 843 | if (ecdh == null) { | ||
| 844 | throw new SSLProtocolException | ||
| 845 | ("Server did not send a ECDH Server Key Exchange message"); | ||
| 846 | } | ||
| 847 | m2 = new ECDHClientKeyExchange(ecdh.getPublicKey()); | ||
| 848 | break; | ||
| 849 | case K_ECDH_RSA: | ||
| 850 | case K_ECDH_ECDSA: | ||
| 851 | if (serverKey == null) { | ||
| 852 | throw new SSLProtocolException | ||
| 853 | ("Server did not send certificate message"); | ||
| 854 | } | ||
| 855 | if (serverKey instanceof ECPublicKey == false) { | ||
| 856 | throw new SSLProtocolException | ||
| 857 | ("Server certificate does not include an EC key"); | ||
| 858 | } | ||
| 859 | ECParameterSpec params = ((ECPublicKey)serverKey).getParams(); | ||
| 860 | ecdh = new ECDHCrypt(params, sslContext.getSecureRandom()); | ||
| 861 | m2 = new ECDHClientKeyExchange(ecdh.getPublicKey()); | ||
| 862 | break; | ||
| 863 | case K_KRB5: | ||
| 864 | case K_KRB5_EXPORT: | ||
| 865 | String hostname = getHostSE(); | ||
| 866 | if (hostname == null) { | ||
| 867 | throw new IOException("Hostname is required" + | ||
| 868 | " to use Kerberos cipher suites"); | ||
| 869 | } | ||
| 870 | KerberosClientKeyExchange kerberosMsg = | ||
| 871 | new KerberosClientKeyExchange( | ||
| 872 | hostname, isLoopbackSE(), getAccSE(), protocolVersion, | ||
| 873 | sslContext.getSecureRandom()); | ||
| 874 | // Record the principals involved in exchange | ||
| 875 | session.setPeerPrincipal(kerberosMsg.getPeerPrincipal()); | ||
| 876 | session.setLocalPrincipal(kerberosMsg.getLocalPrincipal()); | ||
| 877 | m2 = kerberosMsg; | ||
| 878 | break; | ||
| 879 | default: | ||
| 880 | // somethings very wrong | ||
| 881 | throw new RuntimeException | ||
| 882 | ("Unsupported key exchange: " + keyExchange); | ||
| 883 | } | ||
| 884 | if (debug != null && Debug.isOn("handshake")) { | ||
| 885 | m2.print(System.out); | ||
| 886 | } | ||
| 887 | m2.write(output); | ||
| 888 | |||
| 889 | |||
| 890 | /* | ||
| 891 | * THIRD, send a "change_cipher_spec" record followed by the | ||
| 892 | * "Finished" message. We flush the messages we've queued up, to | ||
| 893 | * get concurrency between client and server. The concurrency is | ||
| 894 | * useful as we calculate the master secret, which is needed both | ||
| 895 | * to compute the "Finished" message, and to compute the keys used | ||
| 896 | * to protect all records following the change_cipher_spec. | ||
| 897 | */ | ||
| 898 | |||
| 899 | output.doHashes(); | ||
| 900 | output.flush(); | ||
| 901 | |||
| 902 | /* | ||
| 903 | * We deferred calculating the master secret and this connection's | ||
| 904 | * keying data; we do it now. Deferring this calculation is good | ||
| 905 | * from a performance point of view, since it lets us do it during | ||
| 906 | * some time that network delays and the server's own calculations | ||
| 907 | * would otherwise cause to be "dead" in the critical path. | ||
| 908 | */ | ||
| 909 | SecretKey preMasterSecret; | ||
| 910 | switch (keyExchange) { | ||
| 911 | case K_RSA: | ||
| 912 | case K_RSA_EXPORT: | ||
| 913 | preMasterSecret = ((RSAClientKeyExchange)m2).preMaster; | ||
| 914 | break; | ||
| 915 | case K_KRB5: | ||
| 916 | case K_KRB5_EXPORT: | ||
| 917 | byte[] secretBytes = | ||
| 918 | ((KerberosClientKeyExchange)m2).getUnencryptedPreMasterSecret(); | ||
| 919 | preMasterSecret = new SecretKeySpec(secretBytes, | ||
| 920 | "TlsPremasterSecret"); | ||
| 921 | break; | ||
| 922 | case K_DHE_RSA: | ||
| 923 | case K_DHE_DSS: | ||
| 924 | case K_DH_ANON: | ||
| 925 | preMasterSecret = dh.getAgreedSecret(serverDH); | ||
| 926 | break; | ||
| 927 | case K_ECDHE_RSA: | ||
| 928 | case K_ECDHE_ECDSA: | ||
| 929 | case K_ECDH_ANON: | ||
| 930 | preMasterSecret = ecdh.getAgreedSecret(ephemeralServerKey); | ||
| 931 | break; | ||
| 932 | case K_ECDH_RSA: | ||
| 933 | case K_ECDH_ECDSA: | ||
| 934 | preMasterSecret = ecdh.getAgreedSecret(serverKey); | ||
| 935 | break; | ||
| 936 | default: | ||
| 937 | throw new IOException("Internal error: unknown key exchange " | ||
| 938 | + keyExchange); | ||
| 939 | } | ||
| 940 | |||
| 941 | calculateKeys(preMasterSecret, null); | ||
| 942 | |||
| 943 | /* | ||
| 944 | * FOURTH, if we sent a Certificate, we need to send a signed | ||
| 945 | * CertificateVerify (unless the key in the client's certificate | ||
| 946 | * was a Diffie-Hellman key).). | ||
| 947 | * | ||
| 948 | * This uses a hash of the previous handshake messages ... either | ||
| 949 | * a nonfinal one (if the particular implementation supports it) | ||
| 950 | * or else using the third element in the arrays of hashes being | ||
| 951 | * computed. | ||
| 952 | */ | ||
| 953 | if (signingKey != null) { | ||
| 954 | CertificateVerify m3; | ||
| 955 | try { | ||
| 956 | SignatureAndHashAlgorithm preferableSignatureAlgorithm = null; | ||
| 957 | if (protocolVersion.v >= ProtocolVersion.TLS12.v) { | ||
| 958 | preferableSignatureAlgorithm = | ||
| 959 | SignatureAndHashAlgorithm.getPreferableAlgorithm( | ||
| 960 | peerSupportedSignAlgs, signingKey.getAlgorithm()); | ||
| 961 | |||
| 962 | if (preferableSignatureAlgorithm == null) { | ||
| 963 | throw new SSLHandshakeException( | ||
| 964 | "No supported signature algorithm"); | ||
| 965 | } | ||
| 966 | |||
| 967 | String hashAlg = | ||
| 968 | SignatureAndHashAlgorithm.getHashAlgorithmName( | ||
| 969 | preferableSignatureAlgorithm); | ||
| 970 | if (hashAlg == null || hashAlg.length() == 0) { | ||
| 971 | throw new SSLHandshakeException( | ||
| 972 | "No supported hash algorithm"); | ||
| 973 | } | ||
| 974 | |||
| 975 | handshakeHash.setCertificateVerifyAlg(hashAlg); | ||
| 976 | } | ||
| 977 | |||
| 978 | m3 = new CertificateVerify(protocolVersion, handshakeHash, | ||
| 979 | signingKey, session.getMasterSecret(), | ||
| 980 | sslContext.getSecureRandom(), | ||
| 981 | preferableSignatureAlgorithm); | ||
| 982 | } catch (GeneralSecurityException e) { | ||
| 983 | fatalSE(Alerts.alert_handshake_failure, | ||
| 984 | "Error signing certificate verify", e); | ||
| 985 | // NOTREACHED, make compiler happy | ||
| 986 | m3 = null; | ||
| 987 | } | ||
| 988 | if (debug != null && Debug.isOn("handshake")) { | ||
| 989 | m3.print(System.out); | ||
| 990 | } | ||
| 991 | m3.write(output); | ||
| 992 | output.doHashes(); | ||
| 993 | } else { | ||
| 994 | if (protocolVersion.v >= ProtocolVersion.TLS12.v) { | ||
| 995 | handshakeHash.setCertificateVerifyAlg(null); | ||
| 996 | } | ||
| 997 | } | ||
| 998 | |||
| 999 | /* | ||
| 1000 | * OK, that's that! | ||
| 1001 | */ | ||
| 1002 | sendChangeCipherAndFinish(false); | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | |||
| 1006 | /* | ||
| 1007 | * "Finished" is the last handshake message sent. If we got this | ||
| 1008 | * far, the MAC has been validated post-decryption. We validate | ||
| 1009 | * the two hashes here as an additional sanity check, protecting | ||
| 1010 | * the handshake against various active attacks. | ||
| 1011 | */ | ||
| 1012 | private void serverFinished(Finished mesg) throws IOException { | ||
| 1013 | if (debug != null && Debug.isOn("handshake")) { | ||
| 1014 | mesg.print(System.out); | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | boolean verified = mesg.verify(handshakeHash, Finished.SERVER, | ||
| 1018 | session.getMasterSecret()); | ||
| 1019 | |||
| 1020 | if (!verified) { | ||
| 1021 | fatalSE(Alerts.alert_illegal_parameter, | ||
| 1022 | "server 'finished' message doesn't verify"); | ||
| 1023 | // NOTREACHED | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | /* | ||
| 1027 | * save server verify data for secure renegotiation | ||
| 1028 | */ | ||
| 1029 | if (secureRenegotiation) { | ||
| 1030 | serverVerifyData = mesg.getVerifyData(); | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | /* | ||
| 1034 | * OK, it verified. If we're doing the fast handshake, add that | ||
| 1035 | * "Finished" message to the hash of handshake messages, then send | ||
| 1036 | * our own change_cipher_spec and Finished message for the server | ||
| 1037 | * to verify in turn. These are the last handshake messages. | ||
| 1038 | * | ||
| 1039 | * In any case, update the session cache. We're done handshaking, | ||
| 1040 | * so there are no threats any more associated with partially | ||
| 1041 | * completed handshakes. | ||
| 1042 | */ | ||
| 1043 | if (resumingSession) { | ||
| 1044 | input.digestNow(); | ||
| 1045 | sendChangeCipherAndFinish(true); | ||
| 1046 | } | ||
| 1047 | session.setLastAccessedTime(System.currentTimeMillis()); | ||
| 1048 | |||
| 1049 | if (!resumingSession) { | ||
| 1050 | if (session.isRejoinable()) { | ||
| 1051 | ((SSLSessionContextImpl) sslContext | ||
| 1052 | .engineGetClientSessionContext()) | ||
| 1053 | .put(session); | ||
| 1054 | if (debug != null && Debug.isOn("session")) { | ||
| 1055 | System.out.println("%% Cached client session: " + session); | ||
| 1056 | } | ||
| 1057 | } else if (debug != null && Debug.isOn("session")) { | ||
| 1058 | System.out.println( | ||
| 1059 | "%% Didn't cache non-resumable client session: " | ||
| 1060 | + session); | ||
| 1061 | } | ||
| 1062 | } | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | |||
| 1066 | /* | ||
| 1067 | * Send my change-cipher-spec and Finished message ... done as the | ||
| 1068 | * last handshake act in either the short or long sequences. In | ||
| 1069 | * the short one, we've already seen the server's Finished; in the | ||
| 1070 | * long one, we wait for it now. | ||
| 1071 | */ | ||
| 1072 | private void sendChangeCipherAndFinish(boolean finishedTag) | ||
| 1073 | throws IOException { | ||
| 1074 | Finished mesg = new Finished(protocolVersion, handshakeHash, | ||
| 1075 | Finished.CLIENT, session.getMasterSecret(), cipherSuite); | ||
| 1076 | |||
| 1077 | /* | ||
| 1078 | * Send the change_cipher_spec message, then the Finished message | ||
| 1079 | * which we just calculated (and protected using the keys we just | ||
| 1080 | * calculated). Server responds with its Finished message, except | ||
| 1081 | * in the "fast handshake" (resume session) case. | ||
| 1082 | */ | ||
| 1083 | sendChangeCipherSpec(mesg, finishedTag); | ||
| 1084 | |||
| 1085 | /* | ||
| 1086 | * save client verify data for secure renegotiation | ||
| 1087 | */ | ||
| 1088 | if (secureRenegotiation) { | ||
| 1089 | clientVerifyData = mesg.getVerifyData(); | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | /* | ||
| 1093 | * Update state machine so server MUST send 'finished' next. | ||
| 1094 | * (In "long" handshake case; in short case, we're responding | ||
| 1095 | * to its message.) | ||
| 1096 | */ | ||
| 1097 | state = HandshakeMessage.ht_finished - 1; | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | |||
| 1101 | /* | ||
| 1102 | * Returns a ClientHello message to kickstart renegotiations | ||
| 1103 | */ | ||
| 1104 | HandshakeMessage getKickstartMessage() throws SSLException { | ||
| 1105 | // session ID of the ClientHello message | ||
| 1106 | SessionId sessionId = SSLSessionImpl.nullSession.getSessionId(); | ||
| 1107 | |||
| 1108 | // a list of cipher suites sent by the client | ||
| 1109 | CipherSuiteList cipherSuites = getActiveCipherSuites(); | ||
| 1110 | |||
| 1111 | // set the max protocol version this client is supporting. | ||
| 1112 | maxProtocolVersion = protocolVersion; | ||
| 1113 | |||
| 1114 | // | ||
| 1115 | // Try to resume an existing session. This might be mandatory, | ||
| 1116 | // given certain API options. | ||
| 1117 | // | ||
| 1118 | session = ((SSLSessionContextImpl)sslContext | ||
| 1119 | .engineGetClientSessionContext()) | ||
| 1120 | .get(getHostSE(), getPortSE()); | ||
| 1121 | if (debug != null && Debug.isOn("session")) { | ||
| 1122 | if (session != null) { | ||
| 1123 | System.out.println("%% Client cached " | ||
| 1124 | + session | ||
| 1125 | + (session.isRejoinable() ? "" : " (not rejoinable)")); | ||
| 1126 | } else { | ||
| 1127 | System.out.println("%% No cached client session"); | ||
| 1128 | } | ||
| 1129 | } | ||
| 1130 | if ((session != null) && (session.isRejoinable() == false)) { | ||
| 1131 | session = null; | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | if (session != null) { | ||
| 1135 | CipherSuite sessionSuite = session.getSuite(); | ||
| 1136 | ProtocolVersion sessionVersion = session.getProtocolVersion(); | ||
| 1137 | if (isNegotiable(sessionSuite) == false) { | ||
| 1138 | if (debug != null && Debug.isOn("session")) { | ||
| 1139 | System.out.println("%% can't resume, unavailable cipher"); | ||
| 1140 | } | ||
| 1141 | session = null; | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | if ((session != null) && !isNegotiable(sessionVersion)) { | ||
| 1145 | if (debug != null && Debug.isOn("session")) { | ||
| 1146 | System.out.println("%% can't resume, protocol disabled"); | ||
| 1147 | } | ||
| 1148 | session = null; | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | if (session != null) { | ||
| 1152 | if (debug != null) { | ||
| 1153 | if (Debug.isOn("handshake") || Debug.isOn("session")) { | ||
| 1154 | System.out.println("%% Try resuming " + session | ||
| 1155 | + " from port " + getLocalPortSE()); | ||
| 1156 | } | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | sessionId = session.getSessionId(); | ||
| 1160 | maxProtocolVersion = sessionVersion; | ||
| 1161 | |||
| 1162 | // Update SSL version number in underlying SSL socket and | ||
| 1163 | // handshake output stream, so that the output records (at the | ||
| 1164 | // record layer) have the correct version | ||
| 1165 | setVersion(sessionVersion); | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | /* | ||
| 1169 | * Force use of the previous session ciphersuite, and | ||
| 1170 | * add the SCSV if enabled. | ||
| 1171 | */ | ||
| 1172 | if (!enableNewSession) { | ||
| 1173 | if (session == null) { | ||
| 1174 | throw new SSLHandshakeException( | ||
| 1175 | "Can't reuse existing SSL client session"); | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | Collection<CipherSuite> cipherList = new ArrayList<>(2); | ||
| 1179 | cipherList.add(sessionSuite); | ||
| 1180 | if (!secureRenegotiation && | ||
| 1181 | cipherSuites.contains(CipherSuite.C_SCSV)) { | ||
| 1182 | cipherList.add(CipherSuite.C_SCSV); | ||
| 1183 | } // otherwise, renegotiation_info extension will be used | ||
| 1184 | |||
| 1185 | cipherSuites = new CipherSuiteList(cipherList); | ||
| 1186 | } | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | if (session == null && !enableNewSession) { | ||
| 1190 | throw new SSLHandshakeException("No existing session to resume"); | ||
| 1191 | } | ||
| 1192 | |||
| 1193 | // exclude SCSV for secure renegotiation | ||
| 1194 | if (secureRenegotiation && cipherSuites.contains(CipherSuite.C_SCSV)) { | ||
| 1195 | Collection<CipherSuite> cipherList = | ||
| 1196 | new ArrayList<>(cipherSuites.size() - 1); | ||
| 1197 | for (CipherSuite suite : cipherSuites.collection()) { | ||
| 1198 | if (suite != CipherSuite.C_SCSV) { | ||
| 1199 | cipherList.add(suite); | ||
| 1200 | } | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | cipherSuites = new CipherSuiteList(cipherList); | ||
| 1204 | } | ||
| 1205 | |||
| 1206 | // make sure there is a negotiable cipher suite. | ||
| 1207 | boolean negotiable = false; | ||
| 1208 | for (CipherSuite suite : cipherSuites.collection()) { | ||
| 1209 | if (isNegotiable(suite)) { | ||
| 1210 | negotiable = true; | ||
| 1211 | break; | ||
| 1212 | } | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | if (!negotiable) { | ||
| 1216 | throw new SSLHandshakeException("No negotiable cipher suite"); | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | // Not a TLS1.2+ handshake | ||
| 1220 | // For SSLv2Hello, HandshakeHash.reset() will be called, so we | ||
| 1221 | // cannot call HandshakeHash.protocolDetermined() here. As it does | ||
| 1222 | // not follow the spec that HandshakeHash.reset() can be only be | ||
| 1223 | // called before protocolDetermined. | ||
| 1224 | // if (maxProtocolVersion.v < ProtocolVersion.TLS12.v) { | ||
| 1225 | // handshakeHash.protocolDetermined(maxProtocolVersion); | ||
| 1226 | // } | ||
| 1227 | |||
| 1228 | // create the ClientHello message | ||
| 1229 | ClientHello clientHelloMessage = new ClientHello( | ||
| 1230 | sslContext.getSecureRandom(), maxProtocolVersion, | ||
| 1231 | sessionId, cipherSuites); | ||
| 1232 | |||
| 1233 | // add signature_algorithm extension | ||
| 1234 | if (maxProtocolVersion.v >= ProtocolVersion.TLS12.v) { | ||
| 1235 | // we will always send the signature_algorithm extension | ||
| 1236 | Collection<SignatureAndHashAlgorithm> localSignAlgs = | ||
| 1237 | getLocalSupportedSignAlgs(); | ||
| 1238 | if (localSignAlgs.isEmpty()) { | ||
| 1239 | throw new SSLHandshakeException( | ||
| 1240 | "No supported signature algorithm"); | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | clientHelloMessage.addSignatureAlgorithmsExtension(localSignAlgs); | ||
| 1244 | } | ||
| 1245 | |||
| 1246 | // add server_name extension | ||
| 1247 | if (enableSNIExtension) { | ||
| 1248 | // We cannot use the hostname resolved from name services. For | ||
| 1249 | // virtual hosting, multiple hostnames may be bound to the same IP | ||
| 1250 | // address, so the hostname resolved from name services is not | ||
| 1251 | // reliable. | ||
| 1252 | String hostname = getRawHostnameSE(); | ||
| 1253 | |||
| 1254 | // we only allow FQDN | ||
| 1255 | if (hostname != null && hostname.indexOf('.') > 0 && | ||
| 1256 | !IPAddressUtil.isIPv4LiteralAddress(hostname) && | ||
| 1257 | !IPAddressUtil.isIPv6LiteralAddress(hostname)) { | ||
| 1258 | clientHelloMessage.addServerNameIndicationExtension(hostname); | ||
| 1259 | } | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | // reset the client random cookie | ||
| 1263 | clnt_random = clientHelloMessage.clnt_random; | ||
| 1264 | |||
| 1265 | /* | ||
| 1266 | * need to set the renegotiation_info extension for: | ||
| 1267 | * 1: secure renegotiation | ||
| 1268 | * 2: initial handshake and no SCSV in the ClientHello | ||
| 1269 | * 3: insecure renegotiation and no SCSV in the ClientHello | ||
| 1270 | */ | ||
| 1271 | if (secureRenegotiation || | ||
| 1272 | !cipherSuites.contains(CipherSuite.C_SCSV)) { | ||
| 1273 | clientHelloMessage.addRenegotiationInfoExtension(clientVerifyData); | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | return clientHelloMessage; | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | /* | ||
| 1280 | * Fault detected during handshake. | ||
| 1281 | */ | ||
| 1282 | void handshakeAlert(byte description) throws SSLProtocolException { | ||
| 1283 | String message = Alerts.alertDescription(description); | ||
| 1284 | |||
| 1285 | if (debug != null && Debug.isOn("handshake")) { | ||
| 1286 | System.out.println("SSL - handshake alert: " + message); | ||
| 1287 | } | ||
| 1288 | throw new SSLProtocolException("handshake alert: " + message); | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | /* | ||
| 1292 | * Unless we are using an anonymous ciphersuite, the server always | ||
| 1293 | * sends a certificate message (for the CipherSuites we currently | ||
| 1294 | * support). The trust manager verifies the chain for us. | ||
| 1295 | */ | ||
| 1296 | private void serverCertificate(CertificateMsg mesg) throws IOException { | ||
| 1297 | if (debug != null && Debug.isOn("handshake")) { | ||
| 1298 | mesg.print(System.out); | ||
| 1299 | } | ||
| 1300 | X509Certificate[] peerCerts = mesg.getCertificateChain(); | ||
| 1301 | if (peerCerts.length == 0) { | ||
| 1302 | fatalSE(Alerts.alert_bad_certificate, | ||
| 1303 | "empty certificate chain"); | ||
| 1304 | } | ||
| 1305 | // ask the trust manager to verify the chain | ||
| 1306 | X509TrustManager tm = sslContext.getX509TrustManager(); | ||
| 1307 | try { | ||
| 1308 | // find out the key exchange algorithm used | ||
| 1309 | // use "RSA" for non-ephemeral "RSA_EXPORT" | ||
| 1310 | String keyExchangeString; | ||
| 1311 | if (keyExchange == K_RSA_EXPORT && !serverKeyExchangeReceived) { | ||
| 1312 | keyExchangeString = K_RSA.name; | ||
| 1313 | } else { | ||
| 1314 | keyExchangeString = keyExchange.name; | ||
| 1315 | } | ||
| 1316 | |||
| 1317 | if (tm instanceof X509ExtendedTrustManager) { | ||
| 1318 | if (conn != null) { | ||
| 1319 | ((X509ExtendedTrustManager)tm).checkServerTrusted( | ||
| 1320 | peerCerts.clone(), | ||
| 1321 | keyExchangeString, | ||
| 1322 | conn); | ||
| 1323 | } else { | ||
| 1324 | ((X509ExtendedTrustManager)tm).checkServerTrusted( | ||
| 1325 | peerCerts.clone(), | ||
| 1326 | keyExchangeString, | ||
| 1327 | engine); | ||
| 1328 | } | ||
| 1329 | } else { | ||
| 1330 | // Unlikely to happen, because we have wrapped the old | ||
| 1331 | // X509TrustManager with the new X509ExtendedTrustManager. | ||
| 1332 | throw new CertificateException( | ||
| 1333 | "Improper X509TrustManager implementation"); | ||
| 1334 | } | ||
| 1335 | } catch (CertificateException e) { | ||
| 1336 | // This will throw an exception, so include the original error. | ||
| 1337 | fatalSE(Alerts.alert_certificate_unknown, e); | ||
| 1338 | } | ||
| 1339 | session.setPeerCertificates(peerCerts); | ||
| 1340 | } | ||
| 1341 | } | ||