< prev index next >

src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java

Print this page




  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.nio.*;
  30 import java.security.*;
  31 import java.util.*;

  32 import java.util.function.BiFunction;

  33 
  34 import javax.crypto.BadPaddingException;
  35 
  36 import javax.net.ssl.*;
  37 import javax.net.ssl.SSLEngineResult.*;
  38 
  39 /**
  40  * Implementation of an non-blocking SSLEngine.
  41  *
  42  * *Currently*, the SSLEngine code exists in parallel with the current
  43  * SSLSocket.  As such, the current implementation is using legacy code
  44  * with many of the same abstractions.  However, it varies in many
  45  * areas, most dramatically in the IO handling.
  46  *
  47  * There are three main I/O threads that can be existing in parallel:
  48  * wrap(), unwrap(), and beginHandshake().  We are encouraging users to
  49  * not call multiple instances of wrap or unwrap, because the data could
  50  * appear to flow out of the SSLEngine in a non-sequential order.  We
  51  * take all steps we can to at least make sure the ordering remains
  52  * consistent, but once the calls returns, anything can happen.  For


 220      *
 221      * Note: we support a pseudo protocol called SSLv2Hello which when
 222      * set will result in an SSL v2 Hello being sent with SSL (version 3.0)
 223      * or TLS (version 3.1, 3.2, etc.) version info.
 224      */
 225     private ProtocolList        enabledProtocols;
 226 
 227     /*
 228      * The SSL version associated with this connection.
 229      */
 230     private ProtocolVersion     protocolVersion;
 231 
 232     /*
 233      * security parameters for secure renegotiation.
 234      */
 235     private boolean             secureRenegotiation;
 236     private byte[]              clientVerifyData;
 237     private byte[]              serverVerifyData;
 238 
 239     /*









 240      * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *
 241      * IMPORTANT STUFF TO UNDERSTANDING THE SYNCHRONIZATION ISSUES.
 242      * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *
 243      *
 244      * There are several locks here.
 245      *
 246      * The primary lock is the per-instance lock used by
 247      * synchronized(this) and the synchronized methods.  It controls all
 248      * access to things such as the connection state and variables which
 249      * affect handshaking.  If we are inside a synchronized method, we
 250      * can access the state directly, otherwise, we must use the
 251      * synchronized equivalents.
 252      *
 253      * Note that we must never acquire the <code>this</code> lock after
 254      * <code>writeLock</code> or run the risk of deadlock.
 255      *
 256      * Grab some coffee, and be careful with any code changes.
 257      */
 258     private Object              wrapLock;
 259     private Object              unwrapLock;


 407 
 408         //
 409         // We're already in the middle of a handshake.
 410         //
 411         case cs_HANDSHAKE:
 412         case cs_RENEGOTIATE:
 413             return;
 414 
 415         //
 416         // Anyone allowed to call this routine is required to
 417         // do so ONLY if the connection state is reasonable...
 418         //
 419         default:
 420             throw new IllegalStateException("Internal error");
 421         }
 422 
 423         // state is either cs_START or cs_DATA
 424         if (connectionState == cs_START) {
 425             connectionState = cs_HANDSHAKE;
 426         } else { // cs_DATA















 427             connectionState = cs_RENEGOTIATE;
 428         }
 429 
 430         if (roleIsServer) {
 431             handshaker = new ServerHandshaker(this, sslContext,
 432                     enabledProtocols, doClientAuth,
 433                     protocolVersion, connectionState == cs_HANDSHAKE,
 434                     secureRenegotiation, clientVerifyData, serverVerifyData,
 435                     isDTLS);
 436             handshaker.setSNIMatchers(sniMatchers);
 437             handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
 438         } else {
 439             handshaker = new ClientHandshaker(this, sslContext,
 440                     enabledProtocols,
 441                     protocolVersion, connectionState == cs_HANDSHAKE,
 442                     secureRenegotiation, clientVerifyData, serverVerifyData,
 443                     isDTLS);
 444             handshaker.setSNIServerNames(serverNames);
 445         }
 446         handshaker.setMaximumPacketSize(maximumPacketSize);


 605                         "Warning: Using insecure renegotiation");
 606                 }
 607             }
 608 
 609             // initialize the handshaker, move to cs_RENEGOTIATE
 610             initHandshaker();
 611             break;
 612 
 613         case cs_RENEGOTIATE:
 614             // handshaking already in progress, return
 615             return;
 616 
 617         default:
 618             // cs_ERROR/cs_CLOSED
 619             throw new SSLException("SSLEngine is closing/closed");
 620         }
 621 
 622         //
 623         // Kickstart handshake state machine if we need to ...
 624         //
 625         if (!handshaker.activated()) {
 626              // prior to handshaking, activate the handshake
 627             if (connectionState == cs_RENEGOTIATE) {
 628                 // don't use SSLv2Hello when renegotiating
 629                 handshaker.activate(protocolVersion);
 630             } else {
 631                 handshaker.activate(null);
 632             }
 633 
 634             if (handshaker instanceof ClientHandshaker) {
 635                 // send client hello
 636                 handshaker.kickstart();
 637             } else {    // instanceof ServerHandshaker
 638                 if (connectionState == cs_HANDSHAKE) {
 639                     // initial handshake, no kickstart message to send
 640                 } else {
 641                     // we want to renegotiate, send hello request
 642                     handshaker.kickstart();
 643                 }
 644             }
 645         }


