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 fatalSE(Alerts.alert_unsupported_extension, 423 "Server sent an unsupported extension: " + type); 424 } 425 } 426 427 // Create a new session, we need to do the full handshake 428 session = new SSLSessionImpl(protocolVersion, cipherSuite, 429 mesg.sessionId, getHostSE(), getPortSE()); 430 if (debug != null && Debug.isOn("handshake")) { 431 System.out.println("** " + cipherSuite); 432 } 433 } 434 435 /* 436 * Server's own key was either a signing-only key, or was too 437 * large for export rules ... this message holds an ephemeral 438 * RSA key to use for key exchange. 439 */ 440 private void serverKeyExchange(RSA_ServerKeyExchange mesg) 441 throws IOException, GeneralSecurityException { 442 if (debug != null && Debug.isOn("handshake")) { 443 mesg.print(System.out); 444 } 445 if (!mesg.verify(serverKey, clnt_random, svr_random)) { 446 fatalSE(Alerts.alert_handshake_failure, 447 "server key exchange invalid"); 448 // NOTREACHED 449 } 450 ephemeralServerKey = mesg.getPublicKey(); 451 } 452 453 454 /* 455 * Diffie-Hellman key exchange. We save the server public key and 456 * our own D-H algorithm object so we can defer key calculations 457 * until after we've sent the client key exchange message (which 458 * gives client and server some useful parallelism). 459 */ 460 private void serverKeyExchange(DH_ServerKeyExchange mesg) 461 throws IOException { 462 if (debug != null && Debug.isOn("handshake")) { 463 mesg.print(System.out); 464 } 465 dh = new DHCrypt(mesg.getModulus(), mesg.getBase(), sslContext.getSecureRandom()); 466 serverDH = mesg.getServerPublicKey(); 467 } 468 469 private void serverKeyExchange(ECDH_ServerKeyExchange mesg) throws IOException { 470 if (debug != null && Debug.isOn("handshake")) { 471 mesg.print(System.out); 472 } 473 ECPublicKey key = mesg.getPublicKey(); 474 ecdh = new ECDHCrypt(key.getParams(), sslContext.getSecureRandom()); 475 ephemeralServerKey = key; 476 } 477 478 /* 479 * The server's "Hello Done" message is the client's sign that 480 * it's time to do all the hard work. 481 */ 482 private void serverHelloDone(ServerHelloDone mesg) throws IOException { 483 if (debug != null && Debug.isOn("handshake")) { 484 mesg.print(System.out); 485 } 486 /* 487 * Always make sure the input has been digested before we 488 * start emitting data, to ensure the hashes are correctly 489 * computed for the Finished and CertificateVerify messages 490 * which we send (here). 491 */ 492 input.digestNow(); 493 494 /* 495 * FIRST ... if requested, send an appropriate Certificate chain 496 * to authenticate the client, and remember the associated private 497 * key to sign the CertificateVerify message. 498 */ 499 PrivateKey signingKey = null; 500 501 if (certRequest != null) { 502 X509ExtendedKeyManager km = sslContext.getX509KeyManager(); 503 504 ArrayList<String> keytypesTmp = new ArrayList<String>(4); 505 506 for (int i = 0; i < certRequest.types.length; i++) { 507 String typeName; 508 509 switch (certRequest.types[i]) { 510 case CertificateRequest.cct_rsa_sign: 511 typeName = "RSA"; 512 break; 513 514 case CertificateRequest.cct_dss_sign: 515 typeName = "DSA"; 516 break; 517 518 case CertificateRequest.cct_ecdsa_sign: 519 // ignore if we do not have EC crypto available 520 typeName = JsseJce.isEcAvailable() ? "EC" : null; 521 break; 522 523 // Fixed DH/ECDH client authentication not supported 524 case CertificateRequest.cct_rsa_fixed_dh: 525 case CertificateRequest.cct_dss_fixed_dh: 526 case CertificateRequest.cct_rsa_fixed_ecdh: 527 case CertificateRequest.cct_ecdsa_fixed_ecdh: 528 // Any other values (currently not used in TLS) 529 case CertificateRequest.cct_rsa_ephemeral_dh: 530 case CertificateRequest.cct_dss_ephemeral_dh: 531 default: 532 typeName = null; 533 break; 534 } 535 536 if ((typeName != null) && (!keytypesTmp.contains(typeName))) { 537 keytypesTmp.add(typeName); 538 } 539 } 540 541 String alias = null; 542 int keytypesTmpSize = keytypesTmp.size(); 543 if (keytypesTmpSize != 0) { 544 String keytypes[] = 545 keytypesTmp.toArray(new String[keytypesTmpSize]); 546 547 if (conn != null) { 548 alias = km.chooseClientAlias(keytypes, 549 certRequest.getAuthorities(), conn); 550 } else { 551 alias = km.chooseEngineClientAlias(keytypes, 552 certRequest.getAuthorities(), engine); 553 } 554 } 555 556 CertificateMsg m1 = null; 557 if (alias != null) { 558 X509Certificate[] certs = km.getCertificateChain(alias); 559 if ((certs != null) && (certs.length != 0)) { 560 PublicKey publicKey = certs[0].getPublicKey(); 561 // for EC, make sure we use a supported named curve 562 if (publicKey instanceof ECPublicKey) { 563 ECParameterSpec params = ((ECPublicKey)publicKey).getParams(); 564 int index = SupportedEllipticCurvesExtension.getCurveIndex(params); 565 if (!SupportedEllipticCurvesExtension.isSupported(index)) { 566 publicKey = null; 567 } 568 } 569 if (publicKey != null) { 570 m1 = new CertificateMsg(certs); 571 signingKey = km.getPrivateKey(alias); 572 session.setLocalPrivateKey(signingKey); 573 session.setLocalCertificates(certs); 574 } 575 } 576 } 577 if (m1 == null) { 578 // 579 // No appropriate cert was found ... report this to the 580 // server. For SSLv3, send the no_certificate alert; 581 // TLS uses an empty cert chain instead. 582 // 583 if (protocolVersion.v >= ProtocolVersion.TLS10.v) { 584 m1 = new CertificateMsg(new X509Certificate [0]); 585 } else { 586 warningSE(Alerts.alert_no_certificate); 587 } 588 } 589 590 // 591 // At last ... send any client certificate chain. 592 // 593 if (m1 != null) { 594 if (debug != null && Debug.isOn("handshake")) { 595 m1.print(System.out); 596 } 597 m1.write(output); 598 } 599 } 600 601 /* 602 * SECOND ... send the client key exchange message. The 603 * procedure used is a function of the cipher suite selected; 604 * one is always needed. 605 */ 606 HandshakeMessage m2; 607 608 switch (keyExchange) { 609 610 case K_RSA: 611 case K_RSA_EXPORT: 612 if (serverKey == null) { 613 throw new SSLProtocolException 614 ("Server did not send certificate message"); 615 } 616 617 if (!(serverKey instanceof RSAPublicKey)) { 618 throw new SSLProtocolException 619 ("Server certificate does not include an RSA key"); 620 } 621 622 /* 623 * For RSA key exchange, we randomly generate a new 624 * pre-master secret and encrypt it with the server's 625 * public key. Then we save that pre-master secret 626 * so that we can calculate the keying data later; 627 * it's a performance speedup not to do that until 628 * the client's waiting for the server response, but 629 * more of a speedup for the D-H case. 630 * 631 * If the RSA_EXPORT scheme is active, when the public 632 * key in the server certificate is less than or equal 633 * to 512 bits in length, use the cert's public key, 634 * otherwise, the ephemeral one. 635 */ 636 PublicKey key; 637 if (keyExchange == K_RSA) { 638 key = serverKey; 639 } else { // K_RSA_EXPORT 640 if (JsseJce.getRSAKeyLength(serverKey) <= 512) { 641 // extraneous ephemeralServerKey check done 642 // above in processMessage() 643 key = serverKey; 644 } else { 645 if (ephemeralServerKey == null) { 646 throw new SSLProtocolException("Server did not send" + 647 " a RSA_EXPORT Server Key Exchange message"); 648 } 649 key = ephemeralServerKey; 650 } 651 } 652 653 m2 = new RSAClientKeyExchange(protocolVersion, maxProtocolVersion, 654 sslContext.getSecureRandom(), key); 655 break; 656 case K_DH_RSA: 657 case K_DH_DSS: 658 /* 659 * For DH Key exchange, we only need to make sure the server 660 * knows our public key, so we calculate the same pre-master 661 * secret. 662 * 663 * For certs that had DH keys in them, we send an empty 664 * handshake message (no key) ... we flag this case by 665 * passing a null "dhPublic" value. 666 * 667 * Otherwise we send ephemeral DH keys, unsigned. 668 */ 669 // if (useDH_RSA || useDH_DSS) 670 m2 = new DHClientKeyExchange(); 671 break; 672 case K_DHE_RSA: 673 case K_DHE_DSS: 674 case K_DH_ANON: 675 if (dh == null) { 676 throw new SSLProtocolException 677 ("Server did not send a DH Server Key Exchange message"); 678 } 679 m2 = new DHClientKeyExchange(dh.getPublicKey()); 680 break; 681 case K_ECDHE_RSA: 682 case K_ECDHE_ECDSA: 683 case K_ECDH_ANON: 684 if (ecdh == null) { 685 throw new SSLProtocolException 686 ("Server did not send a ECDH Server Key Exchange message"); 687 } 688 m2 = new ECDHClientKeyExchange(ecdh.getPublicKey()); 689 break; 690 case K_ECDH_RSA: 691 case K_ECDH_ECDSA: 692 if (serverKey == null) { 693 throw new SSLProtocolException 694 ("Server did not send certificate message"); 695 } 696 if (serverKey instanceof ECPublicKey == false) { 697 throw new SSLProtocolException 698 ("Server certificate does not include an EC key"); 699 } 700 ECParameterSpec params = ((ECPublicKey)serverKey).getParams(); 701 ecdh = new ECDHCrypt(params, sslContext.getSecureRandom()); 702 m2 = new ECDHClientKeyExchange(ecdh.getPublicKey()); 703 break; 704 case K_KRB5: 705 case K_KRB5_EXPORT: 706 String hostname = getHostSE(); 707 if (hostname == null) { 708 throw new IOException("Hostname is required" + 709 " to use Kerberos cipher suites"); 710 } 711 KerberosClientKeyExchange kerberosMsg = new KerberosClientKeyExchange 712 (hostname, isLoopbackSE(), getAccSE(), protocolVersion, 713 sslContext.getSecureRandom()); 714 // Record the principals involved in exchange 715 session.setPeerPrincipal(kerberosMsg.getPeerPrincipal()); 716 session.setLocalPrincipal(kerberosMsg.getLocalPrincipal()); 717 m2 = kerberosMsg; 718 break; 719 default: 720 // somethings very wrong 721 throw new RuntimeException 722 ("Unsupported key exchange: " + keyExchange); 723 } 724 if (debug != null && Debug.isOn("handshake")) { 725 m2.print(System.out); 726 } 727 m2.write(output); 728 729 730 /* 731 * THIRD, send a "change_cipher_spec" record followed by the 732 * "Finished" message. We flush the messages we've queued up, to 733 * get concurrency between client and server. The concurrency is 734 * useful as we calculate the master secret, which is needed both 735 * to compute the "Finished" message, and to compute the keys used 736 * to protect all records following the change_cipher_spec. 737 */ 738 739 output.doHashes(); 740 output.flush(); 741 742 /* 743 * We deferred calculating the master secret and this connection's 744 * keying data; we do it now. Deferring this calculation is good 745 * from a performance point of view, since it lets us do it during 746 * some time that network delays and the server's own calculations 747 * would otherwise cause to be "dead" in the critical path. 748 */ 749 SecretKey preMasterSecret; 750 switch (keyExchange) { 751 case K_RSA: 752 case K_RSA_EXPORT: 753 preMasterSecret = ((RSAClientKeyExchange)m2).preMaster; 754 break; 755 case K_KRB5: 756 case K_KRB5_EXPORT: 757 byte[] secretBytes = 758 ((KerberosClientKeyExchange)m2).getPreMasterSecret().getUnencrypted(); 759 preMasterSecret = new SecretKeySpec(secretBytes, "TlsPremasterSecret"); 760 break; 761 case K_DHE_RSA: 762 case K_DHE_DSS: 763 case K_DH_ANON: 764 preMasterSecret = dh.getAgreedSecret(serverDH); 765 break; 766 case K_ECDHE_RSA: 767 case K_ECDHE_ECDSA: 768 case K_ECDH_ANON: 769 preMasterSecret = ecdh.getAgreedSecret(ephemeralServerKey); 770 break; 771 case K_ECDH_RSA: 772 case K_ECDH_ECDSA: 773 preMasterSecret = ecdh.getAgreedSecret(serverKey); 774 break; 775 default: 776 throw new IOException("Internal error: unknown key exchange " + keyExchange); 777 } 778 779 calculateKeys(preMasterSecret, null); 780 781 /* 782 * FOURTH, if we sent a Certificate, we need to send a signed 783 * CertificateVerify (unless the key in the client's certificate 784 * was a Diffie-Hellman key).). 785 * 786 * This uses a hash of the previous handshake messages ... either 787 * a nonfinal one (if the particular implementation supports it) 788 * or else using the third element in the arrays of hashes being 789 * computed. 790 */ 791 if (signingKey != null) { 792 CertificateVerify m3; 793 try { 794 m3 = new CertificateVerify(protocolVersion, handshakeHash, 795 signingKey, session.getMasterSecret(), 796 sslContext.getSecureRandom()); 797 } catch (GeneralSecurityException e) { 798 fatalSE(Alerts.alert_handshake_failure, 799 "Error signing certificate verify", e); 800 // NOTREACHED, make compiler happy 801 m3 = null; 802 } 803 if (debug != null && Debug.isOn("handshake")) { 804 m3.print(System.out); 805 } 806 m3.write(output); 807 output.doHashes(); 808 } 809 810 /* 811 * OK, that's that! 812 */ 813 sendChangeCipherAndFinish(false); 814 } 815 816 817 /* 818 * "Finished" is the last handshake message sent. If we got this 819 * far, the MAC has been validated post-decryption. We validate 820 * the two hashes here as an additional sanity check, protecting 821 * the handshake against various active attacks. 822 */ 823 private void serverFinished(Finished mesg) throws IOException { 824 if (debug != null && Debug.isOn("handshake")) { 825 mesg.print(System.out); 826 } 827 828 boolean verified = mesg.verify(protocolVersion, handshakeHash, 829 Finished.SERVER, session.getMasterSecret()); 830 831 if (!verified) { 832 fatalSE(Alerts.alert_illegal_parameter, 833 "server 'finished' message doesn't verify"); 834 // NOTREACHED 835 } 836 837 /* 838 * OK, it verified. If we're doing the fast handshake, add that 839 * "Finished" message to the hash of handshake messages, then send 840 * our own change_cipher_spec and Finished message for the server 841 * to verify in turn. These are the last handshake messages. 842 * 843 * In any case, update the session cache. We're done handshaking, 844 * so there are no threats any more associated with partially 845 * completed handshakes. 846 */ 847 if (resumingSession) { 848 input.digestNow(); 849 sendChangeCipherAndFinish(true); 850 } 851 session.setLastAccessedTime(System.currentTimeMillis()); 852 853 if (!resumingSession) { 854 if (session.isRejoinable()) { 855 ((SSLSessionContextImpl) sslContext 856 .engineGetClientSessionContext()) 857 .put(session); 858 if (debug != null && Debug.isOn("session")) { 859 System.out.println("%% Cached client session: " + session); 860 } 861 } else if (debug != null && Debug.isOn("session")) { 862 System.out.println( 863 "%% Didn't cache non-resumable client session: " 864 + session); 865 } 866 } 867 } 868 869 870 /* 871 * Send my change-cipher-spec and Finished message ... done as the 872 * last handshake act in either the short or long sequences. In 873 * the short one, we've already seen the server's Finished; in the 874 * long one, we wait for it now. 875 */ 876 private void sendChangeCipherAndFinish(boolean finishedTag) 877 throws IOException { 878 Finished mesg = new Finished(protocolVersion, handshakeHash, 879 Finished.CLIENT, session.getMasterSecret()); 880 881 /* 882 * Send the change_cipher_spec message, then the Finished message 883 * which we just calculated (and protected using the keys we just 884 * calculated). Server responds with its Finished message, except 885 * in the "fast handshake" (resume session) case. 886 */ 887 sendChangeCipherSpec(mesg, finishedTag); 888 889 /* 890 * Update state machine so server MUST send 'finished' next. 891 * (In "long" handshake case; in short case, we're responding 892 * to its message.) 893 */ 894 state = HandshakeMessage.ht_finished - 1; 895 } 896 897 898 /* 899 * Returns a ClientHello message to kickstart renegotiations 900 */ 901 HandshakeMessage getKickstartMessage() throws SSLException { 902 ClientHello mesg = new ClientHello(sslContext.getSecureRandom(), 903 protocolVersion); 904 maxProtocolVersion = protocolVersion; 905 906 clnt_random = mesg.clnt_random; 907 908 // 909 // Try to resume an existing session. This might be mandatory, 910 // given certain API options. 911 // 912 session = ((SSLSessionContextImpl)sslContext 913 .engineGetClientSessionContext()) 914 .get(getHostSE(), getPortSE()); 915 if (debug != null && Debug.isOn("session")) { 916 if (session != null) { 917 System.out.println("%% Client cached " 918 + session 919 + (session.isRejoinable() ? "" : " (not rejoinable)")); 920 } else { 921 System.out.println("%% No cached client session"); 922 } 923 } 924 if ((session != null) && (session.isRejoinable() == false)) { 925 session = null; 926 } 927 928 if (session != null) { 929 CipherSuite sessionSuite = session.getSuite(); 930 ProtocolVersion sessionVersion = session.getProtocolVersion(); 931 if (isEnabled(sessionSuite) == false) { 932 if (debug != null && Debug.isOn("session")) { 933 System.out.println("%% can't resume, cipher disabled"); 934 } 935 session = null; 936 } 937 938 if ((session != null) && 939 (enabledProtocols.contains(sessionVersion) == false)) { 940 if (debug != null && Debug.isOn("session")) { 941 System.out.println("%% can't resume, protocol disabled"); 942 } 943 session = null; 944 } 945 946 if (session != null) { 947 if (debug != null) { 948 if (Debug.isOn("handshake") || Debug.isOn("session")) { 949 System.out.println("%% Try resuming " + session 950 + " from port " + getLocalPortSE()); 951 } 952 } 953 mesg.sessionId = session.getSessionId(); 954 955 mesg.protocolVersion = sessionVersion; 956 maxProtocolVersion = sessionVersion; 957 958 // Update SSL version number in underlying SSL socket and 959 // handshake output stream, so that the output records (at the 960 // record layer) have the correct version 961 setVersion(sessionVersion); 962 } 963 964 // 965 // don't say much beyond the obvious if we _must_ resume. 966 // 967 if (!enableNewSession) { 968 if (session == null) { 969 throw new SSLException( 970 "Can't reuse existing SSL client session"); 971 } 972 mesg.setCipherSuites(new CipherSuiteList(sessionSuite)); 973 return mesg; 974 } 975 } 976 if (session == null) { 977 if (enableNewSession) { 978 mesg.sessionId = SSLSessionImpl.nullSession.getSessionId(); 979 } else { 980 throw new SSLException("No existing session to resume."); 981 } 982 } 983 984 // 985 // All we have left to do is fill out the cipher suites. 986 // (If this changes, change the 'return' above!) 987 // 988 mesg.setCipherSuites(enabledCipherSuites); 989 990 return mesg; 991 } 992 993 /* 994 * Fault detected during handshake. 995 */ 996 void handshakeAlert(byte description) throws SSLProtocolException { 997 String message = Alerts.alertDescription(description); 998 999 if (debug != null && Debug.isOn("handshake")) { 1000 System.out.println("SSL - handshake alert: " + message); 1001 } 1002 throw new SSLProtocolException("handshake alert: " + message); 1003 } 1004 1005 /* 1006 * Unless we are using an anonymous ciphersuite, the server always 1007 * sends a certificate message (for the CipherSuites we currently 1008 * support). The trust manager verifies the chain for us. 1009 */ 1010 private void serverCertificate(CertificateMsg mesg) throws IOException { 1011 if (debug != null && Debug.isOn("handshake")) { 1012 mesg.print(System.out); 1013 } 1014 X509Certificate[] peerCerts = mesg.getCertificateChain(); 1015 if (peerCerts.length == 0) { 1016 fatalSE(Alerts.alert_bad_certificate, 1017 "empty certificate chain"); 1018 } 1019 // ask the trust manager to verify the chain 1020 X509TrustManager tm = sslContext.getX509TrustManager(); 1021 try { 1022 // find out the key exchange algorithm used 1023 // use "RSA" for non-ephemeral "RSA_EXPORT" 1024 String keyExchangeString; 1025 if (keyExchange == K_RSA_EXPORT && !serverKeyExchangeReceived) { 1026 keyExchangeString = K_RSA.name; 1027 } else { 1028 keyExchangeString = keyExchange.name; 1029 } 1030 1031 String identificator = getHostnameVerificationSE(); 1032 if (tm instanceof X509ExtendedTrustManager) { 1033 ((X509ExtendedTrustManager)tm).checkServerTrusted( 1034 (peerCerts != null ? 1035 peerCerts.clone() : 1036 null), 1037 keyExchangeString, 1038 getHostSE(), 1039 identificator); 1040 } else { 1041 if (identificator != null) { 1042 throw new RuntimeException( 1043 "trust manager does not support peer identification"); 1044 } 1045 1046 tm.checkServerTrusted( 1047 (peerCerts != null ? 1048 peerCerts.clone() : 1049 peerCerts), 1050 keyExchangeString); 1051 } 1052 } catch (CertificateException e) { 1053 // This will throw an exception, so include the original error. 1054 fatalSE(Alerts.alert_certificate_unknown, e); 1055 } 1056 session.setPeerCertificates(peerCerts); 1057 } 1058 }