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; + } } }