Ok, here is take 3 and my cleaned up and finally proposed patch which solves
the POST problems by pre-sucking pending input data from the SSL/TLS I/O layer
and re-injecting them after the renegotiation phase into the Apache I/O layer.

Here is an example:

[...]
[26/Jul/1999 17:52:11] [info]  Connection: Client IP: 141.1.129.1, Protocol: SSLv3, 
Cipher: RC4-MD5 (128/128 bits)
[26/Jul/1999 17:52:11] [info]  Initial (No.1) HTTPS request received for child 0 
(server en1.engelschall.com:8443)
[26/Jul/1999 17:52:11] [trace] Reconfigured cipher suite will force renegotiation
[26/Jul/1999 17:52:11] [info]  Requesting connection re-negotiation
[26/Jul/1999 17:52:11] [trace] Performing full renegotiation: complete handshake 
protocol
[26/Jul/1999 17:52:11] [trace] OpenSSL: Handshake: start
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: SSL renegotiate ciphers
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: SSLv3 write hello request A
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: SSLv3 flush data
[26/Jul/1999 17:52:11] [info]  Awaiting re-negotiation handshake
[26/Jul/1999 17:52:11] [trace] OpenSSL: Handshake: start
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: before accept initialization
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: SSLv3 read client hello A
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: SSLv3 write server hello A
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: SSLv3 write certificate A
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: SSLv3 write key exchange A
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: SSLv3 write server done A
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: SSLv3 flush data
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: SSLv3 read client key exchange A
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: SSLv3 read finished A
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: SSLv3 write change cipher spec A
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: SSLv3 write finished A
[26/Jul/1999 17:52:11] [trace] OpenSSL: Loop: SSLv3 flush data
[26/Jul/1999 17:52:11] [trace] Inter-Process Session Cache: request=SET status=OK 
id=4EF9E64F1BACBE87348D204B8881ED42CCFA839E5F7343F86C76F9F0BCF7987E timeout=300s 
(session caching)
[26/Jul/1999 17:52:11] [trace] OpenSSL: Handshake: done
[26/Jul/1999 17:52:11] [info]  Connection: Client IP: 141.1.129.1, Protocol: SSLv3, 
Cipher: EXP-RC2-CBC-MD5 (40/128 bits)
[26/Jul/1999 17:52:11] [trace] OpenSSL: Write: SSL negotiation finished successfully
[26/Jul/1999 17:52:11] [info]  Connection to child 0 closed with standard shutdown 
(server en1.engelschall.com:8443)
[26/Jul/1999 17:52:14] [info]  Connection to child 0 established (server 
en1.engelschall.com:8443)
[26/Jul/1999 17:52:14] [trace] Seeding PRNG with 1032 bytes of entropy
[26/Jul/1999 17:52:14] [trace] OpenSSL: Handshake: start
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: before/accept initialization
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 read client hello A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 write server hello A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 write change cipher spec A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 write finished A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 flush data
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 read finished A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Handshake: done

This a request to the demo HTML form over HTTPS but still without any POST
data. Now I entered some data into the form field and pressed the SUBMIT
button:

[26/Jul/1999 17:52:14] [info]  Connection: Client IP: 141.1.129.1, Protocol: SSLv3, 
Cipher: EXP-RC2-CBC-MD5 (40/128 bits)
[26/Jul/1999 17:52:14] [info]  Initial (No.1) HTTPS request received for child 0 
(server en1.engelschall.com:8443)
[26/Jul/1999 17:52:14] [trace] Reconfigured cipher suite will force renegotiation
[26/Jul/1999 17:52:14] [info]  Requesting connection re-negotiation
[26/Jul/1999 17:52:14] [trace] Performing full renegotiation: complete handshake 
protocol
[26/Jul/1999 17:52:14] [trace] I/O: sucked 12 bytes of input data from SSL/TLS I/O 
layer for delayed injection into Apache I/O layer

Here you can see that before the handshake is performed the POST data is
sucked from the SSL I/O layer into mod_ssl's buffer. Then the renegotiation is
done:

