History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/ssl/ClientHandshaker.java (1 of 18352 files). Show all

Unified · Split

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