Skip to content

Commit 70c61cd

Browse files
author
Ralf S. Engelschall
committed
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
1 parent 8c46d54 commit 70c61cd

4 files changed

Lines changed: 61 additions & 235 deletions

File tree

modules/ssl/README

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@
145145
o The complete EAPI-based SSL_VENDOR stuff was removed.
146146
o The complete EAPI-based SSL_COMPAT stuff was removed.
147147
o The <IfDefine> variable MOD_SSL is no longer provided automatically
148+
o The complete SSL_CONSERVATIVE stuff was removed, i.e.,
149+
SSL renegotiations in combination with POST request are not supported
150+
unless the problem is solved again, but this time through layered I/O.
148151

149152
MAJOR CHANGES
150153

modules/ssl/mod_ssl.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -778,9 +778,6 @@ char *ssl_var_lookup(pool *, server_rec *, conn_rec *, request_rec *, cha
778778
void ssl_io_register(void);
779779
void ssl_io_unregister(void);
780780
long ssl_io_data_cb(BIO *, int, const char *, int, long, long);
781-
#ifndef SSL_CONSERVATIVE
782-
void ssl_io_suck(request_rec *, SSL *);
783-
#endif
784781

785782
/* PRNG */
786783
int ssl_rand_seed(server_rec *, pool *, ssl_rsctx_t, char *);

modules/ssl/ssl_engine_io.c

Lines changed: 0 additions & 223 deletions
Original file line numberDiff line numberDiff line change
@@ -64,229 +64,6 @@
6464

6565
#if 0 /* XXX */
6666

67-
/* _________________________________________________________________
68-
**
69-
** I/O Request Body Sucking and Re-Injection
70-
** _________________________________________________________________
71-
*/
72-
73-
#ifndef SSL_CONSERVATIVE
74-
75-
/*
76-
* Background:
77-
*
78-
* 1. When the client sends a HTTP/HTTPS request, Apache's core code
79-
* reads only the request line ("METHOD /path HTTP/x.y") and the
80-
* attached MIME headers ("Foo: bar") up to the terminating line ("CR
81-
* LF"). An attached request body (for instance the data of a POST
82-
* method) is _NOT_ read. Instead it is read by mod_cgi's content
83-
* handler and directly passed to the CGI script.
84-
*
85-
* 2. mod_ssl supports per-directory re-configuration of SSL parameters.
86-
* This is implemented by performing an SSL renegotiation of the
87-
* re-configured parameters after the request is read, but before the
88-
* response is sent. In more detail: the renegotiation happens after the
89-
* request line and MIME headers were read, but _before_ the attached
90-
* request body is read. The reason simply is that in the HTTP protocol
91-
* usually there is no acknowledgment step between the headers and the
92-
* body (there is the 100-continue feature and the chunking facility
93-
* only), so Apache has no API hook for this step.
94-
*
95-
* 3. the problem now occurs when the client sends a POST request for
96-
* URL /foo via HTTPS the server and the server has SSL parameters
97-
* re-configured on a per-URL basis for /foo. Then mod_ssl has to
98-
* perform an SSL renegotiation after the request was read and before
99-
* the response is sent. But the problem is the pending POST body data
100-
* in the receive buffer of SSL (which Apache still has not read - it's
101-
* pending until mod_cgi sucks it in). When mod_ssl now tries to perform
102-
* the renegotiation the pending data leads to an I/O error.
103-
*
104-
* Solution Idea:
105-
*
106-
* There are only two solutions: Either to simply state that POST
107-
* requests to URLs with SSL re-configurations are not allowed, or to
108-
* renegotiate really after the _complete_ request (i.e. including
109-
* the POST body) was read. Obviously the latter would be preferred,
110-
* but it cannot be done easily inside Apache, because as already
111-
* mentioned, there is no API step between the body reading and the body
112-
* processing. And even when we mod_ssl would hook directly into the
113-
* loop of mod_cgi, we wouldn't solve the problem for other handlers, of
114-
* course. So the only general solution is to suck in the pending data
115-
* of the request body from the OpenSSL BIO into the Apache BUFF. Then
116-
* the renegotiation can be done and after this step Apache can proceed
117-
* processing the request as before.
118-
*
119-
* Solution Implementation:
120-
*
121-
* We cannot simply suck in the data via an SSL_read-based loop because of
122-
* HTTP chunking. Instead we _have_ to use the Apache API for this step which
123-
* is aware of HTTP chunking. So the trick is to suck in the pending request
124-
* data via the Apache API (which uses Apache's BUFF code and in the
125-
* background mod_ssl's I/O glue code) and re-inject it later into the Apache
126-
* BUFF code again. This way the data flows twice through the Apache BUFF, of
127-
* course. But this way the solution doesn't depend on any Apache specifics
128-
* and is fully transparent to Apache modules.
129-
*/
130-
131-
struct ssl_io_suck_st {
132-
BOOL active;
133-
char *bufptr;
134-
int buflen;
135-
char *pendptr;
136-
int pendlen;
137-
};
138-
139-
/* prepare request_rec structure for input sucking */
140-
static void ssl_io_suck_start(request_rec *r)
141-
{
142-
struct ssl_io_suck_st *ss;
143-
144-
ss = ap_ctx_get(r->ctx, "ssl::io::suck");
145-
if (ss == NULL) {
146-
ss = ap_palloc(r->pool, sizeof(struct ssl_io_suck_st));
147-
ap_ctx_set(r->ctx, "ssl::io::suck", ss);
148-
ss->buflen = 8192;
149-
ss->bufptr = ap_palloc(r->pool, ss->buflen);
150-
}
151-
ss->pendptr = ss->bufptr;
152-
ss->pendlen = 0;
153-
ss->active = FALSE;
154-
return;
155-
}
156-
157-
/* record a sucked input chunk */
158-
static void ssl_io_suck_record(request_rec *r, char *buf, int len)
159-
{
160-
struct ssl_io_suck_st *ss;
161-
162-
if ((ss = ap_ctx_get(r->ctx, "ssl::io::suck")) == NULL)
163-
return;
164-
if (((ss->bufptr + ss->buflen) - (ss->pendptr + ss->pendlen)) < len) {
165-
/* "expand" buffer: actually we cannot really expand the buffer
166-
here, because Apache's pool system doesn't support expanding chunks
167-
of memory. Instead we have to either reuse processed data or
168-
allocate a new chunk of memory in advance if we really need more
169-
memory. */
170-
int newlen;
171-
char *newptr;
172-
173-
if (( (ss->pendptr - ss->bufptr)
174-
+ ((ss->bufptr + ss->buflen) - (ss->pendptr + ss->pendlen)) ) >= len) {
175-
/* make memory available by reusing already processed data */
176-
memmove(ss->bufptr, ss->pendptr, ss->pendlen);
177-
ss->pendptr = ss->bufptr;
178-
}
179-
else {
180-
/* too bad, we have to allocate a new larger buffer */
181-
newlen = (ss->buflen * 2) + len;
182-
newptr = ap_palloc(r->pool, newlen);
183-
ss->bufptr = newptr;
184-
ss->buflen = newlen;
185-
memcpy(ss->bufptr, ss->pendptr, ss->pendlen);
186-
ss->pendptr = ss->bufptr;
187-
}
188-
}
189-
memcpy(ss->pendptr+ss->pendlen, buf, len);
190-
ss->pendlen += len;
191-
return;
192-
}
193-
194-
/* finish request_rec after input sucking */
195-
static void ssl_io_suck_end(request_rec *r)
196-
{
197-
struct ssl_io_suck_st *ss;
198-
199-
if ((ss = ap_ctx_get(r->ctx, "ssl::io::suck")) == NULL)
200-
return;
201-
ss->active = TRUE;
202-
r->read_body = REQUEST_NO_BODY;
203-
r->read_length = 0;
204-
r->read_chunked = 0;
205-
r->remaining = 0;
206-
ap_bsetflag(r->connection->client, B_CHUNK, 0);
207-
return;
208-
}
209-
210-
void ssl_io_suck(request_rec *r, SSL *ssl)
211-
{
212-
int rc;
213-
int len;
214-
char *buf;
215-
int buflen;
216-
char c;
217-
int sucked;
218-
219-
if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) == OK) {
220-
if (ap_should_client_block(r)) {
221-
222-
/* read client request block through Apache API */
223-
buflen = HUGE_STRING_LEN;
224-
buf = ap_palloc(r->pool, buflen);
225-
ap_hard_timeout("SSL I/O request body pre-sucking", r);
226-
sucked = 0;
227-
ssl_io_suck_start(r);
228-
while ((len = ap_get_client_block(r, buf, buflen)) > 0) {
229-
ssl_io_suck_record(r, buf, len);
230-
sucked += len;
231-
}
232-
ssl_io_suck_end(r);
233-
ap_kill_timeout(r);
234-
235-
/* suck trailing data (usually CR LF) which
236-
is still in the Apache BUFF layer */
237-
while (ap_bpeekc(r->connection->client) != EOF) {
238-
c = ap_bgetc(r->connection->client);
239-
ssl_io_suck_record(r, &c, 1);
240-
sucked++;
241-
}
242-
243-
ssl_log(r->server, SSL_LOG_TRACE,
244-
"I/O: sucked %d bytes of input data from SSL/TLS I/O layer "
245-
"for delayed injection into Apache I/O layer", sucked);
246-
}
247-
}
248-
return;
249-
}
250-
251-
/* the SSL_read replacement routine which knows about the suck buffer */
252-
static int ssl_io_suck_read(SSL *ssl, char *buf, int len)
253-
{
254-
ap_ctx *actx;
255-
struct ssl_io_suck_st *ss;
256-
request_rec *r = NULL;
257-
int rv;
258-
259-
actx = (ap_ctx *)SSL_get_app_data2(ssl);
260-
if (actx != NULL)
261-
r = (request_rec *)ap_ctx_get(actx, "ssl::request_rec");
262-
263-
rv = -1;
264-
if (r != NULL) {
265-
ss = ap_ctx_get(r->ctx, "ssl::io::suck");
266-
if (ss != NULL) {
267-
if (ss->active && ss->pendlen > 0) {
268-
/* ok, there is pre-sucked data */
269-
len = (ss->pendlen > len ? len : ss->pendlen);
270-
memcpy(buf, ss->pendptr, len);
271-
ss->pendptr += len;
272-
ss->pendlen -= len;
273-
ssl_log(r->server, SSL_LOG_TRACE,
274-
"I/O: injecting %d bytes of pre-sucked data "
275-
"into Apache I/O layer", len);
276-
rv = len;
277-
}
278-
}
279-
}
280-
if (rv == -1)
281-
rv = SSL_read(ssl, buf, len);
282-
return rv;
283-
}
284-
285-
/* override SSL_read in the following code... */
286-
#define SSL_read ssl_io_suck_read
287-
288-
#endif /* !SSL_CONSERVATIVE */
289-
29067
/* _________________________________________________________________
29168
**
29269
** I/O Hooks

modules/ssl/ssl_engine_kernel.c

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -857,19 +857,71 @@ int ssl_hook_Access(request_rec *r)
857857
}
858858
#endif /* SSL_EXPERIMENTAL_PERDIRCA */
859859