[26/Jul/1999 17:52:14] [trace] OpenSSL: Handshake: start
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSL renegotiate ciphers
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 write hello request A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 flush data
[26/Jul/1999 17:52:14] [info]  Awaiting re-negotiation handshake
[26/Jul/1999 17:52:14] [trace] OpenSSL: Handshake: start
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: before accept initialization
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 read client hello A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 write server hello A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 write certificate A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 write key exchange A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 write server done A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 flush data
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 read client key exchange A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 read finished A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 write change cipher spec A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 write finished A
[26/Jul/1999 17:52:14] [trace] OpenSSL: Loop: SSLv3 flush data
[26/Jul/1999 17:52:14] [trace] Inter-Process Session Cache: request=SET status=OK 
id=C1CAB096DAEDC54E143EAA7BA03FDAB2D049090D8D88454C4316FB230EAB6727 timeout=300s 
(session caching)
[26/Jul/1999 17:52:14] [trace] OpenSSL: Handshake: done
[26/Jul/1999 17:52:14] [info]  Connection: Client IP: 141.1.129.1, Protocol: SSLv3, 
Cipher: EXP-RC2-CBC-MD5 (40/128 bits)
[26/Jul/1999 17:52:14] [trace] I/O: injecting 12 bytes of pre-sucked data into Apache 
I/O layer
[26/Jul/1999 17:52:14] [trace] OpenSSL: Write: SSL negotiation finished successfully
[26/Jul/1999 17:52:14] [info]  Connection to child 0 closed with standard shutdown 
(server en1.engelschall.com:8443)

Finally mod_cgi is processing my CGI script and wants to the the POST request
body. As you can see the data is now served from mod_ssl's buffer instead
(again) from the SSL I/O layer.

Please test the appended patch and give feedback.

                                       Ralf S. Engelschall
                                       [EMAIL PROTECTED]
                                       www.engelschall.com

Index: include/buff.h
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/include/buff.h,v
retrieving revision 1.6
diff -u -r1.6 buff.h
--- include/buff.h      1999/01/10 11:07:22     1.6
+++ include/buff.h      1999/07/26 15:27:40
@@ -182,6 +182,8 @@
 
 #ifndef CHARSET_EBCDIC
 
+#define ap_bpeekc(fb) ( ((fb)->incnt == 0) ? EOF : *((fb)->inptr) )
+
 #define ap_bgetc(fb)   ( ((fb)->incnt == 0) ? ap_bfilbuf(fb) : \
                    ((fb)->incnt--, *((fb)->inptr++)) )
 
Index: modules/ssl/mod_ssl.h
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/mod_ssl.h,v
retrieving revision 1.108
diff -u -r1.108 mod_ssl.h
--- modules/ssl/mod_ssl.h       1999/07/25 11:24:13     1.108
+++ modules/ssl/mod_ssl.h       1999/07/26 11:30:25
@@ -715,6 +715,7 @@
 void         ssl_io_register(void);
 void         ssl_io_unregister(void);
 long         ssl_io_data_cb(BIO *, int, const char *, int, long, long);
+void         ssl_io_suck(request_rec *, SSL *);
 
 /*  PRNG  */
 int          ssl_rand_seed(server_rec *, pool *, ssl_rsctx_t);
Index: modules/ssl/ssl_engine_io.c
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/ssl_engine_io.c,v
retrieving revision 1.23
diff -u -r1.23 ssl_engine_io.c
--- modules/ssl/ssl_engine_io.c 1999/05/04 07:58:53     1.23
+++ modules/ssl/ssl_engine_io.c 1999/07/26 15:51:24
@@ -64,6 +64,159 @@
                                             -- Unknown    */
 #include "mod_ssl.h"
 