1037      */
1038     private synchronized HandshakeStatus processInputRecord(
1039             Plaintext plainText,
1040             ByteBuffer[] appData, int offset, int length) throws IOException {
1041 
1042         HandshakeStatus hsStatus = null;
1043         switch (plainText.contentType) {
1044             case Record.ct_handshake:
1045                 /*
1046                  * Handshake messages always go to a pending session
1047                  * handshaker ... if there isn't one, create one.  This
1048                  * must work asynchronously, for renegotiation.
1049                  *
1050                  * NOTE that handshaking will either resume a session
1051                  * which was in the cache (and which might have other
1052                  * connections in it already), or else will start a new
1053                  * session (new keys exchanged) with just this connection
1054                  * in it.
1055                  */
1056                 initHandshaker();




1057                 if (!handshaker.activated()) {
1058                     // prior to handshaking, activate the handshake
1059                     if (connectionState == cs_RENEGOTIATE) {
1060                         // don't use SSLv2Hello when renegotiating
1061                         handshaker.activate(protocolVersion);
1062                     } else {
1063                         handshaker.activate(null);
1064                     }
1065                 }
1066 
1067                 /*
1068                  * process the handshake record ... may contain just
1069                  * a partial handshake message or multiple messages.
1070                  *
1071                  * The handshaker state machine will ensure that it's
1072                  * a finished message.
1073                  */
1074                 handshaker.processRecord(plainText.fragment, expectingFinished);
1075                 expectingFinished = false;
1076 


1081                     if (connectionState == cs_RENEGOTIATE) {
1082                         connectionState = cs_DATA;
1083                     }
1084                 } else if (handshaker.isDone()) {
1085                     // reset the parameters for secure renegotiation.
1086                     secureRenegotiation =
1087                                 handshaker.isSecureRenegotiation();
1088                     clientVerifyData = handshaker.getClientVerifyData();
1089                     serverVerifyData = handshaker.getServerVerifyData();
1090                     // set connection ALPN value
1091                     applicationProtocol =
1092                         handshaker.getHandshakeApplicationProtocol();
1093 
1094                     sess = handshaker.getSession();
1095                     handshakeSession = null;
1096                     if (outputRecord.isEmpty()) {
1097                         hsStatus = finishHandshake();
1098                         connectionState = cs_DATA;
1099                     }
1100 
1101                     // No handshakeListeners here.  That's a
1102                     // SSLSocket thing.































1103                 } else if (handshaker.taskOutstanding()) {
1104                     hsStatus = HandshakeStatus.NEED_TASK;
1105                 }
1106                 break;
1107 
1108             case Record.ct_application_data:
1109                 // Pass this right back up to the application.
1110                 if ((connectionState != cs_DATA)
1111                         && (connectionState != cs_RENEGOTIATE)
1112                         && (connectionState != cs_CLOSED)) {
1113                     throw new SSLProtocolException(
1114                             "Data received in non-data state: " +
1115                             connectionState);
1116                 }
1117 
1118                 if (expectingFinished) {
1119                     throw new SSLProtocolException
1120                             ("Expecting finished message, received data");
1121                 }
1122 


1680      */
1681     @Override
1682     public synchronized SSLSession getSession() {
1683         return sess;
1684     }
1685 
1686     @Override
1687     public synchronized SSLSession getHandshakeSession() {
1688         return handshakeSession;
1689     }
1690 
1691     synchronized void setHandshakeSession(SSLSessionImpl session) {
1692         // update the fragment size, which may be negotiated during handshaking
1693         inputRecord.changeFragmentSize(session.getNegotiatedMaxFragSize());
1694         outputRecord.changeFragmentSize(session.getNegotiatedMaxFragSize());
1695 
1696         handshakeSession = session;
1697     }
1698 
1699     /**



























































1700      * Returns a delegated <code>Runnable</code> task for
1701      * this <code>SSLEngine</code>.
1702      */
1703     @Override
1704     public synchronized Runnable getDelegatedTask() {
1705         if (handshaker != null) {
1706             return handshaker.getTask();
1707         }
1708         return null;
1709     }
1710 
1711 
1712     //
1713     // EXCEPTION AND ALERT HANDLING
1714     //
1715 
1716     /*
1717      * Send a warning alert.
1718      */
1719     void warning(byte description) {


2267     public synchronized String getHandshakeApplicationProtocol() {
2268         if ((handshaker != null) && handshaker.started()) {
2269             return handshaker.getHandshakeApplicationProtocol();
2270         }
2271         return null;
2272     }
2273 
2274     @Override
2275     public synchronized void setHandshakeApplicationProtocolSelector(
2276         BiFunction<SSLEngine, List<String>, String> selector) {
2277         applicationProtocolSelector = selector;
2278         if ((handshaker != null) && !handshaker.activated()) {
2279             handshaker.setApplicationProtocolSelectorSSLEngine(selector);
2280         }
2281     }
2282 
2283     @Override
2284     public synchronized BiFunction<SSLEngine, List<String>, String>
2285         getHandshakeApplicationProtocolSelector() {
2286         return this.applicationProtocolSelector;


































































2287     }
2288 
2289     /**
2290      * Returns a printable representation of this end of the connection.
2291      */
2292     @Override
2293     public String toString() {
2294         StringBuilder retval = new StringBuilder(80);
2295 
2296         retval.append(Integer.toHexString(hashCode()));
2297         retval.append("[");
2298         retval.append("SSLEngine[hostname=");
2299         String host = getPeerHost();
2300         retval.append((host == null) ? "null" : host);
2301         retval.append(" port=");
2302         retval.append(Integer.toString(getPeerPort()));
2303         retval.append(" role=" + (roleIsServer ? "Server" : "Client"));
2304         retval.append("] ");
2305         retval.append(getSession().getCipherSuite());
2306         retval.append("]");


  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.nio.*;
  30 import java.security.*;
  31 import java.util.*;
  32 import java.util.Map.Entry;
  33 import java.util.function.BiFunction;
  34 import java.util.function.Consumer;
  35 
  36 import javax.crypto.BadPaddingException;
  37 
  38 import javax.net.ssl.*;
  39 import javax.net.ssl.SSLEngineResult.*;
  40 
  41 /**
  42  * Implementation of an non-blocking SSLEngine.
  43  *
  44  * *Currently*, the SSLEngine code exists in parallel with the current
  45  * SSLSocket.  As such, the current implementation is using legacy code
  46  * with many of the same abstractions.  However, it varies in many
  47  * areas, most dramatically in the IO handling.
  48  *
  49  * There are three main I/O threads that can be existing in parallel:
  50  * wrap(), unwrap(), and beginHandshake().  We are encouraging users to
  51  * not call multiple instances of wrap or unwrap, because the data could
  52  * appear to flow out of the SSLEngine in a non-sequential order.  We
  53  * take all steps we can to at least make sure the ordering remains
  54  * consistent, but once the calls returns, anything can happen.  For


 222      *
 223      * Note: we support a pseudo protocol called SSLv2Hello which when
 224      * set will result in an SSL v2 Hello being sent with SSL (version 3.0)
 225      * or TLS (version 3.1, 3.2, etc.) version info.
 226      */
 227     private ProtocolList        enabledProtocols;
 228 
 229     /*
 230      * The SSL version associated with this connection.
 231      */
 232     private ProtocolVersion     protocolVersion;
 233 
 234     /*
 235      * security parameters for secure renegotiation.
 236      */
 237     private boolean             secureRenegotiation;
 238     private byte[]              clientVerifyData;
 239     private byte[]              serverVerifyData;
 240 
 241     /*
 242      * If anyone wants to get notified about handshake completions,
 243      * they'll show up on this list.
 244      */
 245     private HashMap<HandshakeCompletedListener, AccessControlContext>
 246                                                         handshakeCompletedListeners;
 247 
 248     private HashMap<HandshakeListener, AccessControlContext> handshakeListeners;
 249 
 250     /*
 251      * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *
 252      * IMPORTANT STUFF TO UNDERSTANDING THE SYNCHRONIZATION ISSUES.
 253      * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *
 254      *
 255      * There are several locks here.
 256      *
 257      * The primary lock is the per-instance lock used by
 258      * synchronized(this) and the synchronized methods.  It controls all
 259      * access to things such as the connection state and variables which
 260      * affect handshaking.  If we are inside a synchronized method, we
 261      * can access the state directly, otherwise, we must use the
 262      * synchronized equivalents.
 263      *
 264      * Note that we must never acquire the <code>this</code> lock after
 265      * <code>writeLock</code> or run the risk of deadlock.
 266      *
 267      * Grab some coffee, and be careful with any code changes.
 268      */
 269     private Object              wrapLock;
 270     private Object              unwrapLock;


 418 
 419         //
 420         // We're already in the middle of a handshake.
 421         //
 422         case cs_HANDSHAKE:
 423         case cs_RENEGOTIATE:
 424             return;
 425 
 426         //
 427         // Anyone allowed to call this routine is required to
 428         // do so ONLY if the connection state is reasonable...
 429         //
 430         default:
 431             throw new IllegalStateException("Internal error");
 432         }
 433 
 434         // state is either cs_START or cs_DATA
 435         if (connectionState == cs_START) {
 436             connectionState = cs_HANDSHAKE;
 437         } else { // cs_DATA
 438             if (handshakeListeners != null) {
 439                 for (final Entry<HandshakeListener, AccessControlContext> e : 
 440                     handshakeListeners.entrySet()) {
 441                     boolean renegotiationEnabled = AccessController.doPrivileged(
 442                             new PrivilegedAction<Boolean>() {
 443                                 @Override
 444                                 public Boolean run() {
 445                                     return e.getKey().renegotiationEnabled();
 446                                 }
 447                             }, e.getValue());
 448                     if (!renegotiationEnabled) {
 449                         return;
 450                     }
 451                 }
 452             }
 453             connectionState = cs_RENEGOTIATE;
 454         }
 455 
 456         if (roleIsServer) {
 457             handshaker = new ServerHandshaker(this, sslContext,
 458                     enabledProtocols, doClientAuth,
 459                     protocolVersion, connectionState == cs_HANDSHAKE,
 460                     secureRenegotiation, clientVerifyData, serverVerifyData,
 461                     isDTLS);
 462             handshaker.setSNIMatchers(sniMatchers);
 463             handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
 464         } else {
 465             handshaker = new ClientHandshaker(this, sslContext,
 466                     enabledProtocols,
 467                     protocolVersion, connectionState == cs_HANDSHAKE,
 468                     secureRenegotiation, clientVerifyData, serverVerifyData,
 469                     isDTLS);
 470             handshaker.setSNIServerNames(serverNames);
 471         }
 472         handshaker.setMaximumPacketSize(maximumPacketSize);


 631                         "Warning: Using insecure renegotiation");
 632                 }
 633             }
 634 
 635             // initialize the handshaker, move to cs_RENEGOTIATE
 636             initHandshaker();
 637             break;
 638 
 639         case cs_RENEGOTIATE:
 640             // handshaking already in progress, return
 641             return;
 642 
 643         default:
 644             // cs_ERROR/cs_CLOSED
 645             throw new SSLException("SSLEngine is closing/closed");
 646         }
 647 
 648         //
 649         // Kickstart handshake state machine if we need to ...
 650         //
 651         if (handshaker != null && !handshaker.activated()) {
 652              // prior to handshaking, activate the handshake
 653             if (connectionState == cs_RENEGOTIATE) {
 654                 // don't use SSLv2Hello when renegotiating
 655                 handshaker.activate(protocolVersion);
 656             } else {
 657                 handshaker.activate(null);
 658             }
 659 
 660             if (handshaker instanceof ClientHandshaker) {
 661                 // send client hello
 662                 handshaker.kickstart();
 663             } else {    // instanceof ServerHandshaker
 664                 if (connectionState == cs_HANDSHAKE) {
 665                     // initial handshake, no kickstart message to send
 666                 } else {
 667                     // we want to renegotiate, send hello request
 668                     handshaker.kickstart();
 669                 }
 670             }
 671         }


