9c0ce39
--- httpd-2.2.14/modules/ssl/ssl_engine_init.c.cve3555
9c0ce39
+++ httpd-2.2.14/modules/ssl/ssl_engine_init.c
9c0ce39
@@ -501,10 +501,7 @@ static void ssl_init_ctx_callbacks(serve
9c0ce39
     SSL_CTX_set_tmp_rsa_callback(ctx, ssl_callback_TmpRSA);
9c0ce39
     SSL_CTX_set_tmp_dh_callback(ctx,  ssl_callback_TmpDH);
9c0ce39
 
9c0ce39
-    if (s->loglevel >= APLOG_DEBUG) {
9c0ce39
-        /* this callback only logs if LogLevel >= info */
9c0ce39
-        SSL_CTX_set_info_callback(ctx, ssl_callback_LogTracingState);
9c0ce39
-    }
9c0ce39
+    SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
9c0ce39
 }
9c0ce39
 
9c0ce39
 static void ssl_init_ctx_verify(server_rec *s,
9c0ce39
--- httpd-2.2.14/modules/ssl/ssl_engine_io.c.cve3555
9c0ce39
+++ httpd-2.2.14/modules/ssl/ssl_engine_io.c
9c0ce39
@@ -103,6 +103,7 @@ typedef struct {
9c0ce39
     ap_filter_t        *pInputFilter;
9c0ce39
     ap_filter_t        *pOutputFilter;
9c0ce39
     int                nobuffer; /* non-zero to prevent buffering */
9c0ce39
+    SSLConnRec         *config;
9c0ce39
 } ssl_filter_ctx_t;
9c0ce39
 
9c0ce39
 typedef struct {
9c0ce39
@@ -193,7 +194,13 @@ static int bio_filter_out_read(BIO *bio,
9c0ce39
 static int bio_filter_out_write(BIO *bio, const char *in, int inl)
9c0ce39
 {
9c0ce39
     bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
9c0ce39
-
9c0ce39
+    
9c0ce39
+    /* Abort early if the client has initiated a renegotiation. */
9c0ce39
+    if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
9c0ce39
+        outctx->rc = APR_ECONNABORTED;
9c0ce39
+        return -1;
9c0ce39
+    }
9c0ce39
+    
9c0ce39
     /* when handshaking we'll have a small number of bytes.
9c0ce39
      * max size SSL will pass us here is about 16k.
9c0ce39
      * (16413 bytes to be exact)
9c0ce39
@@ -466,6 +473,12 @@ static int bio_filter_in_read(BIO *bio, 
9c0ce39
     if (!in)
9c0ce39
         return 0;
9c0ce39
 
9c0ce39
+    /* Abort early if the client has initiated a renegotiation. */
9c0ce39
+    if (inctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
9c0ce39
+        inctx->rc = APR_ECONNABORTED;
9c0ce39
+        return -1;
9c0ce39
+    }
9c0ce39
+
9c0ce39
     /* XXX: flush here only required for SSLv2;
9c0ce39
      * OpenSSL calls BIO_flush() at the appropriate times for
9c0ce39
      * the other protocols.
9c0ce39
@@ -1724,6 +1737,8 @@ void ssl_io_filter_init(conn_rec *c, SSL
9c0ce39
 
9c0ce39
     filter_ctx = apr_palloc(c->pool, sizeof(ssl_filter_ctx_t));
9c0ce39
 
9c0ce39
+    filter_ctx->config          = myConnConfig(c);
9c0ce39
+
9c0ce39
     filter_ctx->nobuffer        = 0;
9c0ce39
     filter_ctx->pOutputFilter   = ap_add_output_filter(ssl_io_filter,
9c0ce39
                                                    filter_ctx, NULL, c);
9c0ce39
--- httpd-2.2.14/modules/ssl/ssl_engine_kernel.c.cve3555
9c0ce39
+++ httpd-2.2.14/modules/ssl/ssl_engine_kernel.c
9c0ce39
@@ -729,6 +729,10 @@ int ssl_hook_Access(request_rec *r)
9c0ce39
                                        (unsigned char *)&id,
9c0ce39
                                        sizeof(id));
9c0ce39
 
9c0ce39
+            /* Toggle the renegotiation state to allow the new
9c0ce39
+             * handshake to proceed. */
9c0ce39
+            sslconn->reneg_state = RENEG_ALLOW;
9c0ce39
+            
9c0ce39
             SSL_renegotiate(ssl);
9c0ce39
             SSL_do_handshake(ssl);
9c0ce39
 
9c0ce39
@@ -750,6 +754,8 @@ int ssl_hook_Access(request_rec *r)
9c0ce39
             SSL_set_state(ssl, SSL_ST_ACCEPT);
9c0ce39
             SSL_do_handshake(ssl);
9c0ce39
 
9c0ce39
+            sslconn->reneg_state = RENEG_REJECT;
9c0ce39
+
9c0ce39
             if (SSL_get_state(ssl) != SSL_ST_OK) {
9c0ce39
                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
9c0ce39
                               "Re-negotiation handshake failed: "
9c0ce39
@@ -1844,76 +1850,55 @@ void ssl_callback_DelSessionCacheEntry(S
9c0ce39
     return;
9c0ce39
 }
9c0ce39
 
9c0ce39
-/*
9c0ce39
- * This callback function is executed while OpenSSL processes the
9c0ce39
- * SSL handshake and does SSL record layer stuff. We use it to
9c0ce39
- * trace OpenSSL's processing in out SSL logfile.
9c0ce39
- */
9c0ce39
-void ssl_callback_LogTracingState(MODSSL_INFO_CB_ARG_TYPE ssl, int where, int rc)
9c0ce39
+/* Dump debugginfo trace to the log file. */
9c0ce39
+static void log_tracing_state(MODSSL_INFO_CB_ARG_TYPE ssl, conn_rec *c, 
9c0ce39
+                              server_rec *s, int where, int rc)
9c0ce39
 {
9c0ce39
-    conn_rec *c;
9c0ce39
-    server_rec *s;
9c0ce39
-    SSLSrvConfigRec *sc;
9c0ce39
-
9c0ce39
-    /*
9c0ce39
-     * find corresponding server
9c0ce39
-     */
9c0ce39
-    if (!(c = (conn_rec *)SSL_get_app_data((SSL *)ssl))) {
9c0ce39
-        return;
9c0ce39
-    }
9c0ce39
-
9c0ce39
-    s = mySrvFromConn(c);
9c0ce39
-    if (!(sc = mySrvConfig(s))) {
9c0ce39
-        return;
9c0ce39
-    }
9c0ce39
-
9c0ce39
     /*
9c0ce39
      * create the various trace messages
9c0ce39
      */
9c0ce39
-    if (s->loglevel >= APLOG_DEBUG) {
9c0ce39
-        if (where & SSL_CB_HANDSHAKE_START) {
9c0ce39
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
9c0ce39
-                         "%s: Handshake: start", SSL_LIBRARY_NAME);
9c0ce39
-        }
9c0ce39
-        else if (where & SSL_CB_HANDSHAKE_DONE) {
9c0ce39
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
9c0ce39
-                         "%s: Handshake: done", SSL_LIBRARY_NAME);
9c0ce39
-        }
9c0ce39
-        else if (where & SSL_CB_LOOP) {
9c0ce39
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
9c0ce39
-                         "%s: Loop: %s",
9c0ce39
-                         SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
9c0ce39
-        }
9c0ce39
-        else if (where & SSL_CB_READ) {
9c0ce39
+    if (where & SSL_CB_HANDSHAKE_START) {
9c0ce39
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
9c0ce39
+                     "%s: Handshake: start", SSL_LIBRARY_NAME);
9c0ce39
+    }
9c0ce39
+    else if (where & SSL_CB_HANDSHAKE_DONE) {
9c0ce39
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
9c0ce39
+                     "%s: Handshake: done", SSL_LIBRARY_NAME);
9c0ce39
+    }
9c0ce39
+    else if (where & SSL_CB_LOOP) {
9c0ce39
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
9c0ce39
+                     "%s: Loop: %s",
9c0ce39
+                     SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
9c0ce39
+    }
9c0ce39
+    else if (where & SSL_CB_READ) {
9c0ce39
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
9c0ce39
+                     "%s: Read: %s",
9c0ce39
+                     SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
9c0ce39
+    }
9c0ce39
+    else if (where & SSL_CB_WRITE) {
9c0ce39
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
9c0ce39
+                     "%s: Write: %s",
9c0ce39
+                     SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
9c0ce39
+    }
9c0ce39
+    else if (where & SSL_CB_ALERT) {
9c0ce39
+        char *str = (where & SSL_CB_READ) ? "read" : "write";
9c0ce39
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
9c0ce39
+                     "%s: Alert: %s:%s:%s",
9c0ce39
+                     SSL_LIBRARY_NAME, str,
9c0ce39
+                     SSL_alert_type_string_long(rc),
9c0ce39
+                     SSL_alert_desc_string_long(rc));
9c0ce39
+    }
9c0ce39
+    else if (where & SSL_CB_EXIT) {
9c0ce39
+        if (rc == 0) {
9c0ce39
             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
9c0ce39
-                         "%s: Read: %s",
9c0ce39
+                         "%s: Exit: failed in %s",
9c0ce39
                          SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
9c0ce39
         }
9c0ce39
-        else if (where & SSL_CB_WRITE) {
9c0ce39
+        else if (rc < 0) {
9c0ce39
             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
9c0ce39
-                         "%s: Write: %s",
9c0ce39
+                         "%s: Exit: error in %s",
9c0ce39
                          SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
9c0ce39
         }
9c0ce39
-        else if (where & SSL_CB_ALERT) {
9c0ce39
-            char *str = (where & SSL_CB_READ) ? "read" : "write";
9c0ce39
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
9c0ce39
-                         "%s: Alert: %s:%s:%s",
9c0ce39
-                         SSL_LIBRARY_NAME, str,
9c0ce39
-                         SSL_alert_type_string_long(rc),
9c0ce39
-                         SSL_alert_desc_string_long(rc));
9c0ce39
-        }
9c0ce39
-        else if (where & SSL_CB_EXIT) {
9c0ce39
-            if (rc == 0) {
9c0ce39
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
9c0ce39
-                             "%s: Exit: failed in %s",
9c0ce39
-                             SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
9c0ce39
-            }
9c0ce39
-            else if (rc < 0) {
9c0ce39
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
9c0ce39
-                             "%s: Exit: error in %s",
9c0ce39
-                             SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
9c0ce39
-            }
9c0ce39
-        }
9c0ce39
     }
9c0ce39
 
9c0ce39
     /*
9c0ce39
@@ -1933,6 +1918,52 @@ void ssl_callback_LogTracingState(MODSSL
9c0ce39
     }
9c0ce39
 }
9c0ce39
 
9c0ce39
+/*
9c0ce39
+ * This callback function is executed while OpenSSL processes the SSL
9c0ce39
+ * handshake and does SSL record layer stuff.  It's used to trap
9c0ce39
+ * client-initiated renegotiations, and for dumping everything to the
9c0ce39
+ * log.
9c0ce39
+ */
9c0ce39
+void ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE ssl, int where, int rc)
9c0ce39
+{
9c0ce39
+    conn_rec *c;
9c0ce39
+    server_rec *s;
9c0ce39
+    SSLConnRec *scr;
9c0ce39
+
9c0ce39
+    /* Retrieve the conn_rec and the associated SSLConnRec. */
9c0ce39
+    if ((c = (conn_rec *)SSL_get_app_data((SSL *)ssl)) == NULL) {
9c0ce39
+        return;
9c0ce39
+    }
9c0ce39
+
9c0ce39
+    if ((scr = myConnConfig(c)) == NULL) {
9c0ce39
+        return;
9c0ce39
+    }
9c0ce39
+
9c0ce39
+    /* If the reneg state is to reject renegotiations, check the SSL
9c0ce39
+     * state machine and move to ABORT if a Client Hello is being
9c0ce39
+     * read. */
9c0ce39
+    if ((where & SSL_CB_ACCEPT_LOOP) && scr->reneg_state == RENEG_REJECT) {
9c0ce39
+        int state = SSL_get_state(ssl);
9c0ce39
+        
9c0ce39
+        if (state == SSL3_ST_SR_CLNT_HELLO_A 
9c0ce39
+            || state == SSL23_ST_SR_CLNT_HELLO_A) {
9c0ce39
+            scr->reneg_state = RENEG_ABORT;
9c0ce39
+            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
9c0ce39
+                          "rejecting client initiated renegotiation");
9c0ce39
+        }
9c0ce39
+    }
9c0ce39
+    /* If the first handshake is complete, change state to reject any
9c0ce39
+     * subsequent client-initated renegotiation. */
9c0ce39
+    else if ((where & SSL_CB_HANDSHAKE_DONE) && scr->reneg_state == RENEG_INIT) {
9c0ce39
+        scr->reneg_state = RENEG_REJECT;
9c0ce39
+    }
9c0ce39
+
9c0ce39
+    s = mySrvFromConn(c);
9c0ce39
+    if (s && s->loglevel >= APLOG_DEBUG) {
9c0ce39
+        log_tracing_state(ssl, c, s, where, rc);
9c0ce39
+    }
9c0ce39
+}
9c0ce39
+
9c0ce39
 #ifndef OPENSSL_NO_TLSEXT
