src/java.base/share/classes/sun/security/ssl/TransportContext.java
changeset 50768 68fa3d4026ea
child 51141 2dd2d73c52f6
equal deleted inserted replaced
50767:356eaea05bf0 50768:68fa3d4026ea
       
     1 /*
       
     2  * Copyright (c) 2018, 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.Closeable;
       
    29 import java.io.IOException;
       
    30 import java.security.AccessControlContext;
       
    31 import java.security.AccessController;
       
    32 import java.security.PrivilegedAction;
       
    33 import java.util.HashMap;
       
    34 import java.util.HashSet;
       
    35 import java.util.List;
       
    36 import java.util.Map;
       
    37 import java.util.Set;
       
    38 import javax.net.ssl.HandshakeCompletedEvent;
       
    39 import javax.net.ssl.HandshakeCompletedListener;
       
    40 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
       
    41 import javax.net.ssl.SSLException;
       
    42 import javax.net.ssl.SSLSocket;
       
    43 import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
       
    44 
       
    45 /**
       
    46  * SSL/(D)TLS transportation context.
       
    47  */
       
    48 class TransportContext implements ConnectionContext, Closeable {
       
    49     final SSLTransport              transport;
       
    50 
       
    51     // registered plaintext consumers
       
    52     final Map<Byte, SSLConsumer>    consumers;
       
    53     final AccessControlContext      acc;
       
    54 
       
    55     final SSLContextImpl            sslContext;
       
    56     final SSLConfiguration          sslConfig;
       
    57     final InputRecord               inputRecord;
       
    58     final OutputRecord              outputRecord;
       
    59 
       
    60     // connection status
       
    61     boolean                         isUnsureMode;
       
    62     boolean                         isNegotiated = false;
       
    63     boolean                         isBroken = false;
       
    64     boolean                         isInputCloseNotified = false;
       
    65     boolean                         isOutputCloseNotified = false;
       
    66     Exception                       closeReason = null;
       
    67 
       
    68     // negotiated security parameters
       
    69     SSLSessionImpl                  conSession;
       
    70     ProtocolVersion                 protocolVersion;
       
    71     String                          applicationProtocol= null;
       
    72 
       
    73     // handshake context
       
    74     HandshakeContext                handshakeContext = null;
       
    75 
       
    76     // connection reserved status for handshake.
       
    77     boolean                         secureRenegotiation = false;
       
    78     byte[]                          clientVerifyData;
       
    79     byte[]                          serverVerifyData;
       
    80 
       
    81     // connection sensitive configuration
       
    82     List<NamedGroup>                serverRequestedNamedGroups;
       
    83 
       
    84     CipherSuite cipherSuite;
       
    85     private static final byte[] emptyByteArray = new byte[0];
       
    86 
       
    87     // Please never use the transport parameter other than storing a
       
    88     // reference to this object.
       
    89     //
       
    90     // Called by SSLEngineImpl
       
    91     TransportContext(SSLContextImpl sslContext, SSLTransport transport,
       
    92             InputRecord inputRecord, OutputRecord outputRecord) {
       
    93         this(sslContext, transport, new SSLConfiguration(sslContext, true),
       
    94                 inputRecord, outputRecord, true);
       
    95     }
       
    96 
       
    97     // Please never use the transport parameter other than storing a
       
    98     // reference to this object.
       
    99     //
       
   100     // Called by SSLSocketImpl
       
   101     TransportContext(SSLContextImpl sslContext, SSLTransport transport,
       
   102             InputRecord inputRecord, OutputRecord outputRecord,
       
   103             boolean isClientMode) {
       
   104         this(sslContext, transport,
       
   105                 new SSLConfiguration(sslContext, isClientMode),
       
   106                 inputRecord, outputRecord, false);
       
   107     }
       
   108 
       
   109     // Please never use the transport parameter other than storing a
       
   110     // reference to this object.
       
   111     //
       
   112     // Called by SSLSocketImpl with an existing SSLConfig
       
   113     TransportContext(SSLContextImpl sslContext, SSLTransport transport,
       
   114             SSLConfiguration sslConfig,
       
   115             InputRecord inputRecord, OutputRecord outputRecord) {
       
   116         this(sslContext, transport, (SSLConfiguration)sslConfig.clone(),
       
   117                 inputRecord, outputRecord, false);
       
   118     }
       
   119 
       
   120     private TransportContext(SSLContextImpl sslContext, SSLTransport transport,
       
   121             SSLConfiguration sslConfig, InputRecord inputRecord,
       
   122             OutputRecord outputRecord, boolean isUnsureMode) {
       
   123         this.transport = transport;
       
   124         this.sslContext = sslContext;
       
   125         this.inputRecord = inputRecord;
       
   126         this.outputRecord = outputRecord;
       
   127         this.sslConfig = sslConfig;
       
   128         if (this.sslConfig.maximumPacketSize == 0) {
       
   129             this.sslConfig.maximumPacketSize = outputRecord.getMaxPacketSize();
       
   130         }
       
   131         this.isUnsureMode = isUnsureMode;
       
   132 
       
   133         // initial security parameters
       
   134         this.conSession = SSLSessionImpl.nullSession;
       
   135         this.protocolVersion = this.sslConfig.maximumProtocolVersion;
       
   136         this.clientVerifyData = emptyByteArray;
       
   137         this.serverVerifyData = emptyByteArray;
       
   138 
       
   139         this.acc = AccessController.getContext();
       
   140         this.consumers = new HashMap<>();
       
   141     }
       
   142 
       
   143     // Dispatch plaintext to a specific consumer.
       
   144     void dispatch(Plaintext plaintext) throws IOException {
       
   145         if (plaintext == null) {
       
   146             return;
       
   147         }
       
   148 
       
   149         ContentType ct = ContentType.valueOf(plaintext.contentType);
       
   150         if (ct == null) {
       
   151             fatal(Alert.UNEXPECTED_MESSAGE,
       
   152                 "Unknown content type: " + plaintext.contentType);
       
   153             return;
       
   154         }
       
   155 
       
   156         switch (ct) {
       
   157             case HANDSHAKE:
       
   158                 byte type = HandshakeContext.getHandshakeType(this,
       
   159                         plaintext);
       
   160                 if (handshakeContext == null) {
       
   161                     if (type == SSLHandshake.KEY_UPDATE.id ||
       
   162                             type == SSLHandshake.NEW_SESSION_TICKET.id) {
       
   163                         if (isNegotiated &&
       
   164                                 protocolVersion.useTLS13PlusSpec()) {
       
   165                             handshakeContext = new PostHandshakeContext(this);
       
   166                         } else {
       
   167                             fatal(Alert.UNEXPECTED_MESSAGE,
       
   168                                     "Unexpected post-handshake message: " +
       
   169                                     SSLHandshake.nameOf(type));
       
   170                         }
       
   171                     } else {
       
   172                         handshakeContext = sslConfig.isClientMode ?
       
   173                                 new ClientHandshakeContext(sslContext, this) :
       
   174                                 new ServerHandshakeContext(sslContext, this);
       
   175                         outputRecord.initHandshaker();
       
   176                     }
       
   177                 }
       
   178                 handshakeContext.dispatch(type, plaintext);
       
   179                 break;
       
   180             case ALERT:
       
   181                 Alert.alertConsumer.consume(this, plaintext.fragment);
       
   182                 break;
       
   183             default:
       
   184                 SSLConsumer consumer = consumers.get(plaintext.contentType);
       
   185                 if (consumer != null) {
       
   186                     consumer.consume(this, plaintext.fragment);
       
   187                 } else {
       
   188                     fatal(Alert.UNEXPECTED_MESSAGE,
       
   189                         "Unexpected content: " + plaintext.contentType);
       
   190                 }
       
   191         }
       
   192     }
       
   193 
       
   194     void kickstart() throws IOException {
       
   195         if (isUnsureMode) {
       
   196             throw new IllegalStateException("Client/Server mode not yet set.");
       
   197         }
       
   198 
       
   199         if (outputRecord.isClosed() || inputRecord.isClosed() || isBroken) {
       
   200             if (closeReason != null) {
       
   201                 throw new SSLException(
       
   202                         "Cannot kickstart, the connection is broken or closed",
       
   203                         closeReason);
       
   204             } else {
       
   205                 throw new SSLException(
       
   206                         "Cannot kickstart, the connection is broken or closed");
       
   207             }
       
   208         }
       
   209 
       
   210         // initialize the handshaker if necessary
       
   211         if (handshakeContext == null) {
       
   212             //  TLS1.3 post-handshake
       
   213             if (isNegotiated && protocolVersion.useTLS13PlusSpec()) {
       
   214                 handshakeContext = new PostHandshakeContext(this);
       
   215             } else {
       
   216                 handshakeContext = sslConfig.isClientMode ?
       
   217                         new ClientHandshakeContext(sslContext, this) :
       
   218                         new ServerHandshakeContext(sslContext, this);
       
   219                 outputRecord.initHandshaker();
       
   220             }
       
   221         }
       
   222 
       
   223         // kickstart the handshake if needed
       
   224         //
       
   225         // Need no kickstart message on server side unless the connection
       
   226         // has been established.
       
   227         if(isNegotiated || sslConfig.isClientMode) {
       
   228            handshakeContext.kickstart();
       
   229         }
       
   230     }
       
   231 
       
   232     void keyUpdate() throws IOException {
       
   233         kickstart();
       
   234     }
       
   235 
       
   236     boolean isPostHandshakeContext() {
       
   237         return handshakeContext != null &&
       
   238                 (handshakeContext instanceof PostHandshakeContext);
       
   239     }
       
   240 
       
   241     // Note: close_notify is delivered as a warning alert.
       
   242     void warning(Alert alert) {
       
   243         // For initial handshaking, don't send a warning alert message to peer
       
   244         // if handshaker has not started.
       
   245         if (isNegotiated || handshakeContext != null) {
       
   246             try {
       
   247                 outputRecord.encodeAlert(Alert.Level.WARNING.level, alert.id);
       
   248             } catch (IOException ioe) {
       
   249                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
       
   250                     SSLLogger.warning(
       
   251                         "Warning: failed to send warning alert " + alert, ioe);
       
   252                 }
       
   253             }
       
   254         }
       
   255     }
       
   256 
       
   257     void fatal(Alert alert,
       
   258             String diagnostic) throws SSLException {
       
   259         fatal(alert, diagnostic, null);
       
   260     }
       
   261 
       
   262     void fatal(Alert alert, Throwable cause) throws SSLException {
       
   263         fatal(alert, null, cause);
       
   264     }
       
   265 
       
   266     void fatal(Alert alert,
       
   267             String diagnostic, Throwable cause) throws SSLException {
       
   268         fatal(alert, diagnostic, false, cause);
       
   269     }
       
   270 
       
   271     // Note: close_notify is not delivered via fatal() methods.
       
   272     void fatal(Alert alert, String diagnostic,
       
   273             boolean recvFatalAlert, Throwable cause) throws SSLException {
       
   274         // If we've already shutdown because of an error, there is nothing we
       
   275         // can do except rethrow the exception.
       
   276         //
       
   277         // Most exceptions seen here will be SSLExceptions. We may find the
       
   278         // occasional Exception which hasn't been converted to a SSLException,
       
   279         // so we'll do it here.
       
   280         if (closeReason != null) {
       
   281             if (cause == null) {
       
   282                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
       
   283                     SSLLogger.warning(
       
   284                             "Closed transport, general or untracked problem");
       
   285                 }
       
   286                 throw alert.createSSLException(
       
   287                         "Closed transport, general or untracked problem");
       
   288             }
       
   289 
       
   290             if (cause instanceof SSLException) {
       
   291                 throw (SSLException)cause;
       
   292             } else {    // unlikely, but just in case.
       
   293                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
       
   294                     SSLLogger.warning(
       
   295                             "Closed transport, unexpected rethrowing", cause);
       
   296                 }
       
   297                 throw alert.createSSLException("Unexpected rethrowing", cause);
       
   298             }
       
   299         }
       
   300 
       
   301         // If we have no further information, make a general-purpose
       
   302         // message for folks to see.  We generally have one or the other.
       
   303         if (diagnostic == null) {
       
   304             if (cause == null) {
       
   305                 diagnostic = "General/Untracked problem";
       
   306             } else {
       
   307                 diagnostic = cause.getMessage();
       
   308             }
       
   309         }
       
   310 
       
   311         if (cause == null) {
       
   312             cause = alert.createSSLException(diagnostic);
       
   313         }
       
   314 
       
   315         // shutdown the transport
       
   316         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
       
   317             SSLLogger.severe("Fatal (" + alert + "): " + diagnostic, cause);
       
   318         }
       
   319 
       
   320         // remember the close reason
       
   321         if (cause instanceof SSLException) {
       
   322             closeReason = (SSLException)cause;
       
   323         } else {
       
   324             // Including RuntimeException, but we'll throw those down below.
       
   325             closeReason = alert.createSSLException(diagnostic, cause);
       
   326         }
       
   327 
       
   328         // close inbound
       
   329         try {
       
   330             inputRecord.close();
       
   331         } catch (IOException ioe) {
       
   332             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
       
   333                 SSLLogger.warning("Fatal: input record closure failed", ioe);
       
   334             }
       
   335         }
       
   336 
       
   337         // invalidate the session
       
   338         if (conSession != null) {
       
   339             conSession.invalidate();
       
   340         }
       
   341 
       
   342         if (handshakeContext != null &&
       
   343                 handshakeContext.handshakeSession != null) {
       
   344             handshakeContext.handshakeSession.invalidate();
       
   345         }
       
   346 
       
   347         // send fatal alert
       
   348         //
       
   349         // If we haven't even started handshaking yet, or we are the recipient
       
   350         // of a fatal alert, no need to generate a fatal close alert.
       
   351         if (!recvFatalAlert && !isOutboundDone() && !isBroken &&
       
   352                 (isNegotiated || handshakeContext != null)) {
       
   353             try {
       
   354                 outputRecord.encodeAlert(Alert.Level.FATAL.level, alert.id);
       
   355             } catch (IOException ioe) {
       
   356                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
       
   357                     SSLLogger.warning(
       
   358                         "Fatal: failed to send fatal alert " + alert, ioe);
       
   359                 }
       
   360             }
       
   361         }
       
   362 
       
   363         // close outbound
       
   364         try {
       
   365             outputRecord.close();
       
   366         } catch (IOException ioe) {
       
   367             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
       
   368                 SSLLogger.warning("Fatal: output record closure failed", ioe);
       
   369             }
       
   370         }
       
   371 
       
   372         // terminal handshake context
       
   373         if (handshakeContext != null) {
       
   374             handshakeContext = null;
       
   375         }
       
   376 
       
   377         // terminal the transport
       
   378         try {
       
   379             transport.shutdown();
       
   380         } catch (IOException ioe) {
       
   381             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
       
   382                 SSLLogger.warning("Fatal: transport closure failed", ioe);
       
   383             }
       
   384         } finally {
       
   385             isBroken = true;
       
   386         }
       
   387 
       
   388         if (closeReason instanceof SSLException) {
       
   389             throw (SSLException)closeReason;
       
   390         } else {
       
   391             throw (RuntimeException)closeReason;
       
   392         }
       
   393     }
       
   394 
       
   395     void setUseClientMode(boolean useClientMode) {
       
   396         /*
       
   397          * If we need to change the client mode and the enabled
       
   398          * protocols and cipher suites haven't specifically been
       
   399          * set by the user, change them to the corresponding
       
   400          * default ones.
       
   401          */
       
   402         if (sslConfig.isClientMode != useClientMode) {
       
   403             // Once handshaking has begun, the mode can not be reset for the
       
   404             // life of this engine.
       
   405             if (handshakeContext != null || isNegotiated) {
       
   406                 throw new IllegalArgumentException(
       
   407                     "Cannot change mode after SSL traffic has started");
       
   408             }
       
   409 
       
   410             if (sslContext.isDefaultProtocolVesions(
       
   411                     sslConfig.enabledProtocols)) {
       
   412                 sslConfig.enabledProtocols =
       
   413                         sslContext.getDefaultProtocolVersions(!useClientMode);
       
   414             }
       
   415 
       
   416             if (sslContext.isDefaultCipherSuiteList(
       
   417                     sslConfig.enabledCipherSuites)) {
       
   418                 sslConfig.enabledCipherSuites =
       
   419                         sslContext.getDefaultCipherSuites(!useClientMode);
       
   420             }
       
   421 
       
   422             sslConfig.isClientMode = useClientMode;
       
   423         }
       
   424 
       
   425         isUnsureMode = false;
       
   426     }
       
   427 
       
   428     // The OutputRecord is closed and not buffered output record.
       
   429     boolean isOutboundDone() {
       
   430         return outputRecord.isClosed() && outputRecord.isEmpty();
       
   431     }
       
   432 
       
   433     // The OutputRecord is closed, but buffered output record may be still
       
   434     // waiting for delivery to the underlying connection.
       
   435     boolean isOutboundClosed() {
       
   436         return outputRecord.isClosed();
       
   437     }
       
   438 
       
   439     boolean isInboundDone() {
       
   440         return inputRecord.isClosed();
       
   441     }
       
   442 
       
   443     boolean isClosed() {
       
   444         return isOutboundClosed() && isInboundDone();
       
   445     }
       
   446 
       
   447     @Override
       
   448     public void close() throws IOException {
       
   449         if (!isOutboundDone()) {
       
   450             closeOutbound();
       
   451         }
       
   452 
       
   453         if (!isInboundDone()) {
       
   454             closeInbound();
       
   455         }
       
   456     }
       
   457 
       
   458     void closeInbound() {
       
   459         if (isInboundDone()) {
       
   460             return;
       
   461         }
       
   462 
       
   463         try {
       
   464             if (isInputCloseNotified) {     // passive close
       
   465                 passiveInboundClose();
       
   466             } else {                        // initiative close
       
   467                 initiateInboundClose();
       
   468             }
       
   469         } catch (IOException ioe) {
       
   470             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
       
   471                 SSLLogger.warning("inbound closure failed", ioe);
       
   472             }
       
   473         }
       
   474     }
       
   475 
       
   476     void closeOutbound() {
       
   477         if (isOutboundDone()) {
       
   478             return;
       
   479         }
       
   480 
       
   481         try {
       
   482              initiateOutboundClose();
       
   483         } catch (IOException ioe) {
       
   484             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
       
   485                 SSLLogger.warning("outbound closure failed", ioe);
       
   486             }
       
   487         }
       
   488     }
       
   489 
       
   490     // Close the connection passively.  The closure could be kickoff by
       
   491     // receiving a close_notify alert or reaching end_of_file of the socket.
       
   492     private void passiveInboundClose() throws IOException {
       
   493         if (!isInboundDone()) {
       
   494             inputRecord.close();
       
   495         }
       
   496 
       
   497         // For TLS 1.2 and prior version, it is required to respond with
       
   498         // a close_notify alert of its own and close down the connection
       
   499         // immediately, discarding any pending writes.
       
   500         if (!isOutboundDone() && !isOutputCloseNotified) {
       
   501             try {
       
   502                 // send a close_notify alert
       
   503                 warning(Alert.CLOSE_NOTIFY);
       
   504             } finally {
       
   505                 // any data received after a closure alert is ignored.
       
   506                 isOutputCloseNotified = true;
       
   507                 outputRecord.close();
       
   508             }
       
   509         }
       
   510 
       
   511         transport.shutdown();
       
   512     }
       
   513 
       
   514     // Initiate a close by sending a close_notify alert.
       
   515     private void initiateInboundClose() throws IOException {
       
   516         // TLS 1.3 does not define how to initiate and close a TLS connection
       
   517         // gracefully.  We will always send a close_notify alert, and close
       
   518         // the underlying transportation layer if needed.
       
   519         if (!isInboundDone() && !isInputCloseNotified) {
       
   520             try {
       
   521                 // send a close_notify alert
       
   522                 warning(Alert.CLOSE_NOTIFY);
       
   523             } finally {
       
   524                 // any data received after a closure alert is ignored.
       
   525                 isInputCloseNotified = true;
       
   526                 inputRecord.close();
       
   527             }
       
   528         }
       
   529 
       
   530         // For TLS 1.3, input closure is independent from output closure. Both
       
   531         // parties need not wait to receive a "close_notify" alert before
       
   532         // closing their read side of the connection.
       
   533         //
       
   534         // For TLS 1.2 and prior version, it is not required for the initiator
       
   535         // of the close to wait for the responding close_notify alert before
       
   536         // closing the read side of the connection.
       
   537         try {
       
   538             transport.shutdown();
       
   539         } finally {
       
   540             if (!isOutboundDone()) {
       
   541                 outputRecord.close();
       
   542             }
       
   543         }
       
   544     }
       
   545 
       
   546     // Initiate a close by sending a close_notify alert.
       
   547     private void initiateOutboundClose() throws IOException {
       
   548         if (!isOutboundDone() && !isOutputCloseNotified) {
       
   549             try {     // close outputRecord
       
   550                 // send a close_notify alert
       
   551                 warning(Alert.CLOSE_NOTIFY);
       
   552             } finally {
       
   553                 // any data received after a closure alert is ignored.
       
   554                 isOutputCloseNotified = true;
       
   555                 outputRecord.close();
       
   556             }
       
   557         }
       
   558 
       
   559         // It is not required for the initiator of the close to wait for the
       
   560         // responding close_notify alert before closing the read side of the
       
   561         // connection.  However, if the application protocol using TLS
       
   562         // provides that any data may be carried over the underlying transport
       
   563         // after the TLS connection is closed, the TLS implementation MUST
       
   564         // receive a "close_notify" alert before indicating end-of-data to the
       
   565         // application-layer.
       
   566         try {
       
   567             transport.shutdown();
       
   568         } finally {
       
   569             if (!isInboundDone()) {
       
   570                 inputRecord.close();
       
   571             }
       
   572         }
       
   573     }
       
   574 
       
   575     // Note; HandshakeStatus.FINISHED status is retrieved in other places.
       
   576     HandshakeStatus getHandshakeStatus() {
       
   577         if (!outputRecord.isEmpty()) {
       
   578             // If no handshaking, special case to wrap alters or
       
   579             // post-handshake messages.
       
   580             return HandshakeStatus.NEED_WRAP;
       
   581         } else if (handshakeContext != null) {
       
   582             if (!handshakeContext.delegatedActions.isEmpty()) {
       
   583                 return HandshakeStatus.NEED_TASK;
       
   584             } else if (sslContext.isDTLS() &&
       
   585                     !inputRecord.isEmpty()) {
       
   586                 return HandshakeStatus.NEED_UNWRAP_AGAIN;
       
   587             } else {
       
   588                 return HandshakeStatus.NEED_UNWRAP;
       
   589             }
       
   590         } else if (isOutboundDone() && !isInboundDone()) {
       
   591             /*
       
   592              * Special case where we're closing, but
       
   593              * still need the close_notify before we
       
   594              * can officially be closed.
       
   595              *
       
   596              * Note isOutboundDone is taken care of by
       
   597              * hasOutboundData() above.
       
   598              */
       
   599             return HandshakeStatus.NEED_UNWRAP;
       
   600         }
       
   601 
       
   602         return HandshakeStatus.NOT_HANDSHAKING;
       
   603     }
       
   604 
       
   605     HandshakeStatus finishHandshake() {
       
   606         if (protocolVersion.useTLS13PlusSpec()) {
       
   607             outputRecord.tc = this;
       
   608             inputRecord.tc = this;
       
   609             cipherSuite = handshakeContext.negotiatedCipherSuite;
       
   610             inputRecord.readCipher.baseSecret = handshakeContext.baseReadSecret;
       
   611             outputRecord.writeCipher.baseSecret = handshakeContext.baseWriteSecret;
       
   612         }
       
   613 
       
   614         handshakeContext = null;
       
   615         outputRecord.handshakeHash.finish();
       
   616         inputRecord.finishHandshake();
       
   617         outputRecord.finishHandshake();
       
   618         isNegotiated = true;
       
   619 
       
   620         // Tell folk about handshake completion, but do it in a separate thread.
       
   621         if (transport instanceof SSLSocket &&
       
   622                 sslConfig.handshakeListeners != null &&
       
   623                 !sslConfig.handshakeListeners.isEmpty()) {
       
   624             HandshakeCompletedEvent hce =
       
   625                 new HandshakeCompletedEvent((SSLSocket)transport, conSession);
       
   626             Thread thread = new Thread(
       
   627                 null,
       
   628                 new NotifyHandshake(sslConfig.handshakeListeners, hce),
       
   629                 "HandshakeCompletedNotify-Thread",
       
   630                 0,
       
   631                 false);
       
   632             thread.start();
       
   633         }
       
   634 
       
   635         return HandshakeStatus.FINISHED;
       
   636     }
       
   637 
       
   638     HandshakeStatus finishPostHandshake() {
       
   639         handshakeContext = null;
       
   640 
       
   641         // Note: May need trigger handshake completion even for post-handshake
       
   642         // authentication in the future.
       
   643 
       
   644         return HandshakeStatus.FINISHED;
       
   645     }
       
   646 
       
   647     // A separate thread is allocated to deliver handshake completion
       
   648     // events.
       
   649     private static class NotifyHandshake implements Runnable {
       
   650         private final Set<Map.Entry<HandshakeCompletedListener,
       
   651                 AccessControlContext>> targets;         // who gets notified
       
   652         private final HandshakeCompletedEvent event;    // the notification
       
   653 
       
   654         NotifyHandshake(
       
   655                 Map<HandshakeCompletedListener,AccessControlContext> listeners,
       
   656                 HandshakeCompletedEvent event) {
       
   657             this.targets = new HashSet<>(listeners.entrySet());     // clone
       
   658             this.event = event;
       
   659         }
       
   660 
       
   661         @Override
       
   662         public void run() {
       
   663             // Don't need to synchronize, as it only runs in one thread.
       
   664             for (Map.Entry<HandshakeCompletedListener,
       
   665                     AccessControlContext> entry : targets) {
       
   666                 final HandshakeCompletedListener listener = entry.getKey();
       
   667                 AccessControlContext acc = entry.getValue();
       
   668                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
       
   669                     @Override
       
   670                     public Void run() {
       
   671                         listener.handshakeCompleted(event);
       
   672                         return null;
       
   673                     }
       
   674                 }, acc);
       
   675             }
       
   676         }
       
   677     }
       
   678 }