< prev index next >
src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
Print this page
@@ -28,18 +28,23 @@
import java.io.*;
import java.nio.*;
import java.net.*;
import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.PrivilegedAction;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
import java.security.AlgorithmConstraints;
import java.util.*;
+import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiFunction;
+import java.util.function.Consumer;
import javax.crypto.BadPaddingException;
import javax.net.ssl.*;
import jdk.internal.misc.JavaNetInetAddressAccess;
@@ -338,10 +343,13 @@
/*
* If anyone wants to get notified about handshake completions,
* they'll show up on this list.
*/
private HashMap<HandshakeCompletedListener, AccessControlContext>
+ handshakeCompletedListeners;
+
+ private HashMap<HandshakeListener, AccessControlContext>
handshakeListeners;
/*
* Reuse the same internal input/output streams.
*/
@@ -1115,10 +1123,14 @@
* connections in it already), or else will start a new
* session (new keys exchanged) with just this connection
* in it.
*/
initHandshaker();
+ if (connectionState == cs_DATA && handshaker == null) {
+ // Renegotiation was disabled by a HandshakeListener
+ break;
+ }
if (!handshaker.activated()) {
// prior to handshaking, activate the handshake
if (connectionState == cs_RENEGOTIATE) {
// don't use SSLv2Hello when renegotiating
handshaker.activate(protocolVersion);
@@ -1161,22 +1173,38 @@
handshaker = null;
inputRecord.setHandshakeHash(null);
outputRecord.setHandshakeHash(null);
connectionState = cs_DATA;
+ if (handshakeListeners != null) {
+ HandshakeVerifyDataEvent event =
+ new HandshakeVerifyDataEvent(this,
+ clientVerifyData,
+ serverVerifyData);
+
+ Thread thread = new Thread(
+ null,
+ new NotifyHandshakeVerifyData(
+ handshakeListeners.entrySet(), event),
+ "HandshakeNotify-Thread",
+ 0,
+ false);
+ thread.start();
+ }
+
//
// Tell folk about handshake completion, but do
// it in a separate thread.
//
- if (handshakeListeners != null) {
+ if (handshakeCompletedListeners != null) {
HandshakeCompletedEvent event =
new HandshakeCompletedEvent(this, sess);
Thread thread = new Thread(
null,
- new NotifyHandshake(
- handshakeListeners.entrySet(), event),
+ new NotifyHandshakeComplete(
+ handshakeCompletedListeners.entrySet(), event),
"HandshakeCompletedNotify-Thread",
0,
false);
thread.start();
}
@@ -1352,10 +1380,25 @@
// state is either cs_START or cs_DATA
if (connectionState == cs_START) {
connectionState = cs_HANDSHAKE;
} else { // cs_DATA
+ if (handshakeListeners != null) {
+ for (final Entry<HandshakeListener, AccessControlContext> e :
+ handshakeListeners.entrySet()) {
+ boolean renegotiationEnabled = AccessController.doPrivileged(
+ new PrivilegedAction<Boolean>() {
+ @Override
+ public Boolean run() {
+ return e.getKey().renegotiationEnabled();
+ }
+ }, e.getValue());
+ if (!renegotiationEnabled) {
+ return;
+ }
+ }
+ }
connectionState = cs_RENEGOTIATE;
}
if (roleIsServer) {
handshaker = new ServerHandshaker(this, sslContext,
@@ -1497,11 +1540,11 @@
//
// Note that handshaker.kickstart() writes the message
// to its HandshakeOutStream, which calls back into
// SSLSocketImpl.writeRecord() to send it.
//
- if (!handshaker.activated()) {
+ if (handshaker != null && !handshaker.activated()) {
// prior to handshaking, activate the handshake
if (connectionState == cs_RENEGOTIATE) {
// don't use SSLv2Hello when renegotiating
handshaker.activate(protocolVersion);
} else {
@@ -2541,24 +2584,49 @@
public synchronized void addHandshakeCompletedListener(
HandshakeCompletedListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener is null");
}
- if (handshakeListeners == null) {
- handshakeListeners = new
+ if (handshakeCompletedListeners == null) {
+ handshakeCompletedListeners = new
HashMap<HandshakeCompletedListener, AccessControlContext>(4);
}
- handshakeListeners.put(listener, AccessController.getContext());
+ handshakeCompletedListeners.put(listener, AccessController.getContext());
}
/**
* Removes a previously registered handshake completion listener.
*/
@Override
public synchronized void removeHandshakeCompletedListener(
HandshakeCompletedListener listener) {
+ if (handshakeCompletedListeners == null) {
+ throw new IllegalArgumentException("no listeners");
+ }
+ if (handshakeCompletedListeners.remove(listener) == null) {
+ throw new IllegalArgumentException("listener not registered");
+ }
+ if (handshakeCompletedListeners.isEmpty()) {
+ handshakeCompletedListeners = null;
+ }
+ }
+
+ @Override
+ public synchronized void addHandshakeListener(HandshakeListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener is null");
+ }
+ if (handshakeListeners == null) {
+ handshakeListeners = new
+ HashMap<HandshakeListener, AccessControlContext>(4);
+ }
+ handshakeListeners.put(listener, AccessController.getContext());
+ }
+
+ @Override
+ public synchronized void removeHandshakeListener(HandshakeListener listener) {
if (handshakeListeners == null) {
throw new IllegalArgumentException("no listeners");
}
if (handshakeListeners.remove(listener) == null) {
throw new IllegalArgumentException("listener not registered");
@@ -2683,41 +2751,69 @@
//
// We allocate a separate thread to deliver handshake completion
// events. This ensures that the notifications don't block the
// protocol state machine.
//
- private static class NotifyHandshake implements Runnable {
+ private static abstract class NotifyHandshakeBase<T, E> implements Runnable {
- private Set<Map.Entry<HandshakeCompletedListener,AccessControlContext>>
+ private Set<Map.Entry<T,AccessControlContext>>
targets; // who gets notified
- private HandshakeCompletedEvent event; // the notification
+ private E event; // the notification
- NotifyHandshake(
- Set<Map.Entry<HandshakeCompletedListener,AccessControlContext>>
- entrySet, HandshakeCompletedEvent e) {
+ NotifyHandshakeBase(
+ Set<Map.Entry<T,AccessControlContext>>
+ entrySet, E e) {
targets = new HashSet<>(entrySet); // clone the entry set
event = e;
}
@Override
public void run() {
// Don't need to synchronize, as it only runs in one thread.
- for (Map.Entry<HandshakeCompletedListener,AccessControlContext>
+ for (Map.Entry<T,AccessControlContext>
entry : targets) {
- final HandshakeCompletedListener l = entry.getKey();
+ final T l = entry.getKey();
AccessControlContext acc = entry.getValue();
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
- l.handshakeCompleted(event);
+ getEventCallbackFunction(l).accept(event);
return null;
}
}, acc);
}
}
+
+ protected abstract Consumer<E> getEventCallbackFunction(T l);
+ }
+
+ private static class NotifyHandshakeComplete extends
+ NotifyHandshakeBase<HandshakeCompletedListener, HandshakeCompletedEvent> {
+
+ NotifyHandshakeComplete(Set<Entry<HandshakeCompletedListener, AccessControlContext>> entrySet,
+ HandshakeCompletedEvent e) {
+ super(entrySet, e);
+ }
+
+ protected Consumer<HandshakeCompletedEvent> getEventCallbackFunction(HandshakeCompletedListener l) {
+ return (HandshakeCompletedEvent e) -> l.handshakeCompleted(e);
+ }
+ }
+
+ private static class NotifyHandshakeVerifyData extends
+ NotifyHandshakeBase<HandshakeListener, HandshakeVerifyDataEvent> {
+
+ NotifyHandshakeVerifyData(Set<Entry<HandshakeListener, AccessControlContext>> entrySet,
+ HandshakeVerifyDataEvent e) {
+ super(entrySet, e);
+ }
+
+ protected Consumer<HandshakeVerifyDataEvent> getEventCallbackFunction(HandshakeListener l) {
+ return (HandshakeVerifyDataEvent e) -> l.finishedVerifyData(e);
+ }
}
/**
* Returns a printable representation of this end of the connection.
*/
< prev index next >