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 }