On Thu, Nov 05, 2009 at 09:31:00PM +0000, Joe Orton wrote:
> * we can detect in mod_ssl when the client is renegotiating by using the 
> callback installed using SSL_CTX_set_info_callback(), in conjunction 
> with suitable flags in the SSLConnRec to detect the cases where this is 
> either a server-initiated renegotiation or the initial handshake on the 
> connection.

Here is a very rough first hack (for discussion/testing purposes only!):

Index: ssl_private.h
===================================================================
--- ssl_private.h       (revision 832979)
+++ ssl_private.h       (working copy)
@@ -335,6 +335,14 @@
     int is_proxy;
     int disabled;
     int non_ssl_request;
+    enum { 
+        RENEG_INIT = 0, /* before initial handshake. */
+        RENEG_ALLOW, /* a server-initated renegotiation is taking place */
+        RENEG_REJECT, /* after initial handshake; any client-initiated
+                       * renegotiation should be rejected. */
+        RENEG_ABORT /* renegotiation initiated by client, abort abort */
+    } reneg_state;
+    
     server_rec *server;
 } SSLConnRec;
 
Index: ssl_engine_init.c
===================================================================
--- ssl_engine_init.c   (revision 832979)
+++ ssl_engine_init.c   (working copy)
@@ -520,7 +520,7 @@
     SSL_CTX_set_tmp_rsa_callback(ctx, ssl_callback_TmpRSA);
     SSL_CTX_set_tmp_dh_callback(ctx,  ssl_callback_TmpDH);
 
-    if (s->loglevel >= APLOG_DEBUG) {
+    if (1 || s->loglevel >= APLOG_DEBUG) {
         /* this callback only logs if LogLevel >= info */
         SSL_CTX_set_info_callback(ctx, ssl_callback_LogTracingState);
     }
Index: ssl_engine_io.c
===================================================================
--- ssl_engine_io.c     (revision 832979)
+++ ssl_engine_io.c     (working copy)
@@ -190,10 +190,27 @@
     return -1;
 }
 
+static int conn_in_reneg(conn_rec *c)
+{
+    SSLConnRec *scr = myConnConfig(c);
+    
+    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+                  "reneg_state == %s", scr->reneg_state == RENEG_INIT ? "INIT" 
:
+                  scr->reneg_state == RENEG_REJECT ? "REJECT" :
+                  scr->reneg_state == RENEG_ALLOW ? "ALLOW" : "ABORT");
+
+    return scr->reneg_state == RENEG_ABORT;
+}
+
 static int bio_filter_out_write(BIO *bio, const char *in, int inl)
 {
     bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
-
+    
+    if (conn_in_reneg(outctx->c)) {
+        outctx->rc = APR_EACCES;
+        return -1;
+    }
+    
     /* when handshaking we'll have a small number of bytes.
      * max size SSL will pass us here is about 16k.
      * (16413 bytes to be exact)
@@ -476,6 +493,11 @@
     if (!in)
         return 0;
 
+    if (conn_in_reneg(inctx->f->c)) {
+        inctx->rc = APR_EACCES;
+        return -1;
+    }
+
     /* In theory, OpenSSL should flush as necessary, but it is known
      * not to do so correctly in some cases; see PR 46952.
      *
Index: ssl_engine_kernel.c
===================================================================
--- ssl_engine_kernel.c (revision 832979)
+++ ssl_engine_kernel.c (working copy)
@@ -733,6 +733,8 @@
                                        (unsigned char *)&id,
                                        sizeof(id));
 
+            sslconn->reneg_state = RENEG_ALLOW;
+            
             SSL_renegotiate(ssl);
             SSL_do_handshake(ssl);
 
@@ -754,6 +756,8 @@
             SSL_set_state(ssl, SSL_ST_ACCEPT);
             SSL_do_handshake(ssl);
 
+            sslconn->reneg_state = RENEG_REJECT;
+
             if (SSL_get_state(ssl) != SSL_ST_OK) {
                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                               "Re-negotiation handshake failed: "
@@ -1824,7 +1828,8 @@
     conn_rec *c;
     server_rec *s;
     SSLSrvConfigRec *sc;
-
+    SSLConnRec *scr;
+    
     /*
      * find corresponding server
      */
@@ -1837,6 +1842,18 @@
         return;
     }
 
+    scr = myConnConfig(c);
+
+    {
+        int state = SSL_get_state(ssl);
+        
+        if (scr->reneg_state == RENEG_REJECT
+            && (state == SSL3_ST_SR_CLNT_HELLO_A
+                || state == SSL23_ST_SR_CLNT_HELLO_A)) {
+            scr->reneg_state = RENEG_ABORT;
+        }
+    }
+    
     /*
      * create the various trace messages
      */
@@ -1900,6 +1917,9 @@
                      ssl_var_lookup(NULL, s, c, NULL, "SSL_CIPHER"),
                      ssl_var_lookup(NULL, s, c, NULL, "SSL_CIPHER_USEKEYSIZE"),
                      ssl_var_lookup(NULL, s, c, NULL, 
"SSL_CIPHER_ALGKEYSIZE"));
+        if (scr->reneg_state == RENEG_INIT) {
+            scr->reneg_state = RENEG_REJECT;
+        }
     }
 }
 

Reply via email to