Author: markt
Date: Fri Feb 25 19:19:13 2011
New Revision: 1074675

URL: http://svn.apache.org/viewvc?rev=1074675&view=rev
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=49284
Support SSL re-negotiation in the HTTP NIO connector
There is a fair amount of renaming in this patch. The real work is in the new 
rehandshake() method in the SecureNioChannel.

Modified:
    tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
    tomcat/trunk/java/org/apache/coyote/http11/LocalStrings.properties
    tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java
    tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java
    tomcat/trunk/webapps/docs/changelog.xml

Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java?rev=1074675&r1=1074674&r2=1074675&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java 
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java Fri Feb 
25 19:19:13 2011
@@ -23,6 +23,8 @@ import java.nio.channels.SelectionKey;
 import java.util.Locale;
 import java.util.concurrent.Executor;
 
+import javax.net.ssl.SSLEngine;
+
 import org.apache.coyote.ActionCode;
 import org.apache.coyote.Request;
 import org.apache.coyote.RequestInfo;
@@ -42,7 +44,9 @@ import org.apache.tomcat.util.net.NioCha
 import org.apache.tomcat.util.net.NioEndpoint;
 import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment;
 import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.net.SecureNioChannel;
 import org.apache.tomcat.util.net.SocketStatus;
+import org.apache.tomcat.util.net.jsse.JSSEFactory;
 
 
 /**
@@ -625,8 +629,25 @@ public class Http11NioProcessor extends 
                     .setLimit(maxSavePostSize);
                 inputBuffer.addActiveFilter
                     (inputFilters[Constants.BUFFERED_FILTER]);
+
+                SecureNioChannel sslChannel = (SecureNioChannel) socket;
+                SSLEngine engine = sslChannel.getSslEngine();
+                if (!engine.getNeedClientAuth() && 
!engine.getWantClientAuth()) {
+                    // Need to re-negotiate SSL connection
+                    engine.setNeedClientAuth(true);
+                    try {
+                        sslChannel.rehandshake();
+                        sslSupport = (new JSSEFactory()).getSSLSupport(
+                                engine.getSession());
+                    } catch (IOException ioe) {
+                        
log.warn(sm.getString("http11processor.socket.sslreneg",
+                                ioe));
+                    }
+                }
                 try {
-                    Object sslO = sslSupport.getPeerCertificateChain(true);
+                    // use force=false since re-negotiation is handled above
+                    // (and it is a NO-OP for NIO anyway)
+                    Object sslO = sslSupport.getPeerCertificateChain(false);
                     if( sslO != null) {
                         request.setAttribute
                             (SSLSupport.CERTIFICATE_KEY, sslO);

Modified: tomcat/trunk/java/org/apache/coyote/http11/LocalStrings.properties
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/LocalStrings.properties?rev=1074675&r1=1074674&r2=1074675&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/LocalStrings.properties 
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/LocalStrings.properties Fri Feb 
25 19:19:13 2011
@@ -31,6 +31,7 @@ http11processor.request.process=Error pr
 http11processor.request.finish=Error finishing request
 http11processor.response.finish=Error finishing response
 http11processor.socket.info=Exception getting socket information
+http11processor.socket.sslreneg=Exception re-negotiating SSL connection
 http11processor.socket.ssl=Exception getting SSL attributes
 http11processor.socket.timeout=Error setting socket timeout
 

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java?rev=1074675&r1=1074674&r2=1074675&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java Fri Feb 25 
19:19:13 2011
@@ -175,7 +175,7 @@ public class NioChannel implements ByteC
      * @return boolean
      * TODO Implement this org.apache.tomcat.util.net.SecureNioChannel method
      */
