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