9c0ce39
 /*
9c0ce39
  * This callback function is executed when OpenSSL encounters an extended
9c0ce39
--- httpd-2.2.14/modules/ssl/ssl_private.h.cve3555
9c0ce39
+++ httpd-2.2.14/modules/ssl/ssl_private.h
9c0ce39
@@ -356,6 +356,20 @@ typedef struct {
9c0ce39
     int is_proxy;
9c0ce39
     int disabled;
9c0ce39
     int non_ssl_request;
9c0ce39
+
9c0ce39
+    /* Track the handshake/renegotiation state for the connection so
9c0ce39
+     * that all client-initiated renegotiations can be rejected, as a
9c0ce39
+     * partial fix for CVE-2009-3555. */
9c0ce39
+    enum { 
9c0ce39
+        RENEG_INIT = 0, /* Before initial handshake */
9c0ce39
+        RENEG_REJECT, /* After initial handshake; any client-initiated
9c0ce39
+                       * renegotiation should be rejected */
9c0ce39
+        RENEG_ALLOW, /* A server-initated renegotiation is taking
9c0ce39
+                      * place (as dictated by configuration) */
9c0ce39
+        RENEG_ABORT /* Renegotiation initiated by client, abort the
9c0ce39
+                     * connection */
9c0ce39
+    } reneg_state;
9c0ce39
+    
9c0ce39
     server_rec *server;
9c0ce39
 } SSLConnRec;
9c0ce39
 
9c0ce39
@@ -574,7 +588,7 @@ int          ssl_callback_proxy_cert(SSL
9c0ce39
 int          ssl_callback_NewSessionCacheEntry(SSL *, SSL_SESSION *);
9c0ce39
 SSL_SESSION *ssl_callback_GetSessionCacheEntry(SSL *, unsigned char *, int, int *);
9c0ce39
 void         ssl_callback_DelSessionCacheEntry(SSL_CTX *, SSL_SESSION *);
9c0ce39
-void         ssl_callback_LogTracingState(MODSSL_INFO_CB_ARG_TYPE, int, int);
9c0ce39
+void         ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE, int, int);
9c0ce39
 #ifndef OPENSSL_NO_TLSEXT
9c0ce39
 int          ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *);
9c0ce39
 #endif