1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-08 15:02:10 +03:00

Axe out SSL_CONSERVATIVE stuff which for Apache 1.3 did I/O data

pre-sucking on POST requests and I/O re-injection in case of SSL
renegotiations. This all either cannot be solved any longer or at least
has to be implemented totally different through I/O layering/filtering.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@89017 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Ralf S. Engelschall
2001-05-05 16:23:00 +00:00
parent b8998af6bd
commit d3cf43347b
4 changed files with 61 additions and 235 deletions

View File

@@ -145,6 +145,9 @@
o The complete EAPI-based SSL_VENDOR stuff was removed.
o The complete EAPI-based SSL_COMPAT stuff was removed.
o The <IfDefine> variable MOD_SSL is no longer provided automatically
o The complete SSL_CONSERVATIVE stuff was removed, i.e.,
SSL renegotiations in combination with POST request are not supported
unless the problem is solved again, but this time through layered I/O.
MAJOR CHANGES

View File

@@ -778,9 +778,6 @@ char *ssl_var_lookup(pool *, server_rec *, conn_rec *, request_rec *, cha
void ssl_io_register(void);
void ssl_io_unregister(void);
long ssl_io_data_cb(BIO *, int, const char *, int, long, long);
#ifndef SSL_CONSERVATIVE
void ssl_io_suck(request_rec *, SSL *);
#endif
/* PRNG */
int ssl_rand_seed(server_rec *, pool *, ssl_rsctx_t, char *);

View File

@@ -64,229 +64,6 @@
#if 0 /* XXX */
/* _________________________________________________________________
**
** I/O Request Body Sucking and Re-Injection
** _________________________________________________________________
*/
#ifndef SSL_CONSERVATIVE
/*
* Background:
*
* 1. When the client sends a HTTP/HTTPS request, Apache's core code
* reads only the request line ("METHOD /path HTTP/x.y") and the
* attached MIME headers ("Foo: bar") up to the terminating line ("CR
* LF"). An attached request body (for instance the data of a POST
* method) is _NOT_ read. Instead it is read by mod_cgi's content
* handler and directly passed to the CGI script.
*
* 2. mod_ssl supports per-directory re-configuration of SSL parameters.
* This is implemented by performing an SSL renegotiation of the
* re-configured parameters after the request is read, but before the
* response is sent. In more detail: the renegotiation happens after the
* request line and MIME headers were read, but _before_ the attached
* request body is read. The reason simply is that in the HTTP protocol
* usually there is no acknowledgment step between the headers and the
* body (there is the 100-continue feature and the chunking facility
* only), so Apache has no API hook for this step.
*
* 3. the problem now occurs when the client sends a POST request for
* URL /foo via HTTPS the server and the server has SSL parameters
* re-configured on a per-URL basis for /foo. Then mod_ssl has to
* perform an SSL renegotiation after the request was read and before
* the response is sent. But the problem is the pending POST body data
* in the receive buffer of SSL (which Apache still has not read - it's
* pending until mod_cgi sucks it in). When mod_ssl now tries to perform
* the renegotiation the pending data leads to an I/O error.
*
* Solution Idea:
*
* There are only two solutions: Either to simply state that POST
* requests to URLs with SSL re-configurations are not allowed, or to
* renegotiate really after the _complete_ request (i.e. including
* the POST body) was read. Obviously the latter would be preferred,
* but it cannot be done easily inside Apache, because as already
* mentioned, there is no API step between the body reading and the body
* processing. And even when we mod_ssl would hook directly into the
* loop of mod_cgi, we wouldn't solve the problem for other handlers, of
* course. So the only general solution is to suck in the pending data
* of the request body from the OpenSSL BIO into the Apache BUFF. Then
* the renegotiation can be done and after this step Apache can proceed
* processing the request as before.
*
* Solution Implementation:
*
* We cannot simply suck in the data via an SSL_read-based loop because of
* HTTP chunking. Instead we _have_ to use the Apache API for this step which
* is aware of HTTP chunking. So the trick is to suck in the pending request
* data via the Apache API (which uses Apache's BUFF code and in the
* background mod_ssl's I/O glue code) and re-inject it later into the Apache
* BUFF code again. This way the data flows twice through the Apache BUFF, of
* course. But this way the solution doesn't depend on any Apache specifics
* and is fully transparent to Apache modules.
*/
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: actually we cannot really expand the buffer
here, because Apache's pool system doesn't support expanding chunks
of memory. Instead we have to either reuse processed data or
allocate a new chunk of memory in advance if we really need more
memory. */
int newlen;
char *newptr;
if (( (ss->pendptr - ss->bufptr)
+ ((ss->bufptr + ss->buflen) - (ss->pendptr + ss->pendlen)) ) >= len) {
/* make memory available by reusing already processed data */
memmove(ss->bufptr, ss->pendptr, ss->pendlen);
ss->pendptr = ss->bufptr;
}
else {
/* too bad, we have to allocate a new larger buffer */
newlen = (ss->buflen * 2) + len;
newptr = ap_palloc(r->pool, newlen);
ss->bufptr = newptr;
ss->buflen = newlen;
memcpy(ss->bufptr, ss->pendptr, ss->pendlen);
ss->pendptr = ss->bufptr;
}
}
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 knows 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 = NULL;
int rv;
actx = (ap_ctx *)SSL_get_app_data2(ssl);
if (actx != NULL)
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_CONSERVATIVE */
/* _________________________________________________________________
**
** I/O Hooks

View File

@@ -857,19 +857,71 @@ int ssl_hook_Access(request_rec *r)
}
#endif /* SSL_EXPERIMENTAL_PERDIRCA */
#ifdef SSL_CONSERVATIVE
/*
* SSL renegotiations in conjunction with HTTP
* requests using the POST method are not supported.
*
* Background:
*
* 1. When the client sends a HTTP/HTTPS request, Apache's core code
* reads only the request line ("METHOD /path HTTP/x.y") and the
* attached MIME headers ("Foo: bar") up to the terminating line ("CR
* LF"). An attached request body (for instance the data of a POST
* method) is _NOT_ read. Instead it is read by mod_cgi's content
* handler and directly passed to the CGI script.
*
* 2. mod_ssl supports per-directory re-configuration of SSL parameters.
* This is implemented by performing an SSL renegotiation of the
* re-configured parameters after the request is read, but before the
* response is sent. In more detail: the renegotiation happens after the
* request line and MIME headers were read, but _before_ the attached
* request body is read. The reason simply is that in the HTTP protocol
* usually there is no acknowledgment step between the headers and the
* body (there is the 100-continue feature and the chunking facility
* only), so Apache has no API hook for this step.
*
* 3. the problem now occurs when the client sends a POST request for
* URL /foo via HTTPS the server and the server has SSL parameters
* re-configured on a per-URL basis for /foo. Then mod_ssl has to
* perform an SSL renegotiation after the request was read and before
* the response is sent. But the problem is the pending POST body data
* in the receive buffer of SSL (which Apache still has not read - it's
* pending until mod_cgi sucks it in). When mod_ssl now tries to perform
* the renegotiation the pending data leads to an I/O error.
*
* Solution Idea:
*
* There are only two solutions: Either to simply state that POST
* requests to URLs with SSL re-configurations are not allowed, or to
* renegotiate really after the _complete_ request (i.e. including
* the POST body) was read. Obviously the latter would be preferred,
* but it cannot be done easily inside Apache, because as already
* mentioned, there is no API step between the body reading and the body
* processing. And even when we mod_ssl would hook directly into the
* loop of mod_cgi, we wouldn't solve the problem for other handlers, of
* course. So the only general solution is to suck in the pending data
* of the request body from the OpenSSL BIO into the Apache BUFF. Then
* the renegotiation can be done and after this step Apache can proceed
* processing the request as before.
*
* Solution Implementation:
*
* We cannot simply suck in the data via an SSL_read-based loop because of
* HTTP chunking. Instead we _have_ to use the Apache API for this step which
* is aware of HTTP chunking. So the trick is to suck in the pending request
* data via the Apache API (which uses Apache's BUFF code and in the
* background mod_ssl's I/O glue code) and re-inject it later into the Apache
* BUFF code again. This way the data flows twice through the Apache BUFF, of
* course. But this way the solution doesn't depend on any Apache specifics
* and is fully transparent to Apache modules.
*
* !! BUT ALL THIS IS STILL NOT RE-IMPLEMENTED FOR APACHE 2.0 !!
*/
if (renegotiate && r->method_number == M_POST) {
ssl_log(r->server, SSL_LOG_ERROR,
"SSL Re-negotiation in conjunction with POST method not supported!");
ssl_log(r->server, SSL_LOG_INFO,
"You have to compile without -DSSL_CONSERVATIVE to enabled support for this.");
return METHOD_NOT_ALLOWED;
}
#endif /* SSL_CONSERVATIVE */
/*
* now do the renegotiation if anything was actually reconfigured
@@ -922,9 +974,6 @@ int ssl_hook_Access(request_rec *r)
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));
#ifndef SSL_CONSERVATIVE
ssl_io_suck(r, ssl);
#endif
SSL_renegotiate(ssl);
SSL_do_handshake(ssl);
if (SSL_get_state(ssl) != SSL_ST_OK) {