860-
#ifdef SSL_CONSERVATIVE
861860
/*
862-
* SSL renegotiations in conjunction with HTTP
863-
* requests using the POST method are not supported.
861+
* SSL renegotiations in conjunction with HTTP
862+
* requests using the POST method are not supported.
863+
*
864+
* Background:
865+
*
866+
* 1. When the client sends a HTTP/HTTPS request, Apache's core code
867+
* reads only the request line ("METHOD /path HTTP/x.y") and the
868+
* attached MIME headers ("Foo: bar") up to the terminating line ("CR
869+
* LF"). An attached request body (for instance the data of a POST
870+
* method) is _NOT_ read. Instead it is read by mod_cgi's content
871+
* handler and directly passed to the CGI script.
872+
*
873+
* 2. mod_ssl supports per-directory re-configuration of SSL parameters.
874+
* This is implemented by performing an SSL renegotiation of the
875+
* re-configured parameters after the request is read, but before the
876+
* response is sent. In more detail: the renegotiation happens after the
877+
* request line and MIME headers were read, but _before_ the attached
878+
* request body is read. The reason simply is that in the HTTP protocol
879+
* usually there is no acknowledgment step between the headers and the
880+
* body (there is the 100-continue feature and the chunking facility
881+
* only), so Apache has no API hook for this step.
882+
*
883+
* 3. the problem now occurs when the client sends a POST request for
884+
* URL /foo via HTTPS the server and the server has SSL parameters
885+
* re-configured on a per-URL basis for /foo. Then mod_ssl has to
886+
* perform an SSL renegotiation after the request was read and before
887+
* the response is sent. But the problem is the pending POST body data
888+
* in the receive buffer of SSL (which Apache still has not read - it's
889+
* pending until mod_cgi sucks it in). When mod_ssl now tries to perform
890+
* the renegotiation the pending data leads to an I/O error.
891+
*
892+
* Solution Idea:
893+
*
894+
* There are only two solutions: Either to simply state that POST
895+
* requests to URLs with SSL re-configurations are not allowed, or to
896+
* renegotiate really after the _complete_ request (i.e. including
897+
* the POST body) was read. Obviously the latter would be preferred,
898+
* but it cannot be done easily inside Apache, because as already
899+
* mentioned, there is no API step between the body reading and the body
900+
* processing. And even when we mod_ssl would hook directly into the
901+
* loop of mod_cgi, we wouldn't solve the problem for other handlers, of
902+
* course. So the only general solution is to suck in the pending data
903+
* of the request body from the OpenSSL BIO into the Apache BUFF. Then
904+
* the renegotiation can be done and after this step Apache can proceed
905+
* processing the request as before.
906+
*
907+
* Solution Implementation:
908+
*
909+
* We cannot simply suck in the data via an SSL_read-based loop because of
910+
* HTTP chunking. Instead we _have_ to use the Apache API for this step which
911+
* is aware of HTTP chunking. So the trick is to suck in the pending request
912+
* data via the Apache API (which uses Apache's BUFF code and in the
913+
* background mod_ssl's I/O glue code) and re-inject it later into the Apache
914+
* BUFF code again. This way the data flows twice through the Apache BUFF, of
915+
* course. But this way the solution doesn't depend on any Apache specifics
916+
* and is fully transparent to Apache modules.
917+
*
918+
* !! BUT ALL THIS IS STILL NOT RE-IMPLEMENTED FOR APACHE 2.0 !!
864919
*/
865920
if (renegotiate && r->method_number == M_POST) {
866921
ssl_log(r->server, SSL_LOG_ERROR,
867922
"SSL Re-negotiation in conjunction with POST method not supported!");
868-
ssl_log(r->server, SSL_LOG_INFO,
869-
"You have to compile without -DSSL_CONSERVATIVE to enabled support for this.");
870923
return METHOD_NOT_ALLOWED;
871924
}
872-
#endif /* SSL_CONSERVATIVE */
873925

874926
/*
875927
* now do the renegotiation if anything was actually reconfigured
@@ -922,9 +974,6 @@ int ssl_hook_Access(request_rec *r)
922974
SSL_set_session_id_context(ssl, (unsigned char *)&(r->main), sizeof(r->main));
923975
else
924976
SSL_set_session_id_context(ssl, (unsigned char *)&r, sizeof(r));
925-
#ifndef SSL_CONSERVATIVE
926-
ssl_io_suck(r, ssl);
927-
#endif
928977
SSL_renegotiate(ssl);
929978
SSL_do_handshake(ssl);
930979
if (SSL_get_state(ssl) != SSL_ST_OK) {

0 commit comments

Comments
 (0)