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("]");
|