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