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]