1063      */
1064     private synchronized HandshakeStatus processInputRecord(
1065             Plaintext plainText,
1066             ByteBuffer[] appData, int offset, int length) throws IOException {
1067 
1068         HandshakeStatus hsStatus = null;
1069         switch (plainText.contentType) {
1070             case Record.ct_handshake:
1071                 /*
1072                  * Handshake messages always go to a pending session
1073                  * handshaker ... if there isn't one, create one.  This
1074                  * must work asynchronously, for renegotiation.
1075                  *
1076                  * NOTE that handshaking will either resume a session
1077                  * which was in the cache (and which might have other
1078                  * connections in it already), or else will start a new
1079                  * session (new keys exchanged) with just this connection
1080                  * in it.
1081                  */
1082                 initHandshaker();
1083                 if (connectionState == cs_DATA && handshaker == null) {
1084                     // Renegotiation was disabled by a HandshakeListener
1085                     break;
1086                 }
1087                 if (!handshaker.activated()) {
1088                     // prior to handshaking, activate the handshake
1089                     if (connectionState == cs_RENEGOTIATE) {
1090                         // don't use SSLv2Hello when renegotiating
1091                         handshaker.activate(protocolVersion);
1092                     } else {
1093                         handshaker.activate(null);
1094                     }
1095                 }
1096 
1097                 /*
1098                  * process the handshake record ... may contain just
1099                  * a partial handshake message or multiple messages.
1100                  *
1101                  * The handshaker state machine will ensure that it's
1102                  * a finished message.
1103                  */
1104                 handshaker.processRecord(plainText.fragment, expectingFinished);
1105                 expectingFinished = false;
1106 


1111                     if (connectionState == cs_RENEGOTIATE) {
1112                         connectionState = cs_DATA;
1113                     }
1114                 } else if (handshaker.isDone()) {
1115                     // reset the parameters for secure renegotiation.
1116                     secureRenegotiation =
1117                                 handshaker.isSecureRenegotiation();
1118                     clientVerifyData = handshaker.getClientVerifyData();
1119                     serverVerifyData = handshaker.getServerVerifyData();
1120                     // set connection ALPN value
1121                     applicationProtocol =
1122                         handshaker.getHandshakeApplicationProtocol();
1123 
1124                     sess = handshaker.getSession();
1125                     handshakeSession = null;
1126                     if (outputRecord.isEmpty()) {
1127                         hsStatus = finishHandshake();
1128                         connectionState = cs_DATA;
1129                     }
1130 
1131                     if (handshakeListeners != null) {
1132                         HandshakeVerifyDataEvent event =
1133                                 new HandshakeVerifyDataEvent(this,
1134                                         clientVerifyData,
1135                                         serverVerifyData);
1136 
1137                         Thread thread = new Thread(
1138                             null,
1139                             new NotifyHandshakeVerifyData(
1140                                 handshakeListeners.entrySet(), event),
1141                             "HandshakeNotify-Thread",
1142                             0,
1143                             false);
1144                         thread.start();
1145                     }
1146 
1147                     //
1148                     // Tell folk about handshake completion, but do
1149                     // it in a separate thread.
1150                     //
1151                     if (handshakeCompletedListeners != null) {
1152                         HandshakeCompletedEvent event =
1153                             new HandshakeCompletedEvent(this, sess);
1154 
1155                         Thread thread = new Thread(
1156                             null,
1157                             new NotifyHandshakeComplete(
1158                                 handshakeCompletedListeners.entrySet(), event),
1159                             "HandshakeCompletedNotify-Thread",
1160                             0,
1161                             false);
1162                         thread.start();
1163                     }
1164                 } else if (handshaker.taskOutstanding()) {
1165                     hsStatus = HandshakeStatus.NEED_TASK;
1166                 }
1167                 break;
1168 
1169             case Record.ct_application_data:
1170                 // Pass this right back up to the application.
1171                 if ((connectionState != cs_DATA)
1172                         && (connectionState != cs_RENEGOTIATE)
1173                         && (connectionState != cs_CLOSED)) {
1174                     throw new SSLProtocolException(
1175                             "Data received in non-data state: " +
1176                             connectionState);
1177                 }
1178 
1179                 if (expectingFinished) {
1180                     throw new SSLProtocolException
1181                             ("Expecting finished message, received data");
1182                 }
1183 


1741      */
1742     @Override
1743     public synchronized SSLSession getSession() {
1744         return sess;
1745     }
1746 
1747     @Override
1748     public synchronized SSLSession getHandshakeSession() {
1749         return handshakeSession;
1750     }
1751 
1752     synchronized void setHandshakeSession(SSLSessionImpl session) {
1753         // update the fragment size, which may be negotiated during handshaking
1754         inputRecord.changeFragmentSize(session.getNegotiatedMaxFragSize());
1755         outputRecord.changeFragmentSize(session.getNegotiatedMaxFragSize());
1756 
1757         handshakeSession = session;
1758     }
1759 
1760     /**
1761      * Registers an event listener to receive notifications that an
1762      * SSL handshake has completed on this connection.
1763      */
1764     @Override
1765     public synchronized void addHandshakeCompletedListener(
1766             HandshakeCompletedListener listener) {
1767         if (listener == null) {
1768             throw new IllegalArgumentException("listener is null");
1769         }
1770         if (handshakeCompletedListeners == null) {
1771             handshakeCompletedListeners = new
1772                 HashMap<HandshakeCompletedListener, AccessControlContext>(4);
1773         }
1774         handshakeCompletedListeners.put(listener, AccessController.getContext());
1775     }
1776 
1777     /**
1778      * Removes a previously registered handshake completion listener.
1779      */
1780     @Override
1781     public synchronized void removeHandshakeCompletedListener(
1782             HandshakeCompletedListener listener) {
1783         if (handshakeCompletedListeners == null) {
1784             throw new IllegalArgumentException("no listeners");
1785         }
1786         if (handshakeCompletedListeners.remove(listener) == null) {
1787             throw new IllegalArgumentException("listener not registered");
1788         }
1789         if (handshakeCompletedListeners.isEmpty()) {
1790             handshakeCompletedListeners = null;
1791         }
1792     }
1793 
1794     @Override
1795     public synchronized void addHandshakeListener(HandshakeListener listener) {
1796         if (listener == null) {
1797             throw new IllegalArgumentException("listener is null");
1798         }
1799         if (handshakeListeners == null) {
1800             handshakeListeners = new
1801                 HashMap<HandshakeListener, AccessControlContext>(4);
1802         }
1803         handshakeListeners.put(listener, AccessController.getContext());
1804     }
1805 
1806     @Override
1807     public synchronized void removeHandshakeListener(HandshakeListener listener) {
1808         if (handshakeListeners == null) {
1809             throw new IllegalArgumentException("no listeners");
1810         }
1811         if (handshakeListeners.remove(listener) == null) {
1812             throw new IllegalArgumentException("listener not registered");
1813         }
1814         if (handshakeListeners.isEmpty()) {
1815             handshakeListeners = null;
1816         }
1817     }
1818 
1819     /**
1820      * Returns a delegated <code>Runnable</code> task for
1821      * this <code>SSLEngine</code>.
1822      */
1823     @Override
1824     public synchronized Runnable getDelegatedTask() {
1825         if (handshaker != null) {
1826             return handshaker.getTask();
1827         }
1828         return null;
1829     }
1830 
1831 
1832     //
1833     // EXCEPTION AND ALERT HANDLING
1834     //
1835 
1836     /*
1837      * Send a warning alert.
1838      */
1839     void warning(byte description) {


2387     public synchronized String getHandshakeApplicationProtocol() {
2388         if ((handshaker != null) && handshaker.started()) {
2389             return handshaker.getHandshakeApplicationProtocol();
2390         }
2391         return null;
2392     }
2393 
2394     @Override
2395     public synchronized void setHandshakeApplicationProtocolSelector(
2396         BiFunction<SSLEngine, List<String>, String> selector) {
2397         applicationProtocolSelector = selector;
2398         if ((handshaker != null) && !handshaker.activated()) {
2399             handshaker.setApplicationProtocolSelectorSSLEngine(selector);
2400         }
2401     }
2402 
2403     @Override
2404     public synchronized BiFunction<SSLEngine, List<String>, String>
2405         getHandshakeApplicationProtocolSelector() {
2406         return this.applicationProtocolSelector;
2407     }
2408 
2409     //
2410     // We allocate a separate thread to deliver handshake completion
2411     // events.  This ensures that the notifications don't block the
2412     // protocol state machine.
2413     //
2414     private static abstract class NotifyHandshakeBase<T, E> implements Runnable {
2415 
2416         private Set<Map.Entry<T,AccessControlContext>>
2417                 targets;        // who gets notified
2418         private E event;          // the notification
2419 
2420         NotifyHandshakeBase(
2421             Set<Map.Entry<T,AccessControlContext>>
2422             entrySet, E e) {
2423 
2424             targets = new HashSet<>(entrySet);          // clone the entry set
2425             event = e;
2426         }
2427 
2428         @Override
2429         public void run() {
2430             // Don't need to synchronize, as it only runs in one thread.
2431             for (Map.Entry<T,AccessControlContext>
2432                 entry : targets) {
2433 
2434                 final T l = entry.getKey();
2435                 AccessControlContext acc = entry.getValue();
2436                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
2437                     @Override
2438                     public Void run() {
2439                         getEventCallbackFunction(l).accept(event);
2440                         return null;
2441                     }
2442                 }, acc);
2443             }
2444         }
2445 
2446         protected abstract Consumer<E> getEventCallbackFunction(T l);
2447     }
2448 
2449     private static class NotifyHandshakeComplete extends
2450                     NotifyHandshakeBase<HandshakeCompletedListener, HandshakeCompletedEvent> {
2451 
2452         NotifyHandshakeComplete(Set<Entry<HandshakeCompletedListener, AccessControlContext>> entrySet,
2453                 HandshakeCompletedEvent e) {
2454             super(entrySet, e);
2455         }
2456 
2457         protected Consumer<HandshakeCompletedEvent> getEventCallbackFunction(HandshakeCompletedListener l) {
2458             return (HandshakeCompletedEvent e) -> l.handshakeCompleted(e);
2459         }
2460     }
2461 
2462     private static class NotifyHandshakeVerifyData extends
2463                     NotifyHandshakeBase<HandshakeListener, HandshakeVerifyDataEvent> {
2464 
2465         NotifyHandshakeVerifyData(Set<Entry<HandshakeListener, AccessControlContext>> entrySet,
2466                 HandshakeVerifyDataEvent e) {
2467             super(entrySet, e);
2468         }
2469 
2470         protected Consumer<HandshakeVerifyDataEvent> getEventCallbackFunction(HandshakeListener l) {
2471             return (HandshakeVerifyDataEvent e) -> l.finishedVerifyData(e);
2472         }
2473     }
2474 
2475     /**
2476      * Returns a printable representation of this end of the connection.
2477      */
2478     @Override
2479     public String toString() {
2480         StringBuilder retval = new StringBuilder(80);
2481 
2482         retval.append(Integer.toHexString(hashCode()));
2483         retval.append("[");
2484         retval.append("SSLEngine[hostname=");
2485         String host = getPeerHost();
2486         retval.append((host == null) ? "null" : host);
2487         retval.append(" port=");
2488         retval.append(Integer.toString(getPeerPort()));
2489         retval.append(" role=" + (roleIsServer ? "Server" : "Client"));
2490         retval.append("] ");
2491         retval.append(getSession().getCipherSuite());
2492         retval.append("]");
< prev index next >