1 /*
   2  * Copyright (c) 1996, 2017, 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 import java.security.cert.CertificateParsingException;
  40 import java.security.cert.CertPathValidatorException;
  41 import java.security.cert.CertPathValidatorException.Reason;
  42 import java.security.cert.CertPathValidatorException.BasicReason;
  43 import javax.security.auth.x500.X500Principal;
  44 
  45 import javax.crypto.SecretKey;
  46 
  47 import javax.net.ssl.*;
  48 
  49 import sun.security.ssl.HandshakeMessage.*;
  50 import static sun.security.ssl.CipherSuite.KeyExchange.*;
  51 
  52 /**
  53  * ClientHandshaker does the protocol handshaking from the point
  54  * of view of a client.  It is driven asychronously by handshake messages
  55  * as delivered by the parent Handshaker class, and also uses
  56  * common functionality (e.g. key generation) that is provided there.
  57  *
  58  * @author David Brownell
  59  */
  60 final class ClientHandshaker extends Handshaker {
  61 
  62     // constants for subject alt names of type DNS and IP
  63     private static final int ALTNAME_DNS = 2;
  64     private static final int ALTNAME_IP  = 7;
  65 
  66     // the server's public key from its certificate.
  67     private PublicKey serverKey;
  68 
  69     // the server's ephemeral public key from the server key exchange message
  70     // for ECDHE/ECDH_anon and RSA_EXPORT.
  71     private PublicKey ephemeralServerKey;
  72 
  73     // server's ephemeral public value for DHE/DH_anon key exchanges
  74     private BigInteger          serverDH;
  75 
  76     private DHCrypt             dh;
  77 
  78     private ECDHCrypt ecdh;
  79 
  80     private CertificateRequest  certRequest;
  81 
  82     private boolean serverKeyExchangeReceived;
  83 
  84     private boolean staplingActive = false;
  85     private X509Certificate[] deferredCerts;
  86 
  87     /*
  88      * The RSA PreMasterSecret needs to know the version of
  89      * ClientHello that was used on this handshake.  This represents
  90      * the "max version" this client is supporting.  In the
  91      * case of an initial handshake, it's the max version enabled,
  92      * but in the case of a resumption attempt, it's the version
  93      * of the session we're trying to resume.
  94      */
  95     private ProtocolVersion maxProtocolVersion;
  96 
  97     // To switch off the SNI extension.
  98     private static final boolean enableSNIExtension =
  99             Debug.getBooleanProperty("jsse.enableSNIExtension", true);
 100 
 101     /*
 102      * Allow unsafe server certificate change?
 103      *
 104      * Server certificate change during SSL/TLS renegotiation may be considered
 105      * unsafe, as described in the Triple Handshake attacks:
 106      *
 107      *     https://secure-resumption.com/tlsauth.pdf
 108      *
 109      * Endpoint identification (See
 110      * SSLParameters.getEndpointIdentificationAlgorithm()) is a pretty nice
 111      * guarantee that the server certificate change in renegotiation is legal.
 112      * However, endpoing identification is only enabled for HTTPS and LDAP
 113      * over SSL/TLS by default.  It is not enough to protect SSL/TLS
 114      * connections other than HTTPS and LDAP.
 115      *
 116      * The renegotiation indication extension (See RFC 5764) is a pretty
 117      * strong guarantee that the endpoints on both client and server sides
 118      * are identical on the same connection.  However, the Triple Handshake
 119      * attacks can bypass this guarantee if there is a session-resumption
 120      * handshake between the initial full handshake and the renegotiation
 121      * full handshake.
 122      *
 123      * Server certificate change may be unsafe and should be restricted if
 124      * endpoint identification is not enabled and the previous handshake is
 125      * a session-resumption abbreviated initial handshake, unless the
 126      * identities represented by both certificates can be regraded as the
 127      * same (See isIdentityEquivalent()).
 128      *
 129      * Considering the compatibility impact and the actual requirements to
 130      * support server certificate change in practice, the system property,
 131      * jdk.tls.allowUnsafeServerCertChange, is used to define whether unsafe
 132      * server certificate change in renegotiation is allowed or not.  The
 133      * default value of the system property is "false".  To mitigate the
 134      * compactibility impact, applications may want to set the system
 135      * property to "true" at their own risk.
 136      *
 137      * If the value of the system property is "false", server certificate
 138      * change in renegotiation after a session-resumption abbreviated initial
 139      * handshake is restricted (See isIdentityEquivalent()).
 140      *
 141      * If the system property is set to "true" explicitly, the restriction on
 142      * server certificate change in renegotiation is disabled.
 143      */
 144     private static final boolean allowUnsafeServerCertChange =
 145         Debug.getBooleanProperty("jdk.tls.allowUnsafeServerCertChange", false);
 146 
 147     // To switch off the max_fragment_length extension.
 148     private static final boolean enableMFLExtension =
 149             Debug.getBooleanProperty("jsse.enableMFLExtension", false);
 150 
 151     // To switch off the supported_groups extension for DHE cipher suite.
 152     private static final boolean enableFFDHE =
 153             Debug.getBooleanProperty("jsse.enableFFDHE", true);
 154 
 155     // Whether an ALPN extension was sent in the ClientHello
 156     private boolean alpnActive = false;
 157 
 158     private List<SNIServerName> requestedServerNames =
 159             Collections.<SNIServerName>emptyList();
 160 
 161     // maximum fragment length
 162     private int requestedMFLength = -1;     // -1: no fragment length limit
 163 
 164     private boolean serverNamesAccepted = false;
 165 
 166     private ClientHello initialClientHelloMsg = null;   // DTLS only
 167 
 168     /*
 169      * the reserved server certificate chain in previous handshaking
 170      *
 171      * The server certificate chain is only reserved if the previous
 172      * handshake is a session-resumption abbreviated initial handshake.
 173      */
 174     private X509Certificate[] reservedServerCerts = null;
 175 
 176     /*
 177      * Constructors
 178      */
 179     ClientHandshaker(SSLSocketImpl socket, SSLContextImpl context,
 180             ProtocolList enabledProtocols,
 181             ProtocolVersion activeProtocolVersion,
 182             boolean isInitialHandshake, boolean secureRenegotiation,
 183             byte[] clientVerifyData, byte[] serverVerifyData) {
 184 
 185         super(socket, context, enabledProtocols, true, true,
 186             activeProtocolVersion, isInitialHandshake, secureRenegotiation,
 187             clientVerifyData, serverVerifyData);
 188     }
 189 
 190     ClientHandshaker(SSLEngineImpl engine, SSLContextImpl context,
 191             ProtocolList enabledProtocols,
 192             ProtocolVersion activeProtocolVersion,
 193             boolean isInitialHandshake, boolean secureRenegotiation,
 194             byte[] clientVerifyData, byte[] serverVerifyData,
 195             boolean isDTLS) {
 196 
 197         super(engine, context, enabledProtocols, true, true,
 198             activeProtocolVersion, isInitialHandshake, secureRenegotiation,
 199             clientVerifyData, serverVerifyData, isDTLS);
 200     }
 201 
 202     /*
 203      * This routine handles all the client side handshake messages, one at
 204      * a time.  Given the message type (and in some cases the pending cipher
 205      * spec) it parses the type-specific message.  Then it calls a function
 206      * that handles that specific message.
 207      *
 208      * It updates the state machine (need to verify it) as each message
 209      * is processed, and writes responses as needed using the connection
 210      * in the constructor.
 211      */
 212     @Override
 213     void processMessage(byte type, int messageLen) throws IOException {
 214         // check the handshake state
 215         List<Byte> ignoredOptStates = handshakeState.check(type);
 216 
 217         // If the state machine has skipped over certificate status
 218         // and stapling was enabled, we need to check the chain immediately
 219         // because it was deferred, waiting for CertificateStatus.
 220         if (staplingActive && ignoredOptStates.contains(
 221                 HandshakeMessage.ht_certificate_status)) {
 222             checkServerCerts(deferredCerts);
 223             serverKey = session.getPeerCertificates()[0].getPublicKey();
 224         }
 225 
 226         switch (type) {
 227         case HandshakeMessage.ht_hello_request:
 228             HelloRequest helloRequest = new HelloRequest(input);
 229             handshakeState.update(helloRequest, resumingSession);
 230             this.serverHelloRequest(helloRequest);
 231             break;
 232 
 233         case HandshakeMessage.ht_hello_verify_request:
 234             if (!isDTLS) {
 235                 throw new SSLProtocolException(
 236                     "hello_verify_request is not a SSL/TLS handshake message");
 237             }
 238 
 239             HelloVerifyRequest helloVerifyRequest =
 240                         new HelloVerifyRequest(input, messageLen);
 241             handshakeState.update(helloVerifyRequest, resumingSession);
 242             this.helloVerifyRequest(helloVerifyRequest);
 243             break;
 244 
 245         case HandshakeMessage.ht_server_hello:
 246             ServerHello serverHello = new ServerHello(input, messageLen);
 247             this.serverHello(serverHello);
 248 
 249             // This handshake state update needs the resumingSession value
 250             // set by serverHello().
 251             handshakeState.update(serverHello, resumingSession);
 252             break;
 253 
 254         case HandshakeMessage.ht_certificate:
 255             if (keyExchange == K_DH_ANON || keyExchange == K_ECDH_ANON
 256                     || ClientKeyExchangeService.find(keyExchange.name) != null) {
 257                 // No external key exchange provider needs a cert now.
 258                 fatalSE(Alerts.alert_unexpected_message,
 259                     "unexpected server cert chain");
 260                 // NOTREACHED
 261             }
 262             CertificateMsg certificateMsg = new CertificateMsg(input);
 263             handshakeState.update(certificateMsg, resumingSession);
 264             this.serverCertificate(certificateMsg);
 265             if (!staplingActive) {
 266                 // If we are not doing stapling, we can set serverKey right
 267                 // away.  Otherwise, we will wait until verification of the
 268                 // chain has completed after CertificateStatus;
 269                 serverKey = session.getPeerCertificates()[0].getPublicKey();
 270             }
 271             break;
 272 
 273         case HandshakeMessage.ht_certificate_status:
 274             CertificateStatus certStatusMsg = new CertificateStatus(input);
 275             handshakeState.update(certStatusMsg, resumingSession);
 276             this.certificateStatus(certStatusMsg);
 277             serverKey = session.getPeerCertificates()[0].getPublicKey();
 278             break;
 279 
 280         case HandshakeMessage.ht_server_key_exchange:
 281             serverKeyExchangeReceived = true;
 282             switch (keyExchange) {
 283             case K_RSA_EXPORT:
 284                 /**
 285                  * The server key exchange message is sent by the server only
 286                  * when the server certificate message does not contain the
 287                  * proper amount of data to allow the client to exchange a
 288                  * premaster secret, such as when RSA_EXPORT is used and the
 289                  * public key in the server certificate is longer than 512 bits.
 290                  */
 291                 if (serverKey == null) {
 292                     throw new SSLProtocolException
 293                         ("Server did not send certificate message");
 294                 }
 295 
 296                 if (!(serverKey instanceof RSAPublicKey)) {
 297                     throw new SSLProtocolException("Protocol violation:" +
 298                         " the certificate type must be appropriate for the" +
 299                         " selected cipher suite's key exchange algorithm");
 300                 }
 301 
 302                 if (JsseJce.getRSAKeyLength(serverKey) <= 512) {
 303                     throw new SSLProtocolException("Protocol violation:" +
 304                         " server sent a server key exchange message for" +
 305                         " key exchange " + keyExchange +
 306                         " when the public key in the server certificate" +
 307                         " is less than or equal to 512 bits in length");
 308                 }
 309 
 310                 try {
 311                     RSA_ServerKeyExchange rsaSrvKeyExchange =
 312                                     new RSA_ServerKeyExchange(input);
 313                     handshakeState.update(rsaSrvKeyExchange, resumingSession);
 314                     this.serverKeyExchange(rsaSrvKeyExchange);
 315                 } catch (GeneralSecurityException e) {
 316                     throw new SSLException("Server key", e);
 317                 }
 318                 break;
 319             case K_DH_ANON:
 320                 try {
 321                     DH_ServerKeyExchange dhSrvKeyExchange =
 322                             new DH_ServerKeyExchange(input, protocolVersion);
 323                     handshakeState.update(dhSrvKeyExchange, resumingSession);
 324                     this.serverKeyExchange(dhSrvKeyExchange);
 325                 } catch (GeneralSecurityException e) {
 326                     throw new SSLException("Server key", e);
 327                 }
 328                 break;
 329             case K_DHE_DSS:
 330             case K_DHE_RSA:
 331                 try {
 332                     DH_ServerKeyExchange dhSrvKeyExchange =
 333                         new DH_ServerKeyExchange(
 334                             input, serverKey,
 335                             clnt_random.random_bytes, svr_random.random_bytes,
 336                             messageLen,
 337                             getLocalSupportedSignAlgs(), protocolVersion);
 338                     handshakeState.update(dhSrvKeyExchange, resumingSession);
 339                     this.serverKeyExchange(dhSrvKeyExchange);
 340                 } catch (GeneralSecurityException e) {
 341                     throw new SSLException("Server key", e);
 342                 }
 343                 break;
 344             case K_ECDHE_ECDSA:
 345             case K_ECDHE_RSA:
 346             case K_ECDH_ANON:
 347                 try {
 348                     ECDH_ServerKeyExchange ecdhSrvKeyExchange =
 349                         new ECDH_ServerKeyExchange
 350                             (input, serverKey, clnt_random.random_bytes,
 351                             svr_random.random_bytes,
 352                             getLocalSupportedSignAlgs(), protocolVersion);
 353                     handshakeState.update(ecdhSrvKeyExchange, resumingSession);
 354                     this.serverKeyExchange(ecdhSrvKeyExchange);
 355                 } catch (GeneralSecurityException e) {
 356                     throw new SSLException("Server key", e);
 357                 }
 358                 break;
 359             case K_RSA:
 360             case K_DH_RSA:
 361             case K_DH_DSS:
 362             case K_ECDH_ECDSA:
 363             case K_ECDH_RSA:
 364                 throw new SSLProtocolException(
 365                     "Protocol violation: server sent a server key exchange"
 366                     + " message for key exchange " + keyExchange);
 367             default:
 368                 throw new SSLProtocolException(
 369                     "unsupported or unexpected key exchange algorithm = "
 370                     + keyExchange);
 371             }
 372             break;
 373 
 374         case HandshakeMessage.ht_certificate_request:
 375             // save for later, it's handled by serverHelloDone
 376             if ((keyExchange == K_DH_ANON) || (keyExchange == K_ECDH_ANON)) {
 377                 throw new SSLHandshakeException(
 378                     "Client authentication requested for "+
 379                     "anonymous cipher suite.");
 380             } else if (ClientKeyExchangeService.find(keyExchange.name) != null) {
 381                 // No external key exchange provider needs a cert now.
 382                 throw new SSLHandshakeException(
 383                     "Client certificate requested for "+
 384                     "external cipher suite: " + keyExchange);
 385             }
 386             certRequest = new CertificateRequest(input, protocolVersion);
 387             if (debug != null && Debug.isOn("handshake")) {
 388                 certRequest.print(System.out);
 389             }
 390             handshakeState.update(certRequest, resumingSession);
 391 
 392             if (protocolVersion.useTLS12PlusSpec()) {
 393                 Collection<SignatureAndHashAlgorithm> peerSignAlgs =
 394                                         certRequest.getSignAlgorithms();
 395                 if (peerSignAlgs == null || peerSignAlgs.isEmpty()) {
 396                     throw new SSLHandshakeException(
 397                         "No peer supported signature algorithms");
 398                 }
 399 
 400                 Collection<SignatureAndHashAlgorithm> supportedPeerSignAlgs =
 401                     SignatureAndHashAlgorithm.getSupportedAlgorithms(
 402                             algorithmConstraints, peerSignAlgs);
 403                 if (supportedPeerSignAlgs.isEmpty()) {
 404                     throw new SSLHandshakeException(
 405                         "No supported signature and hash algorithm in common");
 406                 }
 407 
 408                 setPeerSupportedSignAlgs(supportedPeerSignAlgs);
 409                 session.setPeerSupportedSignatureAlgorithms(
 410                                                 supportedPeerSignAlgs);
 411             }
 412 
 413             break;
 414 
 415         case HandshakeMessage.ht_server_hello_done:
 416             ServerHelloDone serverHelloDone = new ServerHelloDone(input);
 417             handshakeState.update(serverHelloDone, resumingSession);
 418             this.serverHelloDone(serverHelloDone);
 419 
 420             break;
 421 
 422         case HandshakeMessage.ht_finished:
 423             Finished serverFinished =
 424                     new Finished(protocolVersion, input, cipherSuite);
 425             handshakeState.update(serverFinished, resumingSession);
 426             this.serverFinished(serverFinished);
 427 
 428             break;
 429 
 430         default:
 431             throw new SSLProtocolException(
 432                 "Illegal client handshake msg, " + type);
 433         }
 434     }
 435 
 436     /*
 437      * Used by the server to kickstart negotiations -- this requests a
 438      * "client hello" to renegotiate current cipher specs (e.g. maybe lots
 439      * of data has been encrypted with the same keys, or the server needs
 440      * the client to present a certificate).
 441      */
 442     private void serverHelloRequest(HelloRequest mesg) throws IOException {
 443         if (debug != null && Debug.isOn("handshake")) {
 444             mesg.print(System.out);
 445         }
 446 
 447         //
 448         // Could be (e.g. at connection setup) that we already
 449         // sent the "client hello" but the server's not seen it.
 450         //
 451         if (!clientHelloDelivered) {
 452             if (!secureRenegotiation && !allowUnsafeRenegotiation) {
 453                 // renegotiation is not allowed.
 454                 if (activeProtocolVersion.useTLS10PlusSpec()) {
 455                     // response with a no_renegotiation warning,
 456                     warningSE(Alerts.alert_no_renegotiation);
 457 
 458                     // invalidate the handshake so that the caller can
 459                     // dispose this object.
 460                     invalidated = true;
 461 
 462                     // If there is still unread block in the handshake
 463                     // input stream, it would be truncated with the disposal
 464                     // and the next handshake message will become incomplete.
 465                     //
 466                     // However, according to SSL/TLS specifications, no more
 467                     // handshake message should immediately follow ClientHello
 468                     // or HelloRequest. So just let it be.
 469                 } else {
 470                     // For SSLv3, send the handshake_failure fatal error.
 471                     // Note that SSLv3 does not define a no_renegotiation
 472                     // alert like TLSv1. However we cannot ignore the message
 473                     // simply, otherwise the other side was waiting for a
 474                     // response that would never come.
 475                     fatalSE(Alerts.alert_handshake_failure,
 476                         "Renegotiation is not allowed");
 477                 }
 478             } else {
 479                 if (!secureRenegotiation) {
 480                     if (debug != null && Debug.isOn("handshake")) {
 481                         System.out.println(
 482                             "Warning: continue with insecure renegotiation");
 483                     }
 484                 }
 485                 kickstart();
 486             }
 487         }
 488     }
 489 
 490     private void helloVerifyRequest(
 491             HelloVerifyRequest mesg) throws IOException {
 492 
 493         if (debug != null && Debug.isOn("handshake")) {
 494             mesg.print(System.out);
 495         }
 496 
 497         //
 498         // Note that HelloVerifyRequest.server_version is used solely to
 499         // indicate packet formatting, and not as part of version negotiation.
 500         // Need not to check version values match for HelloVerifyRequest
 501         // message.
 502         //
 503         initialClientHelloMsg.cookie = mesg.cookie.clone();
 504 
 505         if (debug != null && Debug.isOn("handshake")) {
 506             initialClientHelloMsg.print(System.out);
 507         }
 508 
 509         // deliver the ClientHello message with cookie
 510         initialClientHelloMsg.write(output);
 511         handshakeState.update(initialClientHelloMsg, resumingSession);
 512     }
 513 
 514     /*
 515      * Server chooses session parameters given options created by the
 516      * client -- basically, cipher options, session id, and someday a
 517      * set of compression options.
 518      *
 519      * There are two branches of the state machine, decided by the
 520      * details of this message.  One is the "fast" handshake, where we
 521      * can resume the pre-existing session we asked resume.  The other
 522      * is a more expensive "full" handshake, with key exchange and
 523      * probably authentication getting done.
 524      */
 525     private void serverHello(ServerHello mesg) throws IOException {
 526         // Dispose the reserved ClientHello message (if exists).
 527         initialClientHelloMsg = null;
 528 
 529         serverKeyExchangeReceived = false;
 530         if (debug != null && Debug.isOn("handshake")) {
 531             mesg.print(System.out);
 532         }
 533 
 534         // check if the server selected protocol version is OK for us
 535         ProtocolVersion mesgVersion = mesg.protocolVersion;
 536         if (!isNegotiable(mesgVersion)) {
 537             throw new SSLHandshakeException(
 538                 "Server chose " + mesgVersion +
 539                 ", but that protocol version is not enabled or not supported " +
 540                 "by the client.");
 541         }
 542 
 543         handshakeHash.protocolDetermined(mesgVersion);
 544 
 545         // Set protocolVersion and propagate to SSLSocket and the
 546         // Handshake streams
 547         setVersion(mesgVersion);
 548 
 549         // check the "renegotiation_info" extension
 550         RenegotiationInfoExtension serverHelloRI = (RenegotiationInfoExtension)
 551                     mesg.extensions.get(ExtensionType.EXT_RENEGOTIATION_INFO);
 552         if (serverHelloRI != null) {
 553             if (isInitialHandshake) {
 554                 // verify the length of the "renegotiated_connection" field
 555                 if (!serverHelloRI.isEmpty()) {
 556                     // abort the handshake with a fatal handshake_failure alert
 557                     fatalSE(Alerts.alert_handshake_failure,
 558                         "The renegotiation_info field is not empty");
 559                 }
 560 
 561                 secureRenegotiation = true;
 562             } else {
 563                 // For a legacy renegotiation, the client MUST verify that
 564                 // it does not contain the "renegotiation_info" extension.
 565                 if (!secureRenegotiation) {
 566                     fatalSE(Alerts.alert_handshake_failure,
 567                         "Unexpected renegotiation indication extension");
 568                 }
 569 
 570                 // verify the client_verify_data and server_verify_data values
 571                 byte[] verifyData =
 572                     new byte[clientVerifyData.length + serverVerifyData.length];
 573                 System.arraycopy(clientVerifyData, 0, verifyData,
 574                         0, clientVerifyData.length);
 575                 System.arraycopy(serverVerifyData, 0, verifyData,
 576                         clientVerifyData.length, serverVerifyData.length);
 577                 if (!MessageDigest.isEqual(verifyData,
 578                                 serverHelloRI.getRenegotiatedConnection())) {
 579                     fatalSE(Alerts.alert_handshake_failure,
 580                         "Incorrect verify data in ServerHello " +
 581                         "renegotiation_info message");
 582                 }
 583             }
 584         } else {
 585             // no renegotiation indication extension
 586             if (isInitialHandshake) {
 587                 if (!allowLegacyHelloMessages) {
 588                     // abort the handshake with a fatal handshake_failure alert
 589                     fatalSE(Alerts.alert_handshake_failure,
 590                         "Failed to negotiate the use of secure renegotiation");
 591                 }
 592 
 593                 secureRenegotiation = false;
 594                 if (debug != null && Debug.isOn("handshake")) {
 595                     System.out.println("Warning: No renegotiation " +
 596                                     "indication extension in ServerHello");
 597                 }
 598             } else {
 599                 // For a secure renegotiation, the client must abort the
 600                 // handshake if no "renegotiation_info" extension is present.
 601                 if (secureRenegotiation) {
 602                     fatalSE(Alerts.alert_handshake_failure,
 603                         "No renegotiation indication extension");
 604                 }
 605 
 606                 // we have already allowed unsafe renegotation before request
 607                 // the renegotiation.
 608             }
 609         }
 610 
 611         //
 612         // Save server nonce, we always use it to compute connection
 613         // keys and it's also used to create the master secret if we're
 614         // creating a new session (i.e. in the full handshake).
 615         //
 616         svr_random = mesg.svr_random;
 617 
 618         if (isNegotiable(mesg.cipherSuite) == false) {
 619             fatalSE(Alerts.alert_illegal_parameter,
 620                 "Server selected improper ciphersuite " + mesg.cipherSuite);
 621         }
 622 
 623         setCipherSuite(mesg.cipherSuite);
 624         if (protocolVersion.useTLS12PlusSpec()) {
 625             handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg());
 626         }
 627 
 628         if (mesg.compression_method != 0) {
 629             fatalSE(Alerts.alert_illegal_parameter,
 630                 "compression type not supported, "
 631                 + mesg.compression_method);
 632             // NOTREACHED
 633         }
 634 
 635         // so far so good, let's look at the session
 636         if (session != null) {
 637             // we tried to resume, let's see what the server decided
 638             if (session.getSessionId().equals(mesg.sessionId)) {
 639                 // server resumed the session, let's make sure everything
 640                 // checks out
 641 
 642                 // Verify that the session ciphers are unchanged.
 643                 CipherSuite sessionSuite = session.getSuite();
 644                 if (cipherSuite != sessionSuite) {
 645                     throw new SSLProtocolException
 646                         ("Server returned wrong cipher suite for session");
 647                 }
 648 
 649                 // verify protocol version match
 650                 ProtocolVersion sessionVersion = session.getProtocolVersion();
 651                 if (protocolVersion != sessionVersion) {
 652                     throw new SSLProtocolException
 653                         ("Server resumed session with wrong protocol version");
 654                 }
 655 
 656                 // validate subject identity
 657                 ClientKeyExchangeService p =
 658                         ClientKeyExchangeService.find(sessionSuite.keyExchange.name);
 659                 if (p != null) {
 660                     Principal localPrincipal = session.getLocalPrincipal();
 661 
 662                     if (p.isRelated(true, getAccSE(), localPrincipal)) {
 663                         if (debug != null && Debug.isOn("session"))
 664                             System.out.println("Subject identity is same");
 665                     } else {
 666                         throw new SSLProtocolException("Server resumed" +
 667                                 " session with wrong subject identity or no subject");
 668                     }
 669                 }
 670 
 671                 // looks fine; resume it.
 672                 resumingSession = true;
 673                 calculateConnectionKeys(session.getMasterSecret());
 674                 if (debug != null && Debug.isOn("session")) {
 675                     System.out.println("%% Server resumed " + session);
 676                 }
 677             } else {
 678                 // we wanted to resume, but the server refused
 679                 //
 680                 // Invalidate the session for initial handshake in case
 681                 // of reusing next time.
 682                 if (isInitialHandshake) {
 683                     session.invalidate();
 684                 }
 685                 session = null;
 686                 if (!enableNewSession) {
 687                     throw new SSLException("New session creation is disabled");
 688                 }
 689             }
 690         }
 691 
 692         // check the "max_fragment_length" extension
 693         MaxFragmentLengthExtension maxFragLenExt = (MaxFragmentLengthExtension)
 694                 mesg.extensions.get(ExtensionType.EXT_MAX_FRAGMENT_LENGTH);
 695         if (maxFragLenExt != null) {
 696             if ((requestedMFLength == -1) ||
 697                     maxFragLenExt.getMaxFragLen() != requestedMFLength) {
 698                 // If the client did not request this extension, or the
 699                 // response value is different from the length it requested,
 700                 // abort the handshake with a fatal illegal_parameter alert.
 701                 fatalSE(Alerts.alert_illegal_parameter,
 702                         "Failed to negotiate the max_fragment_length");
 703             }
 704         } else if (!resumingSession) {
 705             // no "max_fragment_length" extension
 706             requestedMFLength = -1;
 707         }   // Otherwise, using the value negotiated during the original
 708             // session initiation
 709 
 710         // check the ALPN extension
 711         ALPNExtension serverHelloALPN =
 712             (ALPNExtension) mesg.extensions.get(ExtensionType.EXT_ALPN);
 713 
 714         if (serverHelloALPN != null) {
 715             // Check whether an ALPN extension was sent in ClientHello message
 716             if (!alpnActive) {
 717                 fatalSE(Alerts.alert_unsupported_extension,
 718                     "Server sent " + ExtensionType.EXT_ALPN +
 719                     " extension when not requested by client");
 720             }
 721 
 722             List<String> protocols = serverHelloALPN.getPeerAPs();
 723             // Only one application protocol name should be present
 724             String p;
 725             if ((protocols.size() == 1) &&
 726                     !((p = protocols.get(0)).isEmpty())) {
 727                 int i;
 728                 for (i = 0; i < localApl.length; i++) {
 729                     if (localApl[i].equals(p)) {
 730                         break;
 731                     }
 732                 }
 733                 if (i == localApl.length) {
 734                     fatalSE(Alerts.alert_handshake_failure,
 735                         "Server has selected an application protocol name " +
 736                         "which was not offered by the client: " + p);
 737                 }
 738                 applicationProtocol = p;
 739             } else {
 740                 fatalSE(Alerts.alert_handshake_failure,
 741                     "Incorrect data in ServerHello " + ExtensionType.EXT_ALPN +
 742                     " message");
 743             }
 744         } else {
 745             applicationProtocol = "";
 746         }
 747 
 748         if (resumingSession && session != null) {
 749             setHandshakeSessionSE(session);
 750             // Reserve the handshake state if this is a session-resumption
 751             // abbreviated initial handshake.
 752             if (isInitialHandshake) {
 753                 session.setAsSessionResumption(true);
 754             }
 755 
 756             return;
 757         }
 758 
 759         // check extensions
 760         for (HelloExtension ext : mesg.extensions.list()) {
 761             ExtensionType type = ext.type;
 762             if (type == ExtensionType.EXT_SERVER_NAME) {
 763                 serverNamesAccepted = true;
 764             } else if (type == ExtensionType.EXT_STATUS_REQUEST ||
 765                     type == ExtensionType.EXT_STATUS_REQUEST_V2) {
 766                 // Only enable the stapling feature if the client asserted
 767                 // these extensions.
 768                 if (sslContext.isStaplingEnabled(true)) {
 769                     staplingActive = true;
 770                 } else {
 771                     fatalSE(Alerts.alert_unexpected_message, "Server set " +
 772                             type + " extension when not requested by client");
 773                 }
 774             } else if ((type != ExtensionType.EXT_SUPPORTED_GROUPS)
 775                     && (type != ExtensionType.EXT_EC_POINT_FORMATS)
 776                     && (type != ExtensionType.EXT_SERVER_NAME)
 777                     && (type != ExtensionType.EXT_ALPN)
 778                     && (type != ExtensionType.EXT_RENEGOTIATION_INFO)
 779                     && (type != ExtensionType.EXT_STATUS_REQUEST)
 780                     && (type != ExtensionType.EXT_STATUS_REQUEST_V2)) {
 781                 // Note: Better to check client requested extensions rather
 782                 // than all supported extensions.
 783                 fatalSE(Alerts.alert_unsupported_extension,
 784                     "Server sent an unsupported extension: " + type);
 785             }
 786         }
 787 
 788         // Create a new session, we need to do the full handshake
 789         session = new SSLSessionImpl(protocolVersion, cipherSuite,
 790                             getLocalSupportedSignAlgs(),
 791                             mesg.sessionId, getHostSE(), getPortSE());
 792         session.setRequestedServerNames(requestedServerNames);
 793         session.setNegotiatedMaxFragSize(requestedMFLength);
 794         session.setMaximumPacketSize(maximumPacketSize);
 795         setHandshakeSessionSE(session);
 796         if (debug != null && Debug.isOn("handshake")) {
 797             System.out.println("** " + cipherSuite);
 798         }
 799     }
 800 
 801     /*
 802      * Server's own key was either a signing-only key, or was too
 803      * large for export rules ... this message holds an ephemeral
 804      * RSA key to use for key exchange.
 805      */
 806     private void serverKeyExchange(RSA_ServerKeyExchange mesg)
 807             throws IOException, GeneralSecurityException {
 808         if (debug != null && Debug.isOn("handshake")) {
 809             mesg.print(System.out);
 810         }
 811         if (!mesg.verify(serverKey, clnt_random, svr_random)) {
 812             fatalSE(Alerts.alert_handshake_failure,
 813                 "server key exchange invalid");
 814             // NOTREACHED
 815         }
 816         ephemeralServerKey = mesg.getPublicKey();
 817 
 818         // check constraints of RSA PublicKey
 819         if (!algorithmConstraints.permits(
 820             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), ephemeralServerKey)) {
 821 
 822             throw new SSLHandshakeException("RSA ServerKeyExchange " +
 823                     "does not comply to algorithm constraints");
 824         }
 825     }
 826 
 827     /*
 828      * Diffie-Hellman key exchange.  We save the server public key and
 829      * our own D-H algorithm object so we can defer key calculations
 830      * until after we've sent the client key exchange message (which
 831      * gives client and server some useful parallelism).
 832      *
 833      * Note per section 3 of RFC 7919, if the server is not compatible with
 834      * FFDHE specification, the client MAY decide to continue the connection
 835      * if the selected DHE group is acceptable under local policy, or it MAY
 836      * decide to terminate the connection with a fatal insufficient_security
 837      * (71) alert.  The algorithm constraints mechanism is JDK local policy
 838      * used for additional DHE parameters checking.  So this implementation
 839      * does not check the server compatibility and just pass to the local
 840      * algorithm constraints checking.  The client will continue the
 841      * connection if the server selected DHE group is acceptable by the
 842      * specified algorithm constraints.
 843      */
 844     private void serverKeyExchange(DH_ServerKeyExchange mesg)
 845             throws IOException {
 846         if (debug != null && Debug.isOn("handshake")) {
 847             mesg.print(System.out);
 848         }
 849         dh = new DHCrypt(mesg.getModulus(), mesg.getBase(),
 850                                             sslContext.getSecureRandom());
 851         serverDH = mesg.getServerPublicKey();
 852 
 853         // check algorithm constraints
 854         dh.checkConstraints(algorithmConstraints, serverDH);
 855     }
 856 
 857     private void serverKeyExchange(ECDH_ServerKeyExchange mesg)
 858             throws IOException {
 859         if (debug != null && Debug.isOn("handshake")) {
 860             mesg.print(System.out);
 861         }
 862         ECPublicKey key = mesg.getPublicKey();
 863         ecdh = new ECDHCrypt(key.getParams(), sslContext.getSecureRandom());
 864         ephemeralServerKey = key;
 865 
 866         // check constraints of EC PublicKey
 867         if (!algorithmConstraints.permits(
 868             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), ephemeralServerKey)) {
 869 
 870             throw new SSLHandshakeException("ECDH ServerKeyExchange " +
 871                     "does not comply to algorithm constraints");
 872         }
 873     }
 874 
 875     /*
 876      * The server's "Hello Done" message is the client's sign that
 877      * it's time to do all the hard work.
 878      */
 879     private void serverHelloDone(ServerHelloDone mesg) throws IOException {
 880         if (debug != null && Debug.isOn("handshake")) {
 881             mesg.print(System.out);
 882         }
 883 
 884         /*
 885          * FIRST ... if requested, send an appropriate Certificate chain
 886          * to authenticate the client, and remember the associated private
 887          * key to sign the CertificateVerify message.
 888          */
 889         PrivateKey signingKey = null;
 890 
 891         if (certRequest != null) {
 892             X509ExtendedKeyManager km = sslContext.getX509KeyManager();
 893 
 894             ArrayList<String> keytypesTmp = new ArrayList<>(4);
 895 
 896             for (int i = 0; i < certRequest.types.length; i++) {
 897                 String typeName;
 898 
 899                 switch (certRequest.types[i]) {
 900                     case CertificateRequest.cct_rsa_sign:
 901                         typeName = "RSA";
 902                         break;
 903 
 904                     case CertificateRequest.cct_dss_sign:
 905                         typeName = "DSA";
 906                             break;
 907 
 908                     case CertificateRequest.cct_ecdsa_sign:
 909                         // ignore if we do not have EC crypto available
 910                         typeName = JsseJce.isEcAvailable() ? "EC" : null;
 911                         break;
 912 
 913                     // Fixed DH/ECDH client authentication not supported
 914                     //
 915                     // case CertificateRequest.cct_rsa_fixed_dh:
 916                     // case CertificateRequest.cct_dss_fixed_dh:
 917                     // case CertificateRequest.cct_rsa_fixed_ecdh:
 918                     // case CertificateRequest.cct_ecdsa_fixed_ecdh:
 919                     //
 920                     // Any other values (currently not used in TLS)
 921                     //
 922                     // case CertificateRequest.cct_rsa_ephemeral_dh:
 923                     // case CertificateRequest.cct_dss_ephemeral_dh:
 924                     default:
 925                         typeName = null;
 926                         break;
 927                 }
 928 
 929                 if ((typeName != null) && (!keytypesTmp.contains(typeName))) {
 930                     keytypesTmp.add(typeName);
 931                 }
 932             }
 933 
 934             String alias = null;
 935             int keytypesTmpSize = keytypesTmp.size();
 936             if (keytypesTmpSize != 0) {
 937                 String[] keytypes =
 938                         keytypesTmp.toArray(new String[keytypesTmpSize]);
 939 
 940                 if (conn != null) {
 941                     alias = km.chooseClientAlias(keytypes,
 942                         certRequest.getAuthorities(), conn);
 943                 } else {
 944                     alias = km.chooseEngineClientAlias(keytypes,
 945                         certRequest.getAuthorities(), engine);
 946                 }
 947             }
 948 
 949             CertificateMsg m1 = null;
 950             if (alias != null) {
 951                 X509Certificate[] certs = km.getCertificateChain(alias);
 952                 if ((certs != null) && (certs.length != 0)) {
 953                     PublicKey publicKey = certs[0].getPublicKey();
 954                     if (publicKey != null) {
 955                         m1 = new CertificateMsg(certs);
 956                         signingKey = km.getPrivateKey(alias);
 957                         session.setLocalPrivateKey(signingKey);
 958                         session.setLocalCertificates(certs);
 959                     }
 960                 }
 961             }
 962             if (m1 == null) {
 963                 //
 964                 // No appropriate cert was found ... report this to the
 965                 // server.  For SSLv3, send the no_certificate alert;
 966                 // TLS uses an empty cert chain instead.
 967                 //
 968                 if (protocolVersion.useTLS10PlusSpec()) {
 969                     m1 = new CertificateMsg(new X509Certificate [0]);
 970                 } else {
 971                     warningSE(Alerts.alert_no_certificate);
 972                 }
 973                 if (debug != null && Debug.isOn("handshake")) {
 974                     System.out.println(
 975                         "Warning: no suitable certificate found - " +
 976                         "continuing without client authentication");
 977                 }
 978             }
 979 
 980             //
 981             // At last ... send any client certificate chain.
 982             //
 983             if (m1 != null) {
 984                 if (debug != null && Debug.isOn("handshake")) {
 985                     m1.print(System.out);
 986                 }
 987                 m1.write(output);
 988                 handshakeState.update(m1, resumingSession);
 989             }
 990         }
 991 
 992         /*
 993          * SECOND ... send the client key exchange message.  The
 994          * procedure used is a function of the cipher suite selected;
 995          * one is always needed.
 996          */
 997         HandshakeMessage m2;
 998 
 999         switch (keyExchange) {
1000 
1001         case K_RSA:
1002         case K_RSA_EXPORT:
1003             if (serverKey == null) {
1004                 throw new SSLProtocolException
1005                         ("Server did not send certificate message");
1006             }
1007 
1008             if (!(serverKey instanceof RSAPublicKey)) {
1009                 throw new SSLProtocolException
1010                         ("Server certificate does not include an RSA key");
1011             }
1012 
1013             /*
1014              * For RSA key exchange, we randomly generate a new
1015              * pre-master secret and encrypt it with the server's
1016              * public key.  Then we save that pre-master secret
1017              * so that we can calculate the keying data later;
1018              * it's a performance speedup not to do that until
1019              * the client's waiting for the server response, but
1020              * more of a speedup for the D-H case.
1021              *
1022              * If the RSA_EXPORT scheme is active, when the public
1023              * key in the server certificate is less than or equal
1024              * to 512 bits in length, use the cert's public key,
1025              * otherwise, the ephemeral one.
1026              */
1027             PublicKey key;
1028             if (keyExchange == K_RSA) {
1029                 key = serverKey;
1030             } else {    // K_RSA_EXPORT
1031                 if (JsseJce.getRSAKeyLength(serverKey) <= 512) {
1032                     // extraneous ephemeralServerKey check done
1033                     // above in processMessage()
1034                     key = serverKey;
1035                 } else {
1036                     if (ephemeralServerKey == null) {
1037                         throw new SSLProtocolException("Server did not send" +
1038                             " a RSA_EXPORT Server Key Exchange message");
1039                     }
1040                     key = ephemeralServerKey;
1041                 }
1042             }
1043 
1044             m2 = new RSAClientKeyExchange(protocolVersion, maxProtocolVersion,
1045                                 sslContext.getSecureRandom(), key);
1046             break;
1047         case K_DH_RSA:
1048         case K_DH_DSS:
1049             /*
1050              * For DH Key exchange, we only need to make sure the server
1051              * knows our public key, so we calculate the same pre-master
1052              * secret.
1053              *
1054              * For certs that had DH keys in them, we send an empty
1055              * handshake message (no key) ... we flag this case by
1056              * passing a null "dhPublic" value.
1057              *
1058              * Otherwise we send ephemeral DH keys, unsigned.
1059              */
1060             // if (useDH_RSA || useDH_DSS)
1061             m2 = new DHClientKeyExchange();
1062             break;
1063         case K_DHE_RSA:
1064         case K_DHE_DSS:
1065         case K_DH_ANON:
1066             if (dh == null) {
1067                 throw new SSLProtocolException
1068                     ("Server did not send a DH Server Key Exchange message");
1069             }
1070             m2 = new DHClientKeyExchange(dh.getPublicKey());
1071             break;
1072         case K_ECDHE_RSA:
1073         case K_ECDHE_ECDSA:
1074         case K_ECDH_ANON:
1075             if (ecdh == null) {
1076                 throw new SSLProtocolException
1077                     ("Server did not send a ECDH Server Key Exchange message");
1078             }
1079             m2 = new ECDHClientKeyExchange(ecdh.getPublicKey());
1080             break;
1081         case K_ECDH_RSA:
1082         case K_ECDH_ECDSA:
1083             if (serverKey == null) {
1084                 throw new SSLProtocolException
1085                         ("Server did not send certificate message");
1086             }
1087             if (serverKey instanceof ECPublicKey == false) {
1088                 throw new SSLProtocolException
1089                         ("Server certificate does not include an EC key");
1090             }
1091             ECParameterSpec params = ((ECPublicKey)serverKey).getParams();
1092             ecdh = new ECDHCrypt(params, sslContext.getSecureRandom());
1093             m2 = new ECDHClientKeyExchange(ecdh.getPublicKey());
1094             break;
1095         default:
1096             ClientKeyExchangeService p =
1097                     ClientKeyExchangeService.find(keyExchange.name);
1098             if (p == null) {
1099                 // somethings very wrong
1100                 throw new RuntimeException
1101                         ("Unsupported key exchange: " + keyExchange);
1102             }
1103             String sniHostname = null;
1104             for (SNIServerName serverName : requestedServerNames) {
1105                 if (serverName instanceof SNIHostName) {
1106                     sniHostname = ((SNIHostName) serverName).getAsciiName();
1107                     break;
1108                 }
1109             }
1110 
1111             ClientKeyExchange exMsg = null;
1112             if (sniHostname != null) {
1113                 // use first requested SNI hostname
1114                 try {
1115                     exMsg = p.createClientExchange(
1116                             sniHostname, getAccSE(), protocolVersion,
1117                             sslContext.getSecureRandom());
1118                 } catch(IOException e) {
1119                     if (serverNamesAccepted) {
1120                         // server accepted requested SNI hostname,
1121                         // so it must be used
1122                         throw e;
1123                     }
1124                     // fallback to using hostname
1125                     if (debug != null && Debug.isOn("handshake")) {
1126                         System.out.println(
1127                             "Warning, cannot use Server Name Indication: "
1128                                 + e.getMessage());
1129                     }
1130                 }
1131             }
1132 
1133             if (exMsg == null) {
1134                 String hostname = getHostSE();
1135                 if (hostname == null) {
1136                     throw new IOException("Hostname is required" +
1137                         " to use " + keyExchange + " key exchange");
1138                 }
1139                 exMsg = p.createClientExchange(
1140                         hostname, getAccSE(), protocolVersion,
1141                         sslContext.getSecureRandom());
1142             }
1143 
1144             // Record the principals involved in exchange
1145             session.setPeerPrincipal(exMsg.getPeerPrincipal());
1146             session.setLocalPrincipal(exMsg.getLocalPrincipal());
1147             m2 = exMsg;
1148             break;
1149         }
1150         if (debug != null && Debug.isOn("handshake")) {
1151             m2.print(System.out);
1152         }
1153         m2.write(output);
1154         handshakeState.update(m2, resumingSession);
1155 
1156         /*
1157          * THIRD, send a "change_cipher_spec" record followed by the
1158          * "Finished" message.  We flush the messages we've queued up, to
1159          * get concurrency between client and server.  The concurrency is
1160          * useful as we calculate the master secret, which is needed both
1161          * to compute the "Finished" message, and to compute the keys used
1162          * to protect all records following the change_cipher_spec.
1163          */
1164         output.flush();
1165 
1166         /*
1167          * We deferred calculating the master secret and this connection's
1168          * keying data; we do it now.  Deferring this calculation is good
1169          * from a performance point of view, since it lets us do it during
1170          * some time that network delays and the server's own calculations
1171          * would otherwise cause to be "dead" in the critical path.
1172          */
1173         SecretKey preMasterSecret;
1174         switch (keyExchange) {
1175         case K_RSA:
1176         case K_RSA_EXPORT:
1177             preMasterSecret = ((RSAClientKeyExchange)m2).preMaster;
1178             break;
1179         case K_DHE_RSA:
1180         case K_DHE_DSS:
1181         case K_DH_ANON:
1182             preMasterSecret = dh.getAgreedSecret(serverDH, true);
1183             break;
1184         case K_ECDHE_RSA:
1185         case K_ECDHE_ECDSA:
1186         case K_ECDH_ANON:
1187             preMasterSecret = ecdh.getAgreedSecret(ephemeralServerKey);
1188             break;
1189         case K_ECDH_RSA:
1190         case K_ECDH_ECDSA:
1191             preMasterSecret = ecdh.getAgreedSecret(serverKey);
1192             break;
1193         default:
1194             if (ClientKeyExchangeService.find(keyExchange.name) != null) {
1195                 preMasterSecret =
1196                         ((ClientKeyExchange) m2).clientKeyExchange();
1197             } else {
1198                 throw new IOException("Internal error: unknown key exchange "
1199                         + keyExchange);
1200             }
1201         }
1202 
1203         calculateKeys(preMasterSecret, null);
1204 
1205         /*
1206          * FOURTH, if we sent a Certificate, we need to send a signed
1207          * CertificateVerify (unless the key in the client's certificate
1208          * was a Diffie-Hellman key).
1209          *
1210          * This uses a hash of the previous handshake messages ... either
1211          * a nonfinal one (if the particular implementation supports it)
1212          * or else using the third element in the arrays of hashes being
1213          * computed.
1214          */
1215         if (signingKey != null) {
1216             CertificateVerify m3;
1217             try {
1218                 SignatureAndHashAlgorithm preferableSignatureAlgorithm = null;
1219                 if (protocolVersion.useTLS12PlusSpec()) {
1220                     preferableSignatureAlgorithm =
1221                         SignatureAndHashAlgorithm.getPreferableAlgorithm(
1222                             getPeerSupportedSignAlgs(),
1223                             signingKey.getAlgorithm(), signingKey);
1224 
1225                     if (preferableSignatureAlgorithm == null) {
1226                         throw new SSLHandshakeException(
1227                             "No supported signature algorithm");
1228                     }
1229 
1230                     String hashAlg =
1231                         SignatureAndHashAlgorithm.getHashAlgorithmName(
1232                                 preferableSignatureAlgorithm);
1233                     if (hashAlg == null || hashAlg.length() == 0) {
1234                         throw new SSLHandshakeException(
1235                                 "No supported hash algorithm");
1236                     }
1237                 }
1238 
1239                 m3 = new CertificateVerify(protocolVersion, handshakeHash,
1240                     signingKey, session.getMasterSecret(),
1241                     sslContext.getSecureRandom(),
1242                     preferableSignatureAlgorithm);
1243             } catch (GeneralSecurityException e) {
1244                 fatalSE(Alerts.alert_handshake_failure,
1245                     "Error signing certificate verify", e);
1246                 // NOTREACHED, make compiler happy
1247                 m3 = null;
1248             }
1249             if (debug != null && Debug.isOn("handshake")) {
1250                 m3.print(System.out);
1251             }
1252             m3.write(output);
1253             handshakeState.update(m3, resumingSession);
1254             output.flush();
1255         }
1256 
1257         /*
1258          * OK, that's that!
1259          */
1260         sendChangeCipherAndFinish(false);
1261 
1262         // expecting the final ChangeCipherSpec and Finished messages
1263         expectingFinishFlightSE();
1264     }
1265 
1266 
1267     /*
1268      * "Finished" is the last handshake message sent.  If we got this
1269      * far, the MAC has been validated post-decryption.  We validate
1270      * the two hashes here as an additional sanity check, protecting
1271      * the handshake against various active attacks.
1272      */
1273     private void serverFinished(Finished mesg) throws IOException {
1274         if (debug != null && Debug.isOn("handshake")) {
1275             mesg.print(System.out);
1276         }
1277 
1278         boolean verified = mesg.verify(handshakeHash, Finished.SERVER,
1279             session.getMasterSecret());
1280 
1281         if (!verified) {
1282             fatalSE(Alerts.alert_illegal_parameter,
1283                        "server 'finished' message doesn't verify");
1284             // NOTREACHED
1285         }
1286 
1287         /*
1288          * save server verify data for secure renegotiation and TLS channel binding
1289          */
1290         serverVerifyData = mesg.getVerifyData();
1291 
1292         /*
1293          * Reset the handshake state if this is not an initial handshake.
1294          */
1295         if (!isInitialHandshake) {
1296             session.setAsSessionResumption(false);
1297         }
1298 
1299         /*
1300          * OK, it verified.  If we're doing the fast handshake, add that
1301          * "Finished" message to the hash of handshake messages, then send
1302          * our own change_cipher_spec and Finished message for the server
1303          * to verify in turn.  These are the last handshake messages.
1304          *
1305          * In any case, update the session cache.  We're done handshaking,
1306          * so there are no threats any more associated with partially
1307          * completed handshakes.
1308          */
1309         if (resumingSession) {
1310             sendChangeCipherAndFinish(true);
1311         } else {
1312             handshakeFinished = true;
1313         }
1314         session.setLastAccessedTime(System.currentTimeMillis());
1315 
1316         if (!resumingSession) {
1317             if (session.isRejoinable()) {
1318                 ((SSLSessionContextImpl) sslContext
1319                         .engineGetClientSessionContext())
1320                         .put(session);
1321                 if (debug != null && Debug.isOn("session")) {
1322                     System.out.println("%% Cached client session: " + session);
1323                 }
1324             } else if (debug != null && Debug.isOn("session")) {
1325                 System.out.println(
1326                     "%% Didn't cache non-resumable client session: "
1327                     + session);
1328             }
1329         }
1330     }
1331 
1332 
1333     /*
1334      * Send my change-cipher-spec and Finished message ... done as the
1335      * last handshake act in either the short or long sequences.  In
1336      * the short one, we've already seen the server's Finished; in the
1337      * long one, we wait for it now.
1338      */
1339     private void sendChangeCipherAndFinish(boolean finishedTag)
1340             throws IOException {
1341 
1342         // Reload if this message has been reserved.
1343         handshakeHash.reload();
1344 
1345         Finished mesg = new Finished(protocolVersion, handshakeHash,
1346             Finished.CLIENT, session.getMasterSecret(), cipherSuite);
1347 
1348         /*
1349          * Send the change_cipher_spec message, then the Finished message
1350          * which we just calculated (and protected using the keys we just
1351          * calculated).  Server responds with its Finished message, except
1352          * in the "fast handshake" (resume session) case.
1353          */
1354         sendChangeCipherSpec(mesg, finishedTag);
1355 
1356         /*
1357          * save client verify data for secure renegotiation and TLS channel binding
1358          */
1359         clientVerifyData = mesg.getVerifyData();
1360     }
1361 
1362 
1363     /*
1364      * Returns a ClientHello message to kickstart renegotiations
1365      */
1366     @Override
1367     HandshakeMessage getKickstartMessage() throws SSLException {
1368         // session ID of the ClientHello message
1369         SessionId sessionId = SSLSessionImpl.nullSession.getSessionId();
1370 
1371         // a list of cipher suites sent by the client
1372         CipherSuiteList cipherSuites = getActiveCipherSuites();
1373 
1374         // set the max protocol version this client is supporting.
1375         maxProtocolVersion = protocolVersion;
1376 
1377         //
1378         // Try to resume an existing session.  This might be mandatory,
1379         // given certain API options.
1380         //
1381         session = ((SSLSessionContextImpl)sslContext
1382                         .engineGetClientSessionContext())
1383                         .get(getHostSE(), getPortSE());
1384         if (debug != null && Debug.isOn("session")) {
1385             if (session != null) {
1386                 System.out.println("%% Client cached "
1387                     + session
1388                     + (session.isRejoinable() ? "" : " (not rejoinable)"));
1389             } else {
1390                 System.out.println("%% No cached client session");
1391             }
1392         }
1393         if (session != null) {
1394             // If unsafe server certificate change is not allowed, reserve
1395             // current server certificates if the previous handshake is a
1396             // session-resumption abbreviated initial handshake.
1397             if (!allowUnsafeServerCertChange && session.isSessionResumption()) {
1398                 try {
1399                     // If existing, peer certificate chain cannot be null.
1400                     reservedServerCerts =
1401                         (X509Certificate[])session.getPeerCertificates();
1402                 } catch (SSLPeerUnverifiedException puve) {
1403                     // Maybe not certificate-based, ignore the exception.
1404                 }
1405             }
1406 
1407             if (!session.isRejoinable()) {
1408                 session = null;
1409             }
1410         }
1411 
1412         if (session != null) {
1413             CipherSuite sessionSuite = session.getSuite();
1414             ProtocolVersion sessionVersion = session.getProtocolVersion();
1415             if (isNegotiable(sessionSuite) == false) {
1416                 if (debug != null && Debug.isOn("session")) {
1417                     System.out.println("%% can't resume, unavailable cipher");
1418                 }
1419                 session = null;
1420             }
1421 
1422             if ((session != null) && !isNegotiable(sessionVersion)) {
1423                 if (debug != null && Debug.isOn("session")) {
1424                     System.out.println("%% can't resume, protocol disabled");
1425                 }
1426                 session = null;
1427             }
1428 
1429             if (session != null) {
1430                 if (debug != null) {
1431                     if (Debug.isOn("handshake") || Debug.isOn("session")) {
1432                         System.out.println("%% Try resuming " + session
1433                             + " from port " + getLocalPortSE());
1434                     }
1435                 }
1436 
1437                 sessionId = session.getSessionId();
1438                 maxProtocolVersion = sessionVersion;
1439 
1440                 // Update SSL version number in underlying SSL socket and
1441                 // handshake output stream, so that the output records (at the
1442                 // record layer) have the correct version
1443                 setVersion(sessionVersion);
1444             }
1445 
1446             /*
1447              * Force use of the previous session ciphersuite, and
1448              * add the SCSV if enabled.
1449              */
1450             if (!enableNewSession) {
1451                 if (session == null) {
1452                     throw new SSLHandshakeException(
1453                         "Can't reuse existing SSL client session");
1454                 }
1455 
1456                 Collection<CipherSuite> cipherList = new ArrayList<>(2);
1457                 cipherList.add(sessionSuite);
1458                 if (!secureRenegotiation &&
1459                         cipherSuites.contains(CipherSuite.C_SCSV)) {
1460                     cipherList.add(CipherSuite.C_SCSV);
1461                 }   // otherwise, renegotiation_info extension will be used
1462 
1463                 cipherSuites = new CipherSuiteList(cipherList);
1464             }
1465         }
1466 
1467         if (session == null && !enableNewSession) {
1468             throw new SSLHandshakeException("No existing session to resume");
1469         }
1470 
1471         // exclude SCSV for secure renegotiation
1472         if (secureRenegotiation && cipherSuites.contains(CipherSuite.C_SCSV)) {
1473             Collection<CipherSuite> cipherList =
1474                         new ArrayList<>(cipherSuites.size() - 1);
1475             for (CipherSuite suite : cipherSuites.collection()) {
1476                 if (suite != CipherSuite.C_SCSV) {
1477                     cipherList.add(suite);
1478                 }
1479             }
1480 
1481             cipherSuites = new CipherSuiteList(cipherList);
1482         }
1483 
1484         // make sure there is a negotiable cipher suite.
1485         boolean negotiable = false;
1486         for (CipherSuite suite : cipherSuites.collection()) {
1487             if (isNegotiable(suite)) {
1488                 negotiable = true;
1489                 break;
1490             }
1491         }
1492 
1493         if (!negotiable) {
1494             throw new SSLHandshakeException("No negotiable cipher suite");
1495         }
1496 
1497         // Not a TLS1.2+ handshake
1498         // For SSLv2Hello, HandshakeHash.reset() will be called, so we
1499         // cannot call HandshakeHash.protocolDetermined() here. As it does
1500         // not follow the spec that HandshakeHash.reset() can be only be
1501         // called before protocolDetermined.
1502         // if (maxProtocolVersion.v < ProtocolVersion.TLS12.v) {
1503         //     handshakeHash.protocolDetermined(maxProtocolVersion);
1504         // }
1505 
1506         // create the ClientHello message
1507         ClientHello clientHelloMessage = new ClientHello(
1508                 sslContext.getSecureRandom(), maxProtocolVersion,
1509                 sessionId, cipherSuites, isDTLS);
1510 
1511         // Add named groups extension for ECDHE and FFDHE if necessary.
1512         SupportedGroupsExtension sge =
1513                 SupportedGroupsExtension.createExtension(
1514                         algorithmConstraints,
1515                         cipherSuites, enableFFDHE);
1516         if (sge != null) {
1517             clientHelloMessage.extensions.add(sge);
1518             // Add elliptic point format extensions
1519             if (cipherSuites.contains(NamedGroupType.NAMED_GROUP_ECDHE)) {
1520                 clientHelloMessage.extensions.add(
1521                     EllipticPointFormatsExtension.DEFAULT);
1522             }
1523         }
1524 
1525         // add signature_algorithm extension
1526         if (maxProtocolVersion.useTLS12PlusSpec()) {
1527             // we will always send the signature_algorithm extension
1528             Collection<SignatureAndHashAlgorithm> localSignAlgs =
1529                                                 getLocalSupportedSignAlgs();
1530             if (localSignAlgs.isEmpty()) {
1531                 throw new SSLHandshakeException(
1532                             "No supported signature algorithm");
1533             }
1534 
1535             clientHelloMessage.addSignatureAlgorithmsExtension(localSignAlgs);
1536         }
1537 
1538         // add server_name extension
1539         if (enableSNIExtension) {
1540             if (session != null) {
1541                 requestedServerNames = session.getRequestedServerNames();
1542             } else {
1543                 requestedServerNames = serverNames;
1544             }
1545 
1546             if (!requestedServerNames.isEmpty()) {
1547                 clientHelloMessage.addSNIExtension(requestedServerNames);
1548             }
1549         }
1550 
1551         // add max_fragment_length extension
1552         if (enableMFLExtension) {
1553             if (session != null) {
1554                 // The same extension should be sent for resumption.
1555                 requestedMFLength = session.getNegotiatedMaxFragSize();
1556             } else if (maximumPacketSize != 0) {
1557                 // Maybe we can calculate the fragment size more accurate
1558                 // by condering the enabled cipher suites in the future.
1559                 requestedMFLength = maximumPacketSize;
1560                 if (isDTLS) {
1561                     requestedMFLength -= DTLSRecord.maxPlaintextPlusSize;
1562                 } else {
1563                     requestedMFLength -= SSLRecord.maxPlaintextPlusSize;
1564                 }
1565             } else {
1566                 // Need no max_fragment_length extension.
1567                 requestedMFLength = -1;
1568             }
1569 
1570             if ((requestedMFLength > 0) &&
1571                 MaxFragmentLengthExtension.needFragLenNego(requestedMFLength)) {
1572 
1573                 requestedMFLength =
1574                         MaxFragmentLengthExtension.getValidMaxFragLen(
1575                                                         requestedMFLength);
1576                 clientHelloMessage.addMFLExtension(requestedMFLength);
1577             } else {
1578                 requestedMFLength = -1;
1579             }
1580         }
1581 
1582         // Add status_request and status_request_v2 extensions
1583         if (sslContext.isStaplingEnabled(true)) {
1584             clientHelloMessage.addCertStatusReqListV2Extension();
1585             clientHelloMessage.addCertStatusRequestExtension();
1586         }
1587 
1588         // Add ALPN extension
1589         if (localApl != null && localApl.length > 0) {
1590             clientHelloMessage.addALPNExtension(localApl);
1591             alpnActive = true;
1592         }
1593 
1594         // reset the client random cookie
1595         clnt_random = clientHelloMessage.clnt_random;
1596 
1597         /*
1598          * need to set the renegotiation_info extension for:
1599          * 1: secure renegotiation
1600          * 2: initial handshake and no SCSV in the ClientHello
1601          * 3: insecure renegotiation and no SCSV in the ClientHello
1602          */
1603         if (secureRenegotiation ||
1604                 !cipherSuites.contains(CipherSuite.C_SCSV)) {
1605             clientHelloMessage.addRenegotiationInfoExtension(clientVerifyData);
1606         }
1607 
1608         if (isDTLS) {
1609             // Cookie exchange need to reserve the initial ClientHello message.
1610             initialClientHelloMsg = clientHelloMessage;
1611         }
1612 
1613         return clientHelloMessage;
1614     }
1615 
1616     /*
1617      * Fault detected during handshake.
1618      */
1619     @Override
1620     void handshakeAlert(byte description) throws SSLProtocolException {
1621         String message = Alerts.alertDescription(description);
1622 
1623         if (debug != null && Debug.isOn("handshake")) {
1624             System.out.println("SSL - handshake alert: " + message);
1625         }
1626         throw new SSLProtocolException("handshake alert:  " + message);
1627     }
1628 
1629     /*
1630      * Unless we are using an anonymous ciphersuite, the server always
1631      * sends a certificate message (for the CipherSuites we currently
1632      * support). The trust manager verifies the chain for us.
1633      */
1634     private void serverCertificate(CertificateMsg mesg) throws IOException {
1635         if (debug != null && Debug.isOn("handshake")) {
1636             mesg.print(System.out);
1637         }
1638         X509Certificate[] peerCerts = mesg.getCertificateChain();
1639         if (peerCerts.length == 0) {
1640             fatalSE(Alerts.alert_bad_certificate, "empty certificate chain");
1641         }
1642 
1643         // Allow server certificate change in client side during renegotiation
1644         // after a session-resumption abbreviated initial handshake?
1645         //
1646         // DO NOT need to check allowUnsafeServerCertChange here. We only
1647         // reserve server certificates when allowUnsafeServerCertChange is
1648         // flase.
1649         if (reservedServerCerts != null) {
1650             // It is not necessary to check the certificate update if endpoint
1651             // identification is enabled.
1652             String identityAlg = getEndpointIdentificationAlgorithmSE();
1653             if ((identityAlg == null || identityAlg.length() == 0) &&
1654                 !isIdentityEquivalent(peerCerts[0], reservedServerCerts[0])) {
1655 
1656                 fatalSE(Alerts.alert_bad_certificate,
1657                         "server certificate change is restricted " +
1658                         "during renegotiation");
1659             }
1660         }
1661 
1662         // ask the trust manager to verify the chain
1663         if (staplingActive) {
1664             // Defer the certificate check until after we've received the
1665             // CertificateStatus message.  If that message doesn't come in
1666             // immediately following this message we will execute the check
1667             // directly from processMessage before any other SSL/TLS processing.
1668             deferredCerts = peerCerts;
1669         } else {
1670             // We're not doing stapling, so perform the check right now
1671             checkServerCerts(peerCerts);
1672         }
1673     }
1674 
1675     /**
1676      * If certificate status stapling has been enabled, the server will send
1677      * one or more status messages to the client.
1678      *
1679      * @param mesg a {@code CertificateStatus} object built from the data
1680      *      sent by the server.
1681      *
1682      * @throws IOException if any parsing errors occur.
1683      */
1684     private void certificateStatus(CertificateStatus mesg) throws IOException {
1685         if (debug != null && Debug.isOn("handshake")) {
1686             mesg.print(System.out);
1687         }
1688 
1689         // Perform the certificate check using the deferred certificates
1690         // and responses that we have obtained.
1691         session.setStatusResponses(mesg.getResponses());
1692         checkServerCerts(deferredCerts);
1693     }
1694 
1695     /*
1696      * Whether the certificates can represent the same identity?
1697      *
1698      * The certificates can be used to represent the same identity:
1699      *     1. If the subject alternative names of IP address are present in
1700      *        both certificates, they should be identical; otherwise,
1701      *     2. if the subject alternative names of DNS name are present in
1702      *        both certificates, they should be identical; otherwise,
1703      *     3. if the subject fields are present in both certificates, the
1704      *        certificate subjects and issuers should be identical.
1705      */
1706     private static boolean isIdentityEquivalent(X509Certificate thisCert,
1707             X509Certificate prevCert) {
1708         if (thisCert.equals(prevCert)) {
1709             return true;
1710         }
1711 
1712         // check subject alternative names
1713         Collection<List<?>> thisSubjectAltNames = null;
1714         try {
1715             thisSubjectAltNames = thisCert.getSubjectAlternativeNames();
1716         } catch (CertificateParsingException cpe) {
1717             if (debug != null && Debug.isOn("handshake")) {
1718                 System.out.println(
1719                         "Attempt to obtain subjectAltNames extension failed!");
1720             }
1721         }
1722 
1723         Collection<List<?>> prevSubjectAltNames = null;
1724         try {
1725             prevSubjectAltNames = prevCert.getSubjectAlternativeNames();
1726         } catch (CertificateParsingException cpe) {
1727             if (debug != null && Debug.isOn("handshake")) {
1728                 System.out.println(
1729                         "Attempt to obtain subjectAltNames extension failed!");
1730             }
1731         }
1732 
1733         if ((thisSubjectAltNames != null) && (prevSubjectAltNames != null)) {
1734             // check the iPAddress field in subjectAltName extension
1735             Collection<String> thisSubAltIPAddrs =
1736                         getSubjectAltNames(thisSubjectAltNames, ALTNAME_IP);
1737             Collection<String> prevSubAltIPAddrs =
1738                         getSubjectAltNames(prevSubjectAltNames, ALTNAME_IP);
1739             if ((thisSubAltIPAddrs != null) && (prevSubAltIPAddrs != null) &&
1740                 (isEquivalent(thisSubAltIPAddrs, prevSubAltIPAddrs))) {
1741 
1742                 return true;
1743             }
1744 
1745             // check the dNSName field in subjectAltName extension
1746             Collection<String> thisSubAltDnsNames =
1747                         getSubjectAltNames(thisSubjectAltNames, ALTNAME_DNS);
1748             Collection<String> prevSubAltDnsNames =
1749                         getSubjectAltNames(prevSubjectAltNames, ALTNAME_DNS);
1750             if ((thisSubAltDnsNames != null) && (prevSubAltDnsNames != null) &&
1751                 (isEquivalent(thisSubAltDnsNames, prevSubAltDnsNames))) {
1752 
1753                 return true;
1754             }
1755         }
1756 
1757         // check the certificate subject and issuer
1758         X500Principal thisSubject = thisCert.getSubjectX500Principal();
1759         X500Principal prevSubject = prevCert.getSubjectX500Principal();
1760         X500Principal thisIssuer = thisCert.getIssuerX500Principal();
1761         X500Principal prevIssuer = prevCert.getIssuerX500Principal();
1762         if (!thisSubject.getName().isEmpty() &&
1763                 !prevSubject.getName().isEmpty() &&
1764                 thisSubject.equals(prevSubject) &&
1765                 thisIssuer.equals(prevIssuer)) {
1766             return true;
1767         }
1768 
1769         return false;
1770     }
1771 
1772     /*
1773      * Returns the subject alternative name of the specified type in the
1774      * subjectAltNames extension of a certificate.
1775      *
1776      * Note that only those subjectAltName types that use String data
1777      * should be passed into this function.
1778      */
1779     private static Collection<String> getSubjectAltNames(
1780             Collection<List<?>> subjectAltNames, int type) {
1781 
1782         HashSet<String> subAltDnsNames = null;
1783         for (List<?> subjectAltName : subjectAltNames) {
1784             int subjectAltNameType = (Integer)subjectAltName.get(0);
1785             if (subjectAltNameType == type) {
1786                 String subAltDnsName = (String)subjectAltName.get(1);
1787                 if ((subAltDnsName != null) && !subAltDnsName.isEmpty()) {
1788                     if (subAltDnsNames == null) {
1789                         subAltDnsNames =
1790                                 new HashSet<>(subjectAltNames.size());
1791                     }
1792                     subAltDnsNames.add(subAltDnsName);
1793                 }
1794             }
1795         }
1796 
1797         return subAltDnsNames;
1798     }
1799 
1800     private static boolean isEquivalent(Collection<String> thisSubAltNames,
1801             Collection<String> prevSubAltNames) {
1802 
1803         for (String thisSubAltName : thisSubAltNames) {
1804             for (String prevSubAltName : prevSubAltNames) {
1805                 // Only allow the exactly match.  Check no wildcard character.
1806                 if (thisSubAltName.equalsIgnoreCase(prevSubAltName)) {
1807                     return true;
1808                 }
1809             }
1810         }
1811 
1812         return false;
1813     }
1814 
1815     /**
1816      * Perform client-side checking of server certificates.
1817      *
1818      * @param certs an array of {@code X509Certificate} objects presented
1819      *      by the server in the ServerCertificate message.
1820      *
1821      * @throws IOException if a failure occurs during validation or
1822      *      the trust manager associated with the {@code SSLContext} is not
1823      *      an {@code X509ExtendedTrustManager}.
1824      */
1825     private void checkServerCerts(X509Certificate[] certs)
1826             throws IOException {
1827         X509TrustManager tm = sslContext.getX509TrustManager();
1828 
1829         // find out the key exchange algorithm used
1830         // use "RSA" for non-ephemeral "RSA_EXPORT"
1831         String keyExchangeString;
1832         if (keyExchange == K_RSA_EXPORT && !serverKeyExchangeReceived) {
1833             keyExchangeString = K_RSA.name;
1834         } else {
1835             keyExchangeString = keyExchange.name;
1836         }
1837 
1838         try {
1839             if (tm instanceof X509ExtendedTrustManager) {
1840                 if (conn != null) {
1841                     ((X509ExtendedTrustManager)tm).checkServerTrusted(
1842                         certs.clone(),
1843                         keyExchangeString,
1844                         conn);
1845                 } else {
1846                     ((X509ExtendedTrustManager)tm).checkServerTrusted(
1847                         certs.clone(),
1848                         keyExchangeString,
1849                         engine);
1850                 }
1851             } else {
1852                 // Unlikely to happen, because we have wrapped the old
1853                 // X509TrustManager with the new X509ExtendedTrustManager.
1854                 throw new CertificateException(
1855                         "Improper X509TrustManager implementation");
1856             }
1857 
1858             // Once the server certificate chain has been validated, set
1859             // the certificate chain in the TLS session.
1860             session.setPeerCertificates(certs);
1861         } catch (CertificateException ce) {
1862             fatalSE(getCertificateAlert(ce), ce);
1863         }
1864     }
1865 
1866     /**
1867      * When a failure happens during certificate checking from an
1868      * {@link X509TrustManager}, determine what TLS alert description to use.
1869      *
1870      * @param cexc The exception thrown by the {@link X509TrustManager}
1871      *
1872      * @return A byte value corresponding to a TLS alert description number.
1873      */
1874     private byte getCertificateAlert(CertificateException cexc) {
1875         // The specific reason for the failure will determine how to
1876         // set the alert description value
1877         byte alertDesc = Alerts.alert_certificate_unknown;
1878 
1879         Throwable baseCause = cexc.getCause();
1880         if (baseCause instanceof CertPathValidatorException) {
1881             CertPathValidatorException cpve =
1882                     (CertPathValidatorException)baseCause;
1883             Reason reason = cpve.getReason();
1884             if (reason == BasicReason.REVOKED) {
1885                 alertDesc = staplingActive ?
1886                         Alerts.alert_bad_certificate_status_response :
1887                         Alerts.alert_certificate_revoked;
1888             } else if (reason == BasicReason.UNDETERMINED_REVOCATION_STATUS) {
1889                 alertDesc = staplingActive ?
1890                         Alerts.alert_bad_certificate_status_response :
1891                         Alerts.alert_certificate_unknown;
1892             }
1893         }
1894 
1895         return alertDesc;
1896     }
1897 }
1898