1 /* _ _
2 ** _ __ ___ ___ __| | ___ ___| | mod_ssl
3 ** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
4 ** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
5 ** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
6 ** |_____|
7 ** ssl_engine_io.c
8 ** I/O Functions
9 */
10
11 /* ====================================================================
12 * Copyright (c) 1998-2003 Ralf S. Engelschall. All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 *
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 *
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials
24 * provided with the distribution.
25 *
26 * 3. All advertising materials mentioning features or use of this
27 * software must display the following acknowledgment:
28 * "This product includes software developed by
29 * Ralf S. Engelschall <rse@engelschall.com> for use in the
30 * mod_ssl project (http://www.modssl.org/)."
31 *
32 * 4. The names "mod_ssl" must not be used to endorse or promote
33 * products derived from this software without prior written
34 * permission. For written permission, please contact
35 * rse@engelschall.com.
36 *
37 * 5. Products derived from this software may not be called "mod_ssl"
38 * nor may "mod_ssl" appear in their names without prior
39 * written permission of Ralf S. Engelschall.
40 *
41 * 6. Redistributions of any form whatsoever must retain the following
42 * acknowledgment:
43 * "This product includes software developed by
44 * Ralf S. Engelschall <rse@engelschall.com> for use in the
45 * mod_ssl project (http://www.modssl.org/)."
46 *
47 * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
48 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
51 * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
53 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
54 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
56 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
58 * OF THE POSSIBILITY OF SUCH DAMAGE.
59 * ====================================================================
60 */
61 /* ``MY HACK: This universe.
62 Just one little problem:
63 core keeps dumping.''
64 -- Unknown */
65 #include "mod_ssl.h"
66
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 */
ssl_io_suck_start(request_rec * r)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 */
ssl_io_suck_record(request_rec * r,char * buf,int len)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 */
ssl_io_suck_end(request_rec * r)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
ssl_io_suck(request_rec * r,SSL * ssl)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 ap_hard_timeout("SSL I/O request trailing data pre-sucking", r);
238 while (ap_bpeekc(r->connection->client) != EOF) {
239 c = ap_bgetc(r->connection->client);
240 ssl_io_suck_record(r, &c, 1);
241 sucked++;
242 }
243 ap_kill_timeout(r);
244
245 ssl_log(r->server, SSL_LOG_TRACE,
246 "I/O: sucked %d bytes of input data from SSL/TLS I/O layer "
247 "for delayed injection into Apache I/O layer", sucked);
248 }
249 }
250 return;
251 }
252
253 /* the SSL_read replacement routine which knows about the suck buffer */
ssl_io_suck_read(SSL * ssl,char * buf,int len)254 static int ssl_io_suck_read(SSL *ssl, char *buf, int len)
255 {
256 ap_ctx *actx;
257 struct ssl_io_suck_st *ss;
258 request_rec *r = NULL;
259 int rv;
260
261 actx = (ap_ctx *)SSL_get_app_data2(ssl);
262 if (actx != NULL)
263 r = (request_rec *)ap_ctx_get(actx, "ssl::request_rec");
264
265 rv = -1;
266 if (r != NULL) {
267 ss = ap_ctx_get(r->ctx, "ssl::io::suck");
268 if (ss != NULL) {
269 if (ss->active && ss->pendlen > 0) {
270 /* ok, there is pre-sucked data */
271 len = (ss->pendlen > len ? len : ss->pendlen);
272 memcpy(buf, ss->pendptr, len);
273 ss->pendptr += len;
274 ss->pendlen -= len;
275 ssl_log(r->server, SSL_LOG_TRACE,
276 "I/O: injecting %d bytes of pre-sucked data "
277 "into Apache I/O layer", len);
278 rv = len;
279 }
280 }
281 }
282 if (rv == -1)
283 rv = SSL_read(ssl, buf, len);
284 return rv;
285 }
286
287 /* override SSL_read in the following code... */
288 #define SSL_read ssl_io_suck_read
289
290 #endif /* !SSL_CONSERVATIVE */
291
292 /* _________________________________________________________________
293 **
294 ** I/O Hooks
295 ** _________________________________________________________________
296 */
297
298 #include <sys/types.h>
299 #include <sys/uio.h>
300
301 static int ssl_io_hook_read(BUFF *fb, char *buf, int len);
302 static int ssl_io_hook_write(BUFF *fb, char *buf, int len);
303 static int ssl_io_hook_writev(BUFF *fb, const struct iovec *iov, int iovcnt);
304
ssl_io_register(void)305 void ssl_io_register(void)
306 {
307 ap_hook_register("ap::buff::read", ssl_io_hook_read, AP_HOOK_NOCTX);
308 ap_hook_register("ap::buff::write", ssl_io_hook_write, AP_HOOK_NOCTX);
309 ap_hook_register("ap::buff::writev", ssl_io_hook_writev, AP_HOOK_NOCTX);
310 return;
311 }
312
ssl_io_unregister(void)313 void ssl_io_unregister(void)
314 {
315 ap_hook_unregister("ap::buff::read", ssl_io_hook_read);
316 ap_hook_unregister("ap::buff::write", ssl_io_hook_write);
317 ap_hook_unregister("ap::buff::writev", ssl_io_hook_writev);
318 return;
319 }
320
ssl_io_hook_read(BUFF * fb,char * buf,int len)321 static int ssl_io_hook_read(BUFF *fb, char *buf, int len)
322 {
323 SSL *ssl;
324 conn_rec *c;
325 int rc;
326
327 if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) {
328 rc = SSL_read(ssl, buf, len);
329 /*
330 * Simulate an EINTR in case OpenSSL wants to read more.
331 * (This is usually the case when the client forces an SSL
332 * renegotation which is handled implicitly by OpenSSL.)
333 */
334 if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_READ)
335 errno = EINTR;
336 /*
337 * Log SSL errors
338 */
339 if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_SSL) {
340 c = (conn_rec *)SSL_get_app_data(ssl);
341 ssl_log(c->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
342 "SSL error on reading data");
343 }
344 /*
345 * read(2) returns only the generic error number -1
346 */
347 if (rc < 0)
348 rc = -1;
349 }
350 else
351 rc = read(fb->fd_in, buf, len);
352 return rc;
353 }
354
ssl_io_hook_write(BUFF * fb,char * buf,int len)355 static int ssl_io_hook_write(BUFF *fb, char *buf, int len)
356 {
357 SSL *ssl;
358 conn_rec *c;
359 int rc;
360
361 if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) {
362 rc = SSL_write(ssl, buf, len);
363 /*
364 * Simulate an EINTR in case OpenSSL wants to write more.
365 */
366 if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_WRITE)
367 errno = EINTR;
368 /*
369 * Log SSL errors
370 */
371 if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_SSL) {
372 c = (conn_rec *)SSL_get_app_data(ssl);
373 ssl_log(c->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
374 "SSL error on writing data");
375 }
376 /*
377 * write(2) returns only the generic error number -1
378 */
379 if (rc < 0)
380 rc = -1;
381 }
382 else
383 rc = write(fb->fd, buf, len);
384 return rc;
385 }
386
387 /* the prototype for our own SSL_writev() */
388 static int SSL_writev(SSL *, const struct iovec *, int);
389
ssl_io_hook_writev(BUFF * fb,const struct iovec * iov,int iovcnt)390 static int ssl_io_hook_writev(BUFF *fb, const struct iovec *iov, int iovcnt)
391 {
392 SSL *ssl;
393 conn_rec *c;
394 int rc;
395
396 if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) {
397 rc = SSL_writev(ssl, iov, iovcnt);
398 /*
399 * Simulate an EINTR in case OpenSSL wants to write more.
400 */
401 if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_WRITE)
402 errno = EINTR;
403 /*
404 * Log SSL errors
405 */
406 if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_SSL) {
407 c = (conn_rec *)SSL_get_app_data(ssl);
408 ssl_log(c->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
409 "SSL error on writing data");
410 }
411 /*
412 * writev(2) returns only the generic error number -1
413 */
414 if (rc < 0)
415 rc = -1;
416 }
417 else
418 rc = writev(fb->fd, iov, iovcnt);
419 return rc;
420 }
421
422
423 /* _________________________________________________________________
424 **
425 ** Special Functions for OpenSSL
426 ** _________________________________________________________________
427 */
428
429
430 /*
431 * There is no SSL_writev() provided by OpenSSL. The reason is mainly because
432 * OpenSSL has to fragment the data itself again for the SSL record layer, so a
433 * writev() like interface makes not much sense. What we do is to emulate it
434 * to at least being able to use the write() like interface. But keep in mind
435 * that the network I/O performance is not write() like, of course.
436 */
SSL_writev(SSL * ssl,const struct iovec * iov,int iovcnt)437 static int SSL_writev(SSL *ssl, const struct iovec *iov, int iovcnt)
438 {
439 int i;
440 int n;
441 int rc;
442
443 rc = 0;
444 for (i = 0; i < iovcnt; i++) {
445 if ((n = SSL_write(ssl, iov[i].iov_base, iov[i].iov_len)) == -1) {
446 rc = -1;
447 break;
448 }
449 rc += n;
450 }
451 return rc;
452 }
453
454 /* _________________________________________________________________
455 **
456 ** I/O Data Debugging
457 ** _________________________________________________________________
458 */
459
460 #define DUMP_WIDTH 16
461
ssl_io_data_dump(server_rec * srvr,const char * s,long len)462 static void ssl_io_data_dump(server_rec *srvr, const char *s, long len)
463 {
464 char buf[256];
465 char tmp[64];
466 int i, j, rows, trunc;
467 unsigned char ch;
468
469 trunc = 0;
470 for(; (len > 0) && ((s[len-1] == ' ') || (s[len-1] == '\0')); len--)
471 trunc++;
472 rows = (len / DUMP_WIDTH);
473 if ((rows * DUMP_WIDTH) < len)
474 rows++;
475 ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
476 "+-------------------------------------------------------------------------+");
477 for(i = 0 ; i< rows; i++) {
478 snprintf(tmp, sizeof(tmp), "| %04x: ", i * DUMP_WIDTH);
479 ap_cpystrn(buf, tmp, sizeof(buf));
480 for (j = 0; j < DUMP_WIDTH; j++) {
481 if (((i * DUMP_WIDTH) + j) >= len)
482 ap_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
483 else {
484 ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff;
485 snprintf(tmp, sizeof(tmp), "%02x%c", ch , j==7 ? '-' : ' ');
486 ap_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf));
487 }
488 }
489 ap_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
490 for (j = 0; j < DUMP_WIDTH; j++) {
491 if (((i * DUMP_WIDTH) + j) >= len)
492 ap_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
493 else {
494 ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff;
495 snprintf(tmp, sizeof(tmp), "%c", ((ch >= ' ') && (ch <= '~')) ? ch : '.');
496 ap_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf));
497 }
498 }
499 ap_cpystrn(buf+strlen(buf), " |", sizeof(buf)-strlen(buf));
500 ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID, "%s", buf);
501 }
502 if (trunc > 0)
503 ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
504 "| %04x - <SPACES/NULS>", len + trunc);
505 ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
506 "+-------------------------------------------------------------------------+");
507 return;
508 }
509
ssl_io_data_cb(BIO * bio,int cmd,const char * argp,int argi,long argl,long rc)510 long ssl_io_data_cb(BIO *bio, int cmd, const char *argp, int argi, long argl, long rc)
511 {
512 SSL *ssl;
513 conn_rec *c;
514 server_rec *s;
515
516 if ((ssl = (SSL *)BIO_get_callback_arg(bio)) == NULL)
517 return rc;
518 if ((c = (conn_rec *)SSL_get_app_data(ssl)) == NULL)
519 return rc;
520 s = c->server;
521
522 if ( cmd == (BIO_CB_WRITE|BIO_CB_RETURN)
523 || cmd == (BIO_CB_READ |BIO_CB_RETURN) ) {
524 if (rc >= 0) {
525 ssl_log(s, SSL_LOG_DEBUG,
526 "%s: %s %ld/%d bytes %s BIO#%08X [mem: %08lX] %s",
527 SSL_LIBRARY_NAME,
528 (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"),
529 rc, argi, (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "to" : "from"),
530 bio, argp,
531 (argp != NULL ? "(BIO dump follows)" : "(Ops, no memory buffer?)"));
532 if (argp != NULL)
533 ssl_io_data_dump(s, argp, rc);
534 }
535 else {
536 ssl_log(s, SSL_LOG_DEBUG,
537 "%s: I/O error, %d bytes expected to %s on BIO#%08X [mem: %08lX]",
538 SSL_LIBRARY_NAME, argi,
539 (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"),
540 bio, argp);
541 }
542 }
543 return rc;
544 }
545
546