1 /* 2 * Copyright 1996-2008 Sun Microsystems, Inc. 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. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any questions. 24 */ 25 26 27 package sun.security.ssl; 28 29 import java.io.*; 30 import java.math.BigInteger; 31 import java.security.*; 32 import java.util.*; 33 34 import java.security.interfaces.ECPublicKey; 35 import java.security.interfaces.RSAPublicKey; 36 import java.security.spec.ECParameterSpec; 37 38 import java.security.cert.X509Certificate; 39 import java.security.cert.CertificateException; 40 41 import javax.crypto.SecretKey; 42 import javax.crypto.spec.SecretKeySpec; 43 44 import javax.net.ssl.*; 45 46 import javax.security.auth.Subject; 47 import javax.security.auth.kerberos.KerberosPrincipal; 48 import sun.security.jgss.krb5.Krb5Util; 49 import sun.security.jgss.GSSUtil; 50 51 import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager; 52 53 import sun.security.ssl.HandshakeMessage.*; 54 import sun.security.ssl.CipherSuite.*; 55 import static sun.security.ssl.CipherSuite.*; 56 import static sun.security.ssl.CipherSuite.KeyExchange.*; 57 58 /** 59 * ClientHandshaker does the protocol handshaking from the point 60 * of view of a client. It is driven asychronously by handshake messages 61 * as delivered by the parent Handshaker class, and also uses 62 * common functionality (e.g. key generation) that is provided there. 63 * 64 * @author David Brownell 65 */ 66 final class ClientHandshaker extends Handshaker { 67 68 // the server's public key from its certificate. 69 private PublicKey serverKey; 70 71 // the server's ephemeral public key from the server key exchange message 72 // for ECDHE/ECDH_anon and RSA_EXPORT. 73 private PublicKey ephemeralServerKey; 74 75 // server's ephemeral public value for DHE/DH_anon key exchanges 76 private BigInteger serverDH; 77 78 private DHCrypt dh; 79 80 private ECDHCrypt ecdh; 81 82 private CertificateRequest certRequest; 83 84 private boolean serverKeyExchangeReceived; 85 86 /* 87 * The RSA PreMasterSecret needs to know the version of 88 * ClientHello that was used on this handshake. This represents 89 * the "max version" this client is supporting. In the 90 * case of an initial handshake, it's the max version enabled, 91 * but in the case of a resumption attempt, it's the version 92 * of the session we're trying to resume. 93 */ 94 private ProtocolVersion maxProtocolVersion; 95 96 /* 97 * Constructors 98 */ 99 ClientHandshaker(SSLSocketImpl socket, SSLContextImpl context, 100 ProtocolList enabledProtocols) { 101 super(socket, context, enabledProtocols, true, true); 102 } 103 104 ClientHandshaker(SSLEngineImpl engine, SSLContextImpl context, 105 ProtocolList enabledProtocols) { 106 super(engine, context, enabledProtocols, true, true); 107 } 108 109 /* 110 * This routine handles all the client side handshake messages, one at 111 * a time. Given the message type (and in some cases the pending cipher 112 * spec) it parses the type-specific message. Then it calls a function 113 * that handles that specific message. 114 * 115 * It updates the state machine (need to verify it) as each message 116 * is processed, and writes responses as needed using the connection 117 * in the constructor. 118 */ 119 void processMessage(byte type, int messageLen) throws IOException { 120 if (state > type 121 && (type != HandshakeMessage.ht_hello_request 122 && state != HandshakeMessage.ht_client_hello)) { 123 throw new SSLProtocolException( 124 "Handshake message sequence violation, " + type); 125 } 126 127 switch (type) { 128 case HandshakeMessage.ht_hello_request: 129 this.serverHelloRequest(new HelloRequest(input)); 130 break; 131 132 case HandshakeMessage.ht_server_hello: 133 this.serverHello(new ServerHello(input, messageLen)); 134 break; 135 136 case HandshakeMessage.ht_certificate: 137 if (keyExchange == K_DH_ANON || keyExchange == K_ECDH_ANON 138 || keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) { 139 fatalSE(Alerts.alert_unexpected_message, 140 "unexpected server cert chain"); 141 // NOTREACHED 142 } 143 this.serverCertificate(new CertificateMsg(input)); 144 serverKey = 145 session.getPeerCertificates()[0].getPublicKey(); 146 break; 147 148 case HandshakeMessage.ht_server_key_exchange: 149 serverKeyExchangeReceived = true; 150 switch (keyExchange) { 151 case K_RSA_EXPORT: 152 /** 153 * The server key exchange message is sent by the server only 154 * when the server certificate message does not contain the 155 * proper amount of data to allow the client to exchange a 156 * premaster secret, such as when RSA_EXPORT is used and the 157 * public key in the server certificate is longer than 512 bits. 158 */ 159 if (serverKey == null) { 160 throw new SSLProtocolException 161 ("Server did not send certificate message"); 162 } 163 164 if (!(serverKey instanceof RSAPublicKey)) { 165 throw new SSLProtocolException("Protocol violation:" + 166 " the certificate type must be appropriate for the" + 167 " selected cipher suite's key exchange algorithm"); 168 } 169 170 if (JsseJce.getRSAKeyLength(serverKey) <= 512) { 171 throw new SSLProtocolException("Protocol violation:" + 172 " server sent a server key exchange message for" + 173 " key exchange " + keyExchange + 174 " when the public key in the server certificate" + 175 " is less than or equal to 512 bits in length"); 176 } 177 178 try { 179 this.serverKeyExchange(new RSA_ServerKeyExchange(input)); 180 } catch (GeneralSecurityException e) { 181 throwSSLException("Server key", e); 182 } 183 break; 184 case K_DH_ANON: 185 this.serverKeyExchange(new DH_ServerKeyExchange(input)); 186 break; 187 case K_DHE_DSS: 188 case K_DHE_RSA: 189 try { 190 this.serverKeyExchange(new DH_ServerKeyExchange( 191 input, serverKey, 192 clnt_random.random_bytes, svr_random.random_bytes, 193 messageLen)); 194 } catch (GeneralSecurityException e) { 195 throwSSLException("Server key", e); 196 } 197 break; 198 case K_ECDHE_ECDSA: 199 case K_ECDHE_RSA: 200 case K_ECDH_ANON: 201 try { 202 this.serverKeyExchange(new ECDH_ServerKeyExchange 203 (input, serverKey, clnt_random.random_bytes, 204 svr_random.random_bytes)); 205 } catch (GeneralSecurityException e) { 206 throwSSLException("Server key", e); 207 } 208 break; 209 case K_RSA: 210 case K_DH_RSA: 211 case K_DH_DSS: 212 case K_ECDH_ECDSA: 213 case K_ECDH_RSA: 214 throw new SSLProtocolException("Protocol violation: server sent" 215 + " a server key exchange message for key exchange " + keyExchange); 216 case K_KRB5: 217 case K_KRB5_EXPORT: 218 throw new SSLProtocolException( 219 "unexpected receipt of server key exchange algorithm"); 220 default: 221 throw new SSLProtocolException( 222 "unsupported key exchange algorithm = " 223 + keyExchange); 224 } 225 break; 226 227 case HandshakeMessage.ht_certificate_request: 228 // save for later, it's handled by serverHelloDone 229 if ((keyExchange == K_DH_ANON) || (keyExchange == K_ECDH_ANON)) { 230 throw new SSLHandshakeException( 231 "Client authentication requested for "+ 232 "anonymous cipher suite."); 233 } else if (keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) { 234 throw new SSLHandshakeException( 235 "Client certificate requested for "+ 236 "kerberos cipher suite."); 237 } 238 certRequest = new CertificateRequest(input); 239 if (debug != null && Debug.isOn("handshake")) { 240 certRequest.print(System.out); 241 } 242 break; 243 244 case HandshakeMessage.ht_server_hello_done: 245 this.serverHelloDone(new ServerHelloDone(input)); 246 break; 247 248 case HandshakeMessage.ht_finished: 249 this.serverFinished(new Finished(protocolVersion, input)); 250 break; 251 252 default: 253 throw new SSLProtocolException( 254 "Illegal client handshake msg, " + type); 255 } 256 257 // 258 // Move state machine forward if the message handling 259 // code didn't already do so 260 // 261 if (state < type) { 262 state = type; 263 } 264 } 265 266 /* 267 * Used by the server to kickstart negotiations -- this requests a 268 * "client hello" to renegotiate current cipher specs (e.g. maybe lots 269 * of data has been encrypted with the same keys, or the server needs 270 * the client to present a certificate). 271 */ 272 private void serverHelloRequest(HelloRequest mesg) throws IOException { 273 if (debug != null && Debug.isOn("handshake")) { 274 mesg.print(System.out); 275 } 276 277 // 278 // Could be (e.g. at connection setup) that we already 279 // sent the "client hello" but the server's not seen it. 280 // 281 if (state < HandshakeMessage.ht_client_hello) { 282 kickstart(); 283 } 284 } 285 286 287 /* 288 * Server chooses session parameters given options created by the 289 * client -- basically, cipher options, session id, and someday a 290 * set of compression options. 291 * 292 * There are two branches of the state machine, decided by the 293 * details of this message. One is the "fast" handshake, where we 294 * can resume the pre-existing session we asked resume. The other 295 * is a more expensive "full" handshake, with key exchange and 296 * probably authentication getting done. 297 */ 298 private void serverHello(ServerHello mesg) throws IOException { 299 serverKeyExchangeReceived = false; 300 if (debug != null && Debug.isOn("handshake")) { 301 mesg.print(System.out); 302 } 303 304 // check if the server selected protocol version is OK for us 305 ProtocolVersion mesgVersion = mesg.protocolVersion; 306 if (enabledProtocols.contains(mesgVersion) == false) { 307 throw new SSLHandshakeException 308 ("Server chose unsupported or disabled protocol: " + mesgVersion); 309 } 310 311 // Set protocolVersion and propagate to SSLSocket and the 312 // Handshake streams 313 setVersion(mesgVersion); 314 315 // 316 // Save server nonce, we always use it to compute connection 317 // keys and it's also used to create the master secret if we're 318 // creating a new session (i.e. in the full handshake). 319 // 320 svr_random = mesg.svr_random; 321 322 if (isEnabled(mesg.cipherSuite) == false) { 323 fatalSE(Alerts.alert_illegal_parameter, 324 "Server selected disabled ciphersuite " + cipherSuite); 325 } 326 setCipherSuite(mesg.cipherSuite); 327 328 if (mesg.compression_method != 0) { 329 fatalSE(Alerts.alert_illegal_parameter, 330 "compression type not supported, " 331 + mesg.compression_method); 332 // NOTREACHED 333 } 334 335 // so far so good, let's look at the session 336 if (session != null) { 337 // we tried to resume, let's see what the server decided 338 if (session.getSessionId().equals(mesg.sessionId)) { 339 // server resumed the session, let's make sure everything 340 // checks out 341 342 // Verify that the session ciphers are unchanged. 343 CipherSuite sessionSuite = session.getSuite(); 344 if (cipherSuite != sessionSuite) { 345 throw new SSLProtocolException 346 ("Server returned wrong cipher suite for session"); 347 } 348 349 // verify protocol version match 350 ProtocolVersion sessionVersion = session.getProtocolVersion(); 351 if (protocolVersion != sessionVersion) { 352 throw new SSLProtocolException 353 ("Server resumed session with wrong protocol version"); 354 } 355 356 // validate subject identity 357 if (sessionSuite.keyExchange == K_KRB5 || 358 sessionSuite.keyExchange == K_KRB5_EXPORT) { 359 Principal localPrincipal = session.getLocalPrincipal(); 360 361 Subject subject = null; 362 try { 363 subject = AccessController.doPrivileged( 364 new PrivilegedExceptionAction<Subject>() { 365 public Subject run() throws Exception { 366 return Krb5Util.getSubject( 367 GSSUtil.CALLER_SSL_CLIENT, 368 getAccSE()); 369 }}); 370 } catch (PrivilegedActionException e) { 371 subject = null; 372 if (debug != null && Debug.isOn("session")) { 373 System.out.println("Attempt to obtain" + 374 " subject failed!"); 375 } 376 } 377 378 if (subject != null) { 379 Set<KerberosPrincipal> principals = 380 subject.getPrincipals(KerberosPrincipal.class); 381 if (!principals.contains(localPrincipal)) { 382 throw new SSLProtocolException("Server resumed" + 383 " session with wrong subject identity"); 384 } else { 385 if (debug != null && Debug.isOn("session")) 386 System.out.println("Subject identity is same"); 387 } 388 } else { 389 if (debug != null && Debug.isOn("session")) 390 System.out.println("Kerberos credentials are not" + 391 " present in the current Subject; check if " + 392 " javax.security.auth.useSubjectAsCreds" + 393 " system property has been set to false"); 394 throw new SSLProtocolException 395 ("Server resumed session with no subject"); 396 } 397 } 398 399 // looks fine; resume it, and update the state machine. 400 resumingSession = true; 401 state = HandshakeMessage.ht_finished - 1; 402 calculateConnectionKeys(session.getMasterSecret()); 403 if (debug != null && Debug.isOn("session")) { 404 System.out.println("%% Server resumed " + session); 405 } 406 return; 407 } else { 408 // we wanted to resume, but the server refused 409 session = null; 410 if (!enableNewSession) { 411 throw new SSLException 412 ("New session creation is disabled"); 413 } 414 } 415 } 416 417 // check extensions 418 for (HelloExtension ext : mesg.extensions.list()) { 419 ExtensionType type = ext.type; 420 if ((type != ExtensionType.EXT_ELLIPTIC_CURVES) 421 && (type != ExtensionType.EXT_EC_POINT_FORMATS) 422 && (type != ExtensionType.EXT_SERVER_NAME)) { 423 fatalSE(Alerts.alert_unsupported_extension, 424 "Server sent an unsupported extension: " + type); 425 } 426 } 427 428 // Create a new session, we need to do the full handshake 429 session = new SSLSessionImpl(protocolVersion, cipherSuite, 430 mesg.sessionId, getHostSE(), getPortSE()); 431 if (debug != null && Debug.isOn("handshake")) { 432 System.out.println("** " + cipherSuite); 433 } 434 } 435 436 /* 437 * Server's own key was either a signing-only key, or was too 438 * large for export rules ... this message holds an ephemeral 439 * RSA key to use for key exchange. 440 */ 441 private void serverKeyExchange(RSA_ServerKeyExchange mesg) 442 throws IOException, GeneralSecurityException { 443 if (debug != null && Debug.isOn("handshake")) { 444 mesg.print(System.out); 445 } 446 if (!mesg.verify(serverKey, clnt_random, svr_random)) { 447 fatalSE(Alerts.alert_handshake_failure, 448 "server key exchange invalid"); 449 // NOTREACHED 450 } 451 ephemeralServerKey = mesg.getPublicKey(); 452 } 453 454 455 /* 456 * Diffie-Hellman key exchange. We save the server public key and 457 * our own D-H algorithm object so we can defer key calculations 458 * until after we've sent the client key exchange message (which 459 * gives client and server some useful parallelism). 460 */ 461 private void serverKeyExchange(DH_ServerKeyExchange mesg) 462 throws IOException { 463 if (debug != null && Debug.isOn("handshake")) { 464 mesg.print(System.out); 465 } 466 dh = new DHCrypt(mesg.getModulus(), mesg.getBase(), sslContext.getSecureRandom()); 467 serverDH = mesg.getServerPublicKey(); 468 } 469 470 private void serverKeyExchange(ECDH_ServerKeyExchange mesg) throws IOException { 471 if (debug != null && Debug.isOn("handshake")) { 472 mesg.print(System.out); 473 } 474 ECPublicKey key = mesg.getPublicKey(); 475 ecdh = new ECDHCrypt(key.getParams(), sslContext.getSecureRandom()); 476 ephemeralServerKey = key; 477 } 478 479 /* 480 * The server's "Hello Done" message is the client's sign that 481 * it's time to do all the hard work. 482 */ 483 private void serverHelloDone(ServerHelloDone mesg) throws IOException { 484 if (debug != null && Debug.isOn("handshake")) { 485 mesg.print(System.out); 486 } 487 /* 488 * Always make sure the input has been digested before we 489 * start emitting data, to ensure the hashes are correctly 490 * computed for the Finished and CertificateVerify messages 491 * which we send (here). 492 */ 493 input.digestNow(); 494 495 /* 496 * FIRST ... if requested, send an appropriate Certificate chain 497 * to authenticate the client, and remember the associated private 498 * key to sign the CertificateVerify message. 499 */ 500 PrivateKey signingKey = null; 501 502 if (certRequest != null) { 503 X509ExtendedKeyManager km = sslContext.getX509KeyManager(); 504 505 ArrayList<String> keytypesTmp = new ArrayList<String>(4); 506 507 for (int i = 0; i < certRequest.types.length; i++) { 508 String typeName; 509 510 switch (certRequest.types[i]) { 511 case CertificateRequest.cct_rsa_sign: 512 typeName = "RSA"; 513 break; 514 515 case CertificateRequest.cct_dss_sign: 516 typeName = "DSA"; 517 break; 518 519 case CertificateRequest.cct_ecdsa_sign: 520 // ignore if we do not have EC crypto available 521 typeName = JsseJce.isEcAvailable() ? "EC" : null; 522 break; 523 524 // Fixed DH/ECDH client authentication not supported 525 case CertificateRequest.cct_rsa_fixed_dh: 526 case CertificateRequest.cct_dss_fixed_dh: 527 case CertificateRequest.cct_rsa_fixed_ecdh: 528 case CertificateRequest.cct_ecdsa_fixed_ecdh: 529 // Any other values (currently not used in TLS) 530 case CertificateRequest.cct_rsa_ephemeral_dh: 531 case CertificateRequest.cct_dss_ephemeral_dh: 532 default: 533 typeName = null; 534 break; 535 } 536 537 if ((typeName != null) && (!keytypesTmp.contains(typeName))) { 538 keytypesTmp.add(typeName); 539 } 540 } 541 542 String alias = null; 543 int keytypesTmpSize = keytypesTmp.size(); 544 if (keytypesTmpSize != 0) { 545 String keytypes[] = 546 keytypesTmp.toArray(new String[keytypesTmpSize]); 547 548 if (conn != null) { 549 alias = km.chooseClientAlias(keytypes, 550 certRequest.getAuthorities(), conn); 551 } else { 552 alias = km.chooseEngineClientAlias(keytypes, 553 certRequest.getAuthorities(), engine); 554 } 555 } 556 557 CertificateMsg m1 = null; 558 if (alias != null) { 559 X509Certificate[] certs = km.getCertificateChain(alias); 560 if ((certs != null) && (certs.length != 0)) { 561 PublicKey publicKey = certs[0].getPublicKey(); 562 // for EC, make sure we use a supported named curve 563 if (publicKey instanceof ECPublicKey) { 564 ECParameterSpec params = ((ECPublicKey)publicKey).getParams(); 565 int index = SupportedEllipticCurvesExtension.getCurveIndex(params); 566 if (!SupportedEllipticCurvesExtension.isSupported(index)) { 567 publicKey = null; 568 } 569 } 570 if (publicKey != null) { 571 m1 = new CertificateMsg(certs); 572 signingKey = km.getPrivateKey(alias); 573 session.setLocalPrivateKey(signingKey); 574 session.setLocalCertificates(certs); 575 } 576 } 577 } 578 if (m1 == null) { 579 // 580 // No appropriate cert was found ... report this to the 581 // server. For SSLv3, send the no_certificate alert; 582 // TLS uses an empty cert chain instead. 583 // 584 if (protocolVersion.v >= ProtocolVersion.TLS10.v) { 585 m1 = new CertificateMsg(new X509Certificate [0]); 586 } else { 587 warningSE(Alerts.alert_no_certificate); 588 } 589 } 590 591 // 592 // At last ... send any client certificate chain. 593 // 594 if (m1 != null) { 595 if (debug != null && Debug.isOn("handshake")) { 596 m1.print(System.out); 597 } 598 m1.write(output); 599 } 600 } 601 602 /* 603 * SECOND ... send the client key exchange message. The 604 * procedure used is a function of the cipher suite selected; 605 * one is always needed. 606 */ 607 HandshakeMessage m2; 608 609 switch (keyExchange) { 610 611 case K_RSA: 612 case K_RSA_EXPORT: 613 if (serverKey == null) { 614 throw new SSLProtocolException 615 ("Server did not send certificate message"); 616 } 617 618 if (!(serverKey instanceof RSAPublicKey)) { 619 throw new SSLProtocolException 620 ("Server certificate does not include an RSA key"); 621 } 622 623 /* 624 * For RSA key exchange, we randomly generate a new 625 * pre-master secret and encrypt it with the server's 626 * public key. Then we save that pre-master secret 627 * so that we can calculate the keying data later; 628 * it's a performance speedup not to do that until 629 * the client's waiting for the server response, but 630 * more of a speedup for the D-H case. 631 * 632 * If the RSA_EXPORT scheme is active, when the public 633 * key in the server certificate is less than or equal 634 * to 512 bits in length, use the cert's public key, 635 * otherwise, the ephemeral one. 636 */ 637 PublicKey key; 638 if (keyExchange == K_RSA) { 639 key = serverKey; 640 } else { // K_RSA_EXPORT 641 if (JsseJce.getRSAKeyLength(serverKey) <= 512) { 642 // extraneous ephemeralServerKey check done 643 // above in processMessage() 644 key = serverKey; 645 } else { 646 if (ephemeralServerKey == null) { 647 throw new SSLProtocolException("Server did not send" + 648 " a RSA_EXPORT Server Key Exchange message"); 649 } 650 key = ephemeralServerKey; 651 } 652 } 653 654 m2 = new RSAClientKeyExchange(protocolVersion, maxProtocolVersion, 655 sslContext.getSecureRandom(), key); 656 break; 657 case K_DH_RSA: 658 case K_DH_DSS: 659 /* 660 * For DH Key exchange, we only need to make sure the server 661 * knows our public key, so we calculate the same pre-master 662 * secret. 663 * 664 * For certs that had DH keys in them, we send an empty 665 * handshake message (no key) ... we flag this case by 666 * passing a null "dhPublic" value. 667 * 668 * Otherwise we send ephemeral DH keys, unsigned. 669 */ 670 // if (useDH_RSA || useDH_DSS) 671 m2 = new DHClientKeyExchange(); 672 break; 673 case K_DHE_RSA: 674 case K_DHE_DSS: 675 case K_DH_ANON: 676 if (dh == null) { 677 throw new SSLProtocolException 678 ("Server did not send a DH Server Key Exchange message"); 679 } 680 m2 = new DHClientKeyExchange(dh.getPublicKey()); 681 break; 682 case K_ECDHE_RSA: 683 case K_ECDHE_ECDSA: 684 case K_ECDH_ANON: 685 if (ecdh == null) { 686 throw new SSLProtocolException 687 ("Server did not send a ECDH Server Key Exchange message"); 688 } 689 m2 = new ECDHClientKeyExchange(ecdh.getPublicKey()); 690 break; 691 case K_ECDH_RSA: 692 case K_ECDH_ECDSA: 693 if (serverKey == null) { 694 throw new SSLProtocolException 695 ("Server did not send certificate message"); 696 } 697 if (serverKey instanceof ECPublicKey == false) { 698 throw new SSLProtocolException 699 ("Server certificate does not include an EC key"); 700 } 701 ECParameterSpec params = ((ECPublicKey)serverKey).getParams(); 702 ecdh = new ECDHCrypt(params, sslContext.getSecureRandom()); 703 m2 = new ECDHClientKeyExchange(ecdh.getPublicKey()); 704 break; 705 case K_KRB5: 706 case K_KRB5_EXPORT: 707 String hostname = getHostSE(); 708 if (hostname == null) { 709 throw new IOException("Hostname is required" + 710 " to use Kerberos cipher suites"); 711 } 712 KerberosClientKeyExchange kerberosMsg = new KerberosClientKeyExchange 713 (hostname, isLoopbackSE(), getAccSE(), protocolVersion, 714 sslContext.getSecureRandom()); 715 // Record the principals involved in exchange 716 session.setPeerPrincipal(kerberosMsg.getPeerPrincipal()); 717 session.setLocalPrincipal(kerberosMsg.getLocalPrincipal()); 718 m2 = kerberosMsg; 719 break; 720 default: 721 // somethings very wrong 722 throw new RuntimeException 723 ("Unsupported key exchange: " + keyExchange); 724 } 725 if (debug != null && Debug.isOn("handshake")) { 726 m2.print(System.out); 727 } 728 m2.write(output); 729 730 731 /* 732 * THIRD, send a "change_cipher_spec" record followed by the 733 * "Finished" message. We flush the messages we've queued up, to 734 * get concurrency between client and server. The concurrency is 735 * useful as we calculate the master secret, which is needed both 736 * to compute the "Finished" message, and to compute the keys used 737 * to protect all records following the change_cipher_spec. 738 */ 739 740 output.doHashes(); 741 output.flush(); 742 743 /* 744 * We deferred calculating the master secret and this connection's 745 * keying data; we do it now. Deferring this calculation is good 746 * from a performance point of view, since it lets us do it during 747 * some time that network delays and the server's own calculations 748 * would otherwise cause to be "dead" in the critical path. 749 */ 750 SecretKey preMasterSecret; 751 switch (keyExchange) { 752 case K_RSA: 753 case K_RSA_EXPORT: 754 preMasterSecret = ((RSAClientKeyExchange)m2).preMaster; 755 break; 756 case K_KRB5: 757 case K_KRB5_EXPORT: 758 byte[] secretBytes = 759 ((KerberosClientKeyExchange)m2).getPreMasterSecret().getUnencrypted(); 760 preMasterSecret = new SecretKeySpec(secretBytes, "TlsPremasterSecret"); 761 break; 762 case K_DHE_RSA: 763 case K_DHE_DSS: 764 case K_DH_ANON: 765 preMasterSecret = dh.getAgreedSecret(serverDH); 766 break; 767 case K_ECDHE_RSA: 768 case K_ECDHE_ECDSA: 769 case K_ECDH_ANON: 770 preMasterSecret = ecdh.getAgreedSecret(ephemeralServerKey); 771 break; 772 case K_ECDH_RSA: 773 case K_ECDH_ECDSA: 774 preMasterSecret = ecdh.getAgreedSecret(serverKey); 775 break; 776 default: 777 throw new IOException("Internal error: unknown key exchange " + keyExchange); 778 } 779 780 calculateKeys(preMasterSecret, null); 781 782 /* 783 * FOURTH, if we sent a Certificate, we need to send a signed 784 * CertificateVerify (unless the key in the client's certificate 785 * was a Diffie-Hellman key).). 786 * 787 * This uses a hash of the previous handshake messages ... either 788 * a nonfinal one (if the particular implementation supports it) 789 * or else using the third element in the arrays of hashes being 790 * computed. 791 */ 792 if (signingKey != null) { 793 CertificateVerify m3; 794 try { 795 m3 = new CertificateVerify(protocolVersion, handshakeHash, 796 signingKey, session.getMasterSecret(), 797 sslContext.getSecureRandom()); 798 } catch (GeneralSecurityException e) { 799 fatalSE(Alerts.alert_handshake_failure, 800 "Error signing certificate verify", e); 801 // NOTREACHED, make compiler happy 802 m3 = null; 803 } 804 if (debug != null && Debug.isOn("handshake")) { 805 m3.print(System.out); 806 } 807 m3.write(output); 808 output.doHashes(); 809 } 810 811 /* 812 * OK, that's that! 813 */ 814 sendChangeCipherAndFinish(false); 815 } 816 817 818 /* 819 * "Finished" is the last handshake message sent. If we got this 820 * far, the MAC has been validated post-decryption. We validate 821 * the two hashes here as an additional sanity check, protecting 822 * the handshake against various active attacks. 823 */ 824 private void serverFinished(Finished mesg) throws IOException { 825 if (debug != null && Debug.isOn("handshake")) { 826 mesg.print(System.out); 827 } 828 829 boolean verified = mesg.verify(protocolVersion, handshakeHash, 830 Finished.SERVER, session.getMasterSecret()); 831 832 if (!verified) { 833 fatalSE(Alerts.alert_illegal_parameter, 834 "server 'finished' message doesn't verify"); 835 // NOTREACHED 836 } 837 838 /* 839 * OK, it verified. If we're doing the fast handshake, add that 840 * "Finished" message to the hash of handshake messages, then send 841 * our own change_cipher_spec and Finished message for the server 842 * to verify in turn. These are the last handshake messages. 843 * 844 * In any case, update the session cache. We're done handshaking, 845 * so there are no threats any more associated with partially 846 * completed handshakes. 847 */ 848 if (resumingSession) { 849 input.digestNow(); 850 sendChangeCipherAndFinish(true); 851 } 852 session.setLastAccessedTime(System.currentTimeMillis()); 853 854 if (!resumingSession) { 855 if (session.isRejoinable()) { 856 ((SSLSessionContextImpl) sslContext 857 .engineGetClientSessionContext()) 858 .put(session); 859 if (debug != null && Debug.isOn("session")) { 860 System.out.println("%% Cached client session: " + session); 861 } 862 } else if (debug != null && Debug.isOn("session")) { 863 System.out.println( 864 "%% Didn't cache non-resumable client session: " 865 + session); 866 } 867 } 868 } 869 870 871 /* 872 * Send my change-cipher-spec and Finished message ... done as the 873 * last handshake act in either the short or long sequences. In 874 * the short one, we've already seen the server's Finished; in the 875 * long one, we wait for it now. 876 */ 877 private void sendChangeCipherAndFinish(boolean finishedTag) 878 throws IOException { 879 Finished mesg = new Finished(protocolVersion, handshakeHash, 880 Finished.CLIENT, session.getMasterSecret()); 881 882 /* 883 * Send the change_cipher_spec message, then the Finished message 884 * which we just calculated (and protected using the keys we just 885 * calculated). Server responds with its Finished message, except 886 * in the "fast handshake" (resume session) case. 887 */ 888 sendChangeCipherSpec(mesg, finishedTag); 889 890 /* 891 * Update state machine so server MUST send 'finished' next. 892 * (In "long" handshake case; in short case, we're responding 893 * to its message.) 894 */ 895 state = HandshakeMessage.ht_finished - 1; 896 } 897 898 899 /* 900 * Returns a ClientHello message to kickstart renegotiations 901 */ 902 HandshakeMessage getKickstartMessage() throws SSLException { 903 ClientHello mesg = new ClientHello(sslContext.getSecureRandom(), 904 protocolVersion); 905 maxProtocolVersion = protocolVersion; 906 907 clnt_random = mesg.clnt_random; 908 909 // 910 // Try to resume an existing session. This might be mandatory, 911 // given certain API options. 912 // 913 session = ((SSLSessionContextImpl)sslContext 914 .engineGetClientSessionContext()) 915 .get(getHostSE(), getPortSE()); 916 if (debug != null && Debug.isOn("session")) { 917 if (session != null) { 918 System.out.println("%% Client cached " 919 + session 920 + (session.isRejoinable() ? "" : " (not rejoinable)")); 921 } else { 922 System.out.println("%% No cached client session"); 923 } 924 } 925 if ((session != null) && (session.isRejoinable() == false)) { 926 session = null; 927 } 928 929 if (session != null) { 930 CipherSuite sessionSuite = session.getSuite(); 931 ProtocolVersion sessionVersion = session.getProtocolVersion(); 932 if (isEnabled(sessionSuite) == false) { 933 if (debug != null && Debug.isOn("session")) { 934 System.out.println("%% can't resume, cipher disabled"); 935 } 936 session = null; 937 } 938 939 if ((session != null) && 940 (enabledProtocols.contains(sessionVersion) == false)) { 941 if (debug != null && Debug.isOn("session")) { 942 System.out.println("%% can't resume, protocol disabled"); 943 } 944 session = null; 945 } 946 947 if (session != null) { 948 if (debug != null) { 949 if (Debug.isOn("handshake") || Debug.isOn("session")) { 950 System.out.println("%% Try resuming " + session 951 + " from port " + getLocalPortSE()); 952 } 953 } 954 mesg.sessionId = session.getSessionId(); 955 956 mesg.protocolVersion = sessionVersion; 957 maxProtocolVersion = sessionVersion; 958 959 // Update SSL version number in underlying SSL socket and 960 // handshake output stream, so that the output records (at the 961 // record layer) have the correct version 962 setVersion(sessionVersion); 963 } 964 965 // 966 // don't say much beyond the obvious if we _must_ resume. 967 // 968 if (!enableNewSession) { 969 if (session == null) { 970 throw new SSLException( 971 "Can't reuse existing SSL client session"); 972 } 973 mesg.setServerName(this.getHostSE()); 974 mesg.setCipherSuites(new CipherSuiteList(sessionSuite)); 975 return mesg; 976 } 977 } 978 if (session == null) { 979 if (enableNewSession) { 980 mesg.sessionId = SSLSessionImpl.nullSession.getSessionId(); 981 } else { 982 throw new SSLException("No existing session to resume."); 983 } 984 } 985 986 // Put an RFC4366 TLS server name indication extension into ClientHello. 987 mesg.setServerName(this.getHostSE()); 988 989 // 990 // All we have left to do is fill out the cipher suites. 991 // (If this changes, change the 'return' above!) 992 // 993 mesg.setCipherSuites(enabledCipherSuites); 994 995 return mesg; 996 } 997 998 /* 999 * Fault detected during handshake. 1000 */ 1001 void handshakeAlert(byte description) throws SSLProtocolException { 1002 String message = Alerts.alertDescription(description); 1003 1004 if (debug != null && Debug.isOn("handshake")) { 1005 System.out.println("SSL - handshake alert: " + message); 1006 } 1007 throw new SSLProtocolException("handshake alert: " + message); 1008 } 1009 1010 /* 1011 * Unless we are using an anonymous ciphersuite, the server always 1012 * sends a certificate message (for the CipherSuites we currently 1013 * support). The trust manager verifies the chain for us. 1014 */ 1015 private void serverCertificate(CertificateMsg mesg) throws IOException { 1016 if (debug != null && Debug.isOn("handshake")) { 1017 mesg.print(System.out); 1018 } 1019 X509Certificate[] peerCerts = mesg.getCertificateChain(); 1020 if (peerCerts.length == 0) { 1021 fatalSE(Alerts.alert_bad_certificate, 1022 "empty certificate chain"); 1023 } 1024 // ask the trust manager to verify the chain 1025 X509TrustManager tm = sslContext.getX509TrustManager(); 1026 try { 1027 // find out the key exchange algorithm used 1028 // use "RSA" for non-ephemeral "RSA_EXPORT" 1029 String keyExchangeString; 1030 if (keyExchange == K_RSA_EXPORT && !serverKeyExchangeReceived) { 1031 keyExchangeString = K_RSA.name; 1032 } else { 1033 keyExchangeString = keyExchange.name; 1034 } 1035 1036 String identificator = getHostnameVerificationSE(); 1037 if (tm instanceof X509ExtendedTrustManager) { 1038 ((X509ExtendedTrustManager)tm).checkServerTrusted( 1039 (peerCerts != null ? 1040 peerCerts.clone() : 1041 null), 1042 keyExchangeString, 1043 getHostSE(), 1044 identificator); 1045 } else { 1046 if (identificator != null) { 1047 throw new RuntimeException( 1048 "trust manager does not support peer identification"); 1049 } 1050 1051 tm.checkServerTrusted( 1052 (peerCerts != null ? 1053 peerCerts.clone() : 1054 peerCerts), 1055 keyExchangeString); 1056 } 1057 } catch (CertificateException e) { 1058 // This will throw an exception, so include the original error. 1059 fatalSE(Alerts.alert_certificate_unknown, e); 1060 } 1061 session.setPeerCertificates(peerCerts); 1062 } 1063 }