< 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 >