+/*  _________________________________________________________________
+**
+**  I/O Request Body Sucking and Re-Injection
+**  _________________________________________________________________
+*/
+
+#ifdef SSL_EXPERIMENTAL
+
+struct ssl_io_suck_st {
+    BOOL  active;
+    char *bufptr;
+    int   buflen;
+    char *pendptr;
+    int   pendlen;
+};
+
+/* prepare request_rec structure for input sucking */
+static void ssl_io_suck_start(request_rec *r)
+{
+    struct ssl_io_suck_st *ss;
+
+    ss = ap_ctx_get(r->ctx, "ssl::io::suck");
+    if (ss == NULL) {
+        ss = ap_palloc(r->pool, sizeof(struct ssl_io_suck_st));
+        ap_ctx_set(r->ctx, "ssl::io::suck", ss);
+        ss->buflen  = 8192;
+        ss->bufptr  = ap_palloc(r->pool, ss->buflen);
+    }
+    ss->pendptr = ss->bufptr;
+    ss->pendlen = 0;
+    ss->active = FALSE;
+    return;
+}
+
+/* record a sucked input chunk */
+static void ssl_io_suck_record(request_rec *r, char *buf, int len)
+{
+    struct ssl_io_suck_st *ss;
+    
+    if ((ss = ap_ctx_get(r->ctx, "ssl::io::suck")) == NULL)
+        return;
+    if (((ss->bufptr+ss->buflen)-(ss->pendptr+ss->pendlen)) < len) {
+        /* "expand" buffer */
+        int newlen;
+        char *newptr;
+        if (ss->buflen < len)
+            newlen = ss->buflen * 2;
+        else
+            newlen = ss->buflen + len;
+        newptr = ap_palloc(r->pool, newlen);
+        memcpy(newptr, ss->bufptr, ss->buflen);
+        ss->bufptr = newptr;
+        ss->buflen = newlen;
+    }
+    memcpy(ss->pendptr+ss->pendlen, buf, len);
+    ss->pendlen += len;
+    return;
+}
+
+/* finish request_rec after input sucking */
+static void ssl_io_suck_end(request_rec *r)
+{
+    struct ssl_io_suck_st *ss;
+    
+    if ((ss = ap_ctx_get(r->ctx, "ssl::io::suck")) == NULL)
+        return;
+    ss->active = TRUE;
+    r->read_body    = REQUEST_NO_BODY;
+    r->read_length  = 0;
+    r->read_chunked = 0;
+    r->remaining    = 0;
+    ap_bsetflag(r->connection->client, B_CHUNK, 0);
+    return;
+}
+
+void ssl_io_suck(request_rec *r, SSL *ssl)
+{
+    int rc;
+    int len;
+    char *buf;
+    int buflen;
+    char c;
+    int sucked;
+
+    if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) == OK) {
+        if (ap_should_client_block(r)) {
+
+            /* read client request block through Apache API */
+            buflen = HUGE_STRING_LEN;
+            buf = ap_palloc(r->pool, buflen);
+            ap_hard_timeout("SSL I/O request body pre-sucking", r);
+            sucked = 0;
+            ssl_io_suck_start(r);
+            while ((len = ap_get_client_block(r, buf, buflen)) > 0) {
+                ssl_io_suck_record(r, buf, len);
+                sucked += len;
+            }
+            ssl_io_suck_end(r);
+            ap_kill_timeout(r);
+
+            /* suck trailing data (usually CR LF) which 
+               is still in the Apache BUFF layer */
+            while (ap_bpeekc(r->connection->client) != EOF) {
+                c = ap_bgetc(r->connection->client);
+                ssl_io_suck_record(r, &c, 1);
+                sucked++;
+            }
+
+            ssl_log(r->server, SSL_LOG_TRACE, 
+                    "I/O: sucked %d bytes of input data from SSL/TLS I/O layer "
+                    "for delayed injection into Apache I/O layer", sucked);
+        }
+    }
+    return;
+}
+    
+/* the SSL_read replacement routine which known about the suck buffer */
+static int ssl_io_suck_read(SSL *ssl, char *buf, int len)
+{
+    ap_ctx *actx;
+    struct ssl_io_suck_st *ss;
+    request_rec *r;
+    int rv;
+
+    actx = (ap_ctx *)SSL_get_app_data2(ssl);
+    r    = (request_rec *)ap_ctx_get(actx, "ssl::request_rec");
+
+    rv = -1;
+    if (r != NULL) {
+        ss = ap_ctx_get(r->ctx, "ssl::io::suck");
+        if (ss != NULL) {
+            if (ss->active && ss->pendlen > 0) {
+                /* ok, there is pre-sucked data */
+                len = (ss->pendlen > len ? len : ss->pendlen);
+                memcpy(buf, ss->pendptr, len);
+                ss->pendptr += len;
+                ss->pendlen -= len;
+                ssl_log(r->server, SSL_LOG_TRACE, 
+                        "I/O: injecting %d bytes of pre-sucked data "
+                        "into Apache I/O layer", len);
+                rv = len;
+            }
+        }
+    }
+    if (rv == -1)
+        rv = SSL_read(ssl, buf, len);
+    return rv;
+}
+
+/* override SSL_read in the following code... */
+#define SSL_read ssl_io_suck_read
+
+#endif /* SSL_EXPERIMENTAL */
 
 /*  _________________________________________________________________
 **
Index: modules/ssl/ssl_engine_kernel.c
===================================================================
RCS file: /e/modssl/cvs/mod_ssl/pkg.apache/src/modules/ssl/ssl_engine_kernel.c,v
retrieving revision 1.101
diff -u -r1.101 ssl_engine_kernel.c
--- modules/ssl/ssl_engine_kernel.c     1999/07/26 07:42:35     1.101
+++ modules/ssl/ssl_engine_kernel.c     1999/07/26 11:00:31
@@ -938,6 +938,7 @@
                 SSL_set_session_id_context(ssl, (unsigned char *)&(r->main), 
sizeof(r->main));
             else
                 SSL_set_session_id_context(ssl, (unsigned char *)&r, sizeof(r));
+            ssl_io_suck(r, ssl);
             SSL_renegotiate(ssl);
             SSL_do_handshake(ssl);
             if (SSL_get_state(ssl) != SSL_ST_OK) {
______________________________________________________________________
Apache Interface to OpenSSL (mod_ssl)                   www.modssl.org
User Support Mailing List                      [EMAIL PROTECTED]
Automated List Manager                            [EMAIL PROTECTED]

Reply via email to