-    public boolean isInitHandshakeComplete() {
+    public boolean isHandshakeComplete() {
         return true;
     }
 

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java?rev=1074675&r1=1074674&r2=1074675&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java 
(original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java Fri Feb 
25 19:19:13 2011
@@ -43,8 +43,8 @@ public class SecureNioChannel extends Ni
     
     protected SSLEngine sslEngine;
     
-    protected boolean initHandshakeComplete = false;
-    protected HandshakeStatus initHandshakeStatus; //gets set by begin 
handshake
+    protected boolean handshakeComplete = false;
+    protected HandshakeStatus handshakeStatus; //gets set by begin handshake
     
     protected boolean closed = false;
     protected boolean closing = false;
@@ -82,12 +82,12 @@ public class SecureNioChannel extends Ni
         netOutBuffer.limit(0);
         netInBuffer.position(0);
         netInBuffer.limit(0);
-        initHandshakeComplete = false;
+        handshakeComplete = false;
         closed = false;
         closing = false;
         //initiate handshake
         sslEngine.beginHandshake();
-        initHandshakeStatus = sslEngine.getHandshakeStatus();
+        handshakeStatus = sslEngine.getHandshakeStatus();
     }
     
     @Override
@@ -146,35 +146,35 @@ public class SecureNioChannel extends Ni
      */
     @Override
     public int handshake(boolean read, boolean write) throws IOException {
-        if ( initHandshakeComplete ) return 0; //we have done our initial 
handshake
+        if ( handshakeComplete ) return 0; //we have done our initial handshake
         
         if (!flush(netOutBuffer)) return SelectionKey.OP_WRITE; //we still 
have data to write
         
         SSLEngineResult handshake = null;
         
-        while (!initHandshakeComplete) {
-            switch ( initHandshakeStatus ) {
+        while (!handshakeComplete) {
+            switch ( handshakeStatus ) {
                 case NOT_HANDSHAKING: {
                     //should never happen
                     throw new IOException("NOT_HANDSHAKING during handshake");
                 }
                 case FINISHED: {
                     //we are complete if we have delivered the last package
-                    initHandshakeComplete = !netOutBuffer.hasRemaining();
+                    handshakeComplete = !netOutBuffer.hasRemaining();
                     //return 0 if we are complete, otherwise we still have 
data to write
-                    return initHandshakeComplete?0:SelectionKey.OP_WRITE; 
+                    return handshakeComplete?0:SelectionKey.OP_WRITE; 
                 }
                 case NEED_WRAP: {
                     //perform the wrap function
                     handshake = handshakeWrap(write);
                     if ( handshake.getStatus() == Status.OK ){
-                        if (initHandshakeStatus == HandshakeStatus.NEED_TASK) 
-                            initHandshakeStatus = tasks();
+                        if (handshakeStatus == HandshakeStatus.NEED_TASK) 
+                            handshakeStatus = tasks();
                     } else {
                         //wrap should always work with our buffers
                         throw new IOException("Unexpected status:" + 
handshake.getStatus() + " during handshake WRAP.");
                     }
-                    if ( initHandshakeStatus != HandshakeStatus.NEED_UNWRAP || 
(!flush(netOutBuffer)) ) {
+                    if ( handshakeStatus != HandshakeStatus.NEED_UNWRAP || 
(!flush(netOutBuffer)) ) {
                         //should actually return OP_READ if we have NEED_UNWRAP
                         return SelectionKey.OP_WRITE;
                     }
@@ -185,26 +185,26 @@ public class SecureNioChannel extends Ni
                     //perform the unwrap function
                     handshake = handshakeUnwrap(read);
                     if ( handshake.getStatus() == Status.OK ) {
-                        if (initHandshakeStatus == HandshakeStatus.NEED_TASK) 
-                            initHandshakeStatus = tasks();
+                        if (handshakeStatus == HandshakeStatus.NEED_TASK) 
+                            handshakeStatus = tasks();
                     } else if ( handshake.getStatus() == 
Status.BUFFER_UNDERFLOW ){
                         //read more data, reregister for OP_READ
                         return SelectionKey.OP_READ;
                     } else {
-                        throw new IOException("Invalid handshake 
status:"+initHandshakeStatus+" during handshake UNWRAP.");
+                        throw new IOException("Invalid handshake 
status:"+handshakeStatus+" during handshake UNWRAP.");
                     }//switch
                     break;
                 }
                 case NEED_TASK: {
-                    initHandshakeStatus = tasks();
+                    handshakeStatus = tasks();
                     break;
                 }
-                default: throw new IllegalStateException("Invalid handshake 
status:"+initHandshakeStatus);
+                default: throw new IllegalStateException("Invalid handshake 
status:"+handshakeStatus);
             }//switch
         }//while      
         //return 0 if we are complete, otherwise reregister for any activity 
that 
         //would cause this method to be called again.
-        return 
initHandshakeComplete?0:(SelectionKey.OP_WRITE|SelectionKey.OP_READ);
+        return 
handshakeComplete?0:(SelectionKey.OP_WRITE|SelectionKey.OP_READ);
     }
     
     /**
@@ -234,7 +234,7 @@ public class SecureNioChannel extends Ni
         //prepare the results to be written
         netOutBuffer.flip();
         //set the status
-        initHandshakeStatus = result.getHandshakeStatus();
+        handshakeStatus = result.getHandshakeStatus();
         //optimization, if we do have a writable channel, write it now
         if ( doWrite ) flush(netOutBuffer);
         return result;
@@ -268,19 +268,42 @@ public class SecureNioChannel extends Ni
             //compact the buffer, this is an optional method, wonder what 
would happen if we didn't
             netInBuffer.compact();
             //read in the status
-            initHandshakeStatus = result.getHandshakeStatus();
+            handshakeStatus = result.getHandshakeStatus();
             if ( result.getStatus() == SSLEngineResult.Status.OK &&
                  result.getHandshakeStatus() == HandshakeStatus.NEED_TASK ) {
                 //execute tasks if we need to
-                initHandshakeStatus = tasks();
+                handshakeStatus = tasks();
             }
             //perform another unwrap?
             cont = result.getStatus() == SSLEngineResult.Status.OK &&
-                   initHandshakeStatus == HandshakeStatus.NEED_UNWRAP;
+                   handshakeStatus == HandshakeStatus.NEED_UNWRAP;
         }while ( cont );
         return result;
     }
     
+    public void rehandshake() throws IOException {
+        int readBufLimit = getBufHandler().getReadBuffer().limit();
+        try {
+            // Expand read buffer to maximum to allow handshaking to take place
+            getBufHandler().getReadBuffer().limit(
+                    getBufHandler().getReadBuffer().capacity());
+            sslEngine.getSession().invalidate();
+            sslEngine.beginHandshake();
+            handshakeComplete = false;
+            handshakeStatus = sslEngine.getHandshakeStatus();
+            while (!handshakeComplete) {
+                handshake(true, true);
+                if (handshakeStatus == HandshakeStatus.NEED_UNWRAP)  {
+                    handshakeUnwrap(true);
+                }
+            }
+        } finally {
+            // Restore the pre-handshak value
+            getBufHandler().getReadBuffer().limit(readBufLimit);
+        }
+    }
+
+
     /**
      * Sends a SSL close message, will not physically close the connection 
here.<br>
      * To close the connection, you could do something like
@@ -353,7 +376,7 @@ public class SecureNioChannel extends Ni
         //are we in the middle of closing or closed?
         if ( closing || closed) return -1;
         //did we finish our handshake?
-        if (!initHandshakeComplete) throw new IllegalStateException("Handshake 
incomplete, you must complete handshake before reading data.");
+        if (!handshakeComplete) throw new IllegalStateException("Handshake 
incomplete, you must complete handshake before reading data.");
 
         //read from the network
         int netread = sc.read(netInBuffer);
@@ -474,8 +497,8 @@ public class SecureNioChannel extends Ni
     }
 
     @Override
-    public boolean isInitHandshakeComplete() {
-        return initHandshakeComplete;
+    public boolean isHandshakeComplete() {
+        return handshakeComplete;
     }
 
     @Override

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1074675&r1=1074674&r2=1074675&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Fri Feb 25 19:19:13 2011
@@ -151,6 +151,10 @@
   </subsection>
   <subsection name="Coyote">
     <changelog>
+      <add>
+        <bug>49284</bug>: Add SSL re-negotiation support to the HTTP NIO
+        connector. (markt)
+      </add>
       <fix>
         <bug>50780</bug>: Fix memory leak in APR implementation of AJP
         connector introduced by the refactoring for <bug>49884</bug>. (markt) 



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to