Apache HTTPD
tls_filter.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <assert.h>
17#include <apr_lib.h>
18#include <apr_strings.h>
19
20#include <httpd.h>
21#include <http_connection.h>
22#include <http_core.h>
23#include <http_request.h>
24#include <http_log.h>
25#include <ap_socache.h>
26
27#include <rustls.h>
28
29#include "tls_proto.h"
30#include "tls_conf.h"
31#include "tls_core.h"
32#include "tls_filter.h"
33#include "tls_util.h"
34
35
36extern module AP_MODULE_DECLARE_DATA tls_module;
38
39
41 void *userdata, unsigned char *buf, size_t n, size_t *out_n)
42{
43 tls_data_t *d = userdata;
44 size_t len = d->len > n? n : d->len;
45 memcpy(buf, d->data, len);
46 *out_n = len;
47 return 0;
48}
49
65{
67 apr_size_t rlen;
68 apr_off_t passed = 0;
70 int os_err;
72
73 if (APR_BRIGADE_EMPTY(fctx->fin_tls_bb)) {
75 "read_tls_to_rustls, get data from network, block=%d", block);
76 rv = ap_get_brigade(fctx->fin_ctx->next, fctx->fin_tls_bb,
78 if (APR_SUCCESS != rv) {
79 goto cleanup;
80 }
81 }
82
83 while (!APR_BRIGADE_EMPTY(fctx->fin_tls_bb) && passed < (apr_off_t)len) {
85
86 if (APR_BUCKET_IS_EOS(b)) {
88 "read_tls_to_rustls, EOS");
89 if (fctx->fin_tls_buffer_bb) {
91 }
92 rv = APR_EOF; goto cleanup;
93 }
94
95 rv = apr_bucket_read(b, (const char**)&d.data, &d.len, block);
96 if (APR_STATUS_IS_EOF(rv)) {
98 continue;
99 }
100 else if (APR_SUCCESS != rv) {
101 goto cleanup;
102 }
103
104 if (d.len > 0) {
105 /* got something, do not block on getting more */
107
109 tls_read_callback, &d, &rlen);
110 if (os_err) {
112 goto cleanup;
113 }
114
115 if (fctx->fin_tls_buffer_bb) {
116 /* we buffer for later replay on the 'real' rustls_connection */
117 apr_brigade_write(fctx->fin_tls_buffer_bb, NULL, NULL, (const char*)d.data, rlen);
118 }
119 if (rlen >= d.len) {
121 }
122 else {
123 b->start += (apr_off_t)rlen;
124 b->length -= rlen;
125 }
126 fctx->fin_bytes_in_rustls += (apr_off_t)d.len;
127 passed += (apr_off_t)rlen;
128 }
129 else if (d.len == 0) {
131 }
132 }
133
134 if (passed > 0) {
136 if (rr != RUSTLS_RESULT_OK) goto cleanup;
137 }
138
139cleanup:
140 if (rr != RUSTLS_RESULT_OK) {
141 rv = APR_ECONNRESET;
142 if (!errors_expected) {
143 const char *err_descr = "";
144 rv = tls_core_error(fctx->c, rr, &err_descr);
146 "processing TLS data: [%d] %s", (int)rr, err_descr);
147 }
148 }
149 else if (APR_STATUS_IS_EOF(rv) && passed > 0) {
150 /* encountering EOF while actually having read sth is a success. */
151 rv = APR_SUCCESS;
152 }
153 else if (APR_SUCCESS == rv && passed == 0 && fctx->fin_block == APR_NONBLOCK_READ) {
154 rv = APR_EAGAIN;
155 }
156 else {
158 "read_tls_to_rustls, passed %ld bytes to rustls", (long)passed);
159 }
160 return rv;
161}
162
164{
166
167 if (!APR_BRIGADE_EMPTY(fctx->fout_tls_bb)) {
168 rv = ap_pass_brigade(fctx->fout_ctx->next, fctx->fout_tls_bb);
169 if (APR_SUCCESS == rv && fctx->c->aborted) {
170 rv = APR_ECONNRESET;
171 }
172 fctx->fout_bytes_in_tls_bb = 0;
174 }
175 return rv;
176}
177
179 tls_filter_ctx_t *fctx, int flush);
180
182 tls_filter_ctx_t *fctx)
183{
184 apr_status_t rv;
185
186 if (fctx->cc->state != TLS_CONN_ST_DONE) {
187 if (fctx->cc->state > TLS_CONN_ST_CLIENT_HELLO) {
189 rv = fout_pass_all_to_net(fctx, 1);
190 ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, "filter_abort, flushed output");
191 }
192 fctx->c->aborted = 1;
193 fctx->cc->state = TLS_CONN_ST_DONE;
194 }
195 return APR_ECONNABORTED;
196}
197
199{
201
203 "tls_filter, server=%s, recv client hello", fctx->cc->server->server_hostname);
204 /* only for incoming connections */
205 ap_assert(!fctx->cc->outgoing);
206
209
210 ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, "filter_recv_client_hello: start");
212 do {
215 if (APR_SUCCESS != rv) {
216 if (fctx->cc->client_hello_seen) {
217 rv = APR_EAGAIN; /* we got what we needed */
218 break;
219 }
220 /* Something went wrong before we saw the client hello.
221 * This is a real error on which we should not continue. */
222 goto cleanup;
223 }
224 }
225 /* Notice: we never write here to the client. We just want to inspect
226 * the client hello. */
227 } while (!fctx->cc->client_hello_seen);
228
229 /* We have seen the client hello and selected the server (vhost) to use
230 * on this connection. Set up the 'real' rustls_connection based on the
231 * servers 'real' rustls_config. */
233 if (APR_SUCCESS != rv) goto cleanup;
234
235 bb_tmp = fctx->fin_tls_bb; /* data we have yet to feed to rustls */
236 fctx->fin_tls_bb = fctx->fin_tls_buffer_bb; /* data we already fed to the pre_session */
237 fctx->fin_tls_buffer_bb = NULL;
238 APR_BRIGADE_CONCAT(fctx->fin_tls_bb, bb_tmp); /* all tls data from the client so far, reloaded */
240 rv = APR_SUCCESS;
241 }
242
243cleanup:
244 ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, "filter_recv_client_hello: done");
245 return rv;
246}
247
249{
251
253 "tls_filter, server=%s, send client hello", fctx->cc->server->server_hostname);
254 /* Only for outgoing connections */
255 ap_assert(fctx->cc->outgoing);
258 /* write flushed, so it really gets out */
259 rv = fout_pass_all_to_net(fctx, 1);
260 if (APR_SUCCESS != rv) goto cleanup;
261 }
262 }
263
264cleanup:
265 return rv;
266}
267
275 tls_filter_ctx_t *fctx)
276{
278
280 "tls_filter, server=%s, do handshake", fctx->cc->server->server_hostname);
282 do {
284 rv = fout_pass_all_to_net(fctx, 1);
285 if (APR_SUCCESS != rv) goto cleanup;
286 }
289 if (APR_SUCCESS != rv) goto cleanup;
290 }
291 }
293
294 /* rustls reports the TLS handshake to be done, when it *internally* has
295 * processed everything into its buffers. Not when the buffers have been
296 * send to the other side. */
298 rv = fout_pass_all_to_net(fctx, 1);
299 if (APR_SUCCESS != rv) goto cleanup;
300 }
301 }
302cleanup:
304 "tls_filter, server=%s, handshake done", fctx->cc->server->server_hostname);
305 if (APR_SUCCESS != rv) {
306 if (fctx->cc->last_error_descr) {
308 "handshake failed: %s", fctx->cc->last_error_descr);
309 }
310 }
311 return rv;
312}
313
315{
317
318 /* handle termination immediately */
319 if (state == TLS_CONN_ST_DONE) {
320 rv = APR_ECONNABORTED;
321 goto cleanup;
322 }
323
324 if (state > TLS_CONN_ST_CLIENT_HELLO
325 && TLS_CONN_ST_CLIENT_HELLO == fctx->cc->state) {
326 rv = tls_core_conn_init(fctx->c);
327 if (APR_SUCCESS != rv) goto cleanup;
328
329 if (fctx->cc->outgoing) {
330 rv = filter_send_client_hello(fctx);
331 }
332 else {
333 rv = filter_recv_client_hello(fctx);
334 }
335 if (APR_SUCCESS != rv) goto cleanup;
337 }
338
339 if (state > TLS_CONN_ST_HANDSHAKE
340 && TLS_CONN_ST_HANDSHAKE== fctx->cc->state) {
341 rv = filter_do_handshake(fctx);
342 if (APR_SUCCESS != rv) goto cleanup;
344 if (APR_SUCCESS != rv) goto cleanup;
346 }
347
348 if (state < fctx->cc->state) {
349 rv = APR_ECONNABORTED;
350 }
351
352cleanup:
353 if (APR_SUCCESS != rv) {
354 filter_abort(fctx); /* does change the state itself */
355 }
356 return rv;
357}
358
383{
384 tls_filter_ctx_t *fctx = f->ctx;
386 apr_off_t passed = 0, nlen;
389 char *in_buf = NULL;
390
391 fctx->fin_block = block;
392 if (f->c->aborted) {
393 rv = filter_abort(fctx); goto cleanup;
394 }
395
397 "tls_filter_conn_input, server=%s, mode=%d, block=%d, readbytes=%ld",
398 fctx->cc->server->server_hostname, mode, block, (long)readbytes);
399
401 if (APR_SUCCESS != rv) goto cleanup; /* this also leaves on APR_EAGAIN */
402
403 if (!fctx->cc->rustls_connection) {
404 return ap_get_brigade(f->next, bb, mode, block, readbytes);
405 }
406
407#if AP_MODULE_MAGIC_AT_LEAST(20200420, 1)
409#endif
410
411 if (AP_MODE_INIT == mode) {
412 /* INIT is used to trigger the handshake, it does not return any traffic data. */
413 goto cleanup;
414 }
415
416 /* If we have nothing buffered, try getting more input.
417 * a) ask rustls_connection for decrypted data, if it has any.
418 * Note that only full records can be decrypted. We might have
419 * written TLS data to the session, but that does not mean it
420 * can give unencryted data out again.
421 * b) read TLS bytes from the network and feed them to the rustls session.
422 * c) go back to a) if b) added data.
423 */
424 while (APR_BRIGADE_EMPTY(fctx->fin_plain_bb)) {
425 apr_size_t rlen = 0;
426 apr_bucket *b;
427
428 if (fctx->fin_bytes_in_rustls > 0) {
430 in_buf = ap_calloc(in_buf_len, sizeof(char));
432 (unsigned char*)in_buf, in_buf_len, &rlen);
435 rlen = 0;
436 }
437 if (rr != RUSTLS_RESULT_OK) goto cleanup;
439 "tls_filter_conn_input: got %ld plain bytes from rustls", (long)rlen);
440 if (rlen > 0) {
441 b = apr_bucket_heap_create(in_buf, rlen, free, fctx->c->bucket_alloc);
443 }
444 else {
445 free(in_buf);
446 }
447 in_buf = NULL;
448 }
449 if (rlen == 0) {
450 /* that did not produce anything either. try getting more
451 * TLS data from the network into the rustls session. */
452 fctx->fin_bytes_in_rustls = 0;
453 rv = read_tls_to_rustls(fctx, fctx->fin_max_in_rustls, block, 0);
454 if (APR_SUCCESS != rv) goto cleanup; /* this also leave on APR_EAGAIN */
455 }
456 }
457
458 if (AP_MODE_GETLINE == mode) {
461 if (APR_SUCCESS != rv) goto cleanup;
462 passed += nlen;
463 }
464 else if (AP_MODE_READBYTES == mode) {
465 ap_assert(readbytes > 0);
467 if (APR_SUCCESS != rv) goto cleanup;
468 passed += nlen;
469 }
470 else if (AP_MODE_SPECULATIVE == mode) {
471 ap_assert(readbytes > 0);
473 if (APR_SUCCESS != rv) goto cleanup;
474 passed += nlen;
475 }
476 else if (AP_MODE_EXHAUSTIVE == mode) {
477 /* return all we have */
479 }
480 else {
481 /* We do support any other mode */
482 rv = APR_ENOTIMPL; goto cleanup;
483 }
484
485 fout_pass_all_to_net(fctx, 0);
486
487cleanup:
488 if (NULL != in_buf) free(in_buf);
489
490 if (APLOGctrace3(fctx->c)) {
491 tls_util_bb_log(fctx->c, APLOG_TRACE3, "tls_input, fctx->fin_plain_bb", fctx->fin_plain_bb);
492 tls_util_bb_log(fctx->c, APLOG_TRACE3, "tls_input, bb", bb);
493 }
494 if (rr != RUSTLS_RESULT_OK) {
495 const char *err_descr = "";
496
497 rv = tls_core_error(fctx->c, rr, &err_descr);
498 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10355)
499 "tls_filter_conn_input: [%d] %s", (int)rr, err_descr);
500 }
501 else if (APR_STATUS_IS_EAGAIN(rv)) {
503 "tls_filter_conn_input: no data available");
504 }
505 else if (APR_SUCCESS != rv) {
506 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10356)
507 "tls_filter_conn_input");
508 }
509 else {
511 "tls_filter_conn_input: passed %ld bytes", (long)passed);
512 }
513
514#if AP_MODULE_MAGIC_AT_LEAST(20200420, 1)
515 if (APR_SUCCESS == rv || APR_STATUS_IS_EAGAIN(rv)) {
517 }
518#endif
519 return rv;
520}
521
523 void *userdata, const unsigned char *buf, size_t n, size_t *out_n)
524{
525 tls_filter_ctx_t *fctx = userdata;
526 apr_status_t rv;
527
532 rv = fout_pass_tls_to_net(fctx);
533 *out_n = n;
534 }
535 else {
536 rv = apr_brigade_write(fctx->fout_tls_bb, NULL, NULL, (const char*)buf, n);
537 if (APR_SUCCESS != rv) goto cleanup;
539 *out_n = n;
540 }
541cleanup:
543 "tls_write_callback: %ld bytes", (long)n);
544 return APR_TO_OS_ERROR(rv);
545}
546
548 void *userdata, const rustls_iovec *riov, size_t count, size_t *out_n)
549{
550 tls_filter_ctx_t *fctx = userdata;
551 const struct iovec *iov = (const struct iovec*)riov;
552 apr_status_t rv;
553 size_t i, n = 0;
554 apr_bucket *b;
555
556 for (i = 0; i < count; ++i, ++iov) {
557 b = apr_bucket_transient_create((const char*)iov->iov_base, iov->iov_len, fctx->fout_tls_bb->bucket_alloc);
559 n += iov->iov_len;
560 }
562 rv = fout_pass_tls_to_net(fctx);
563 *out_n = n;
565 "tls_write_vectored_callback: %ld bytes in %d slices", (long)n, (int)count);
566 return APR_TO_OS_ERROR(rv);
567}
568
569#define TLS_WRITE_VECTORED 1
577{
579
581 size_t dlen;
582 int os_err;
583
584 if (TLS_WRITE_VECTORED) {
585 do {
588 if (os_err) {
590 goto cleanup;
591 }
592 }
594 }
595 else {
596 do {
599 if (os_err) {
601 goto cleanup;
602 }
603 }
606 "fout_pass_rustls_to_tls, %ld bytes ready for network", (long)fctx->fout_bytes_in_tls_bb);
607 fctx->fout_bytes_in_rustls = 0;
608 }
609 }
610cleanup:
611 return rv;
612}
613
615 tls_filter_ctx_t *fctx, const char *buf, apr_size_t len)
616{
619 apr_size_t written;
620
621 while (len) {
622 /* check if we will exceed the limit of data in rustls.
623 * rustls does not guarantuee that it will accept all data, so we
624 * iterate and flush when needed. */
626 rv = fout_pass_rustls_to_tls(fctx);
627 if (APR_SUCCESS != rv) goto cleanup;
628 }
629
631 (const unsigned char*)buf, len, &written);
632 if (rr != RUSTLS_RESULT_OK) goto cleanup;
633 ap_assert(written <= len);
634 fctx->fout_bytes_in_rustls += (apr_off_t)written;
635 buf += written;
636 len -= written;
637 if (written == 0) {
638 rv = APR_EAGAIN;
639 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, fctx->c, APLOGNO(10357)
640 "fout_pass_buf_to_rustls: not read by rustls at all");
641 goto cleanup;
642 }
643 }
644cleanup:
645 if (rr != RUSTLS_RESULT_OK) {
646 const char *err_descr = "";
647 rv = tls_core_error(fctx->c, rr, &err_descr);
648 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10358)
649 "fout_pass_buf_to_tls to rustls: [%d] %s", (int)rr, err_descr);
650 }
651 return rv;
652}
653
655{
657
658 if (fctx->fout_buf_plain_len) {
661 "fout_pass_all_to_tls: %ld plain bytes written to rustls",
662 (long)fctx->fout_buf_plain_len);
663 if (APR_SUCCESS != rv) goto cleanup;
664 fctx->fout_buf_plain_len = 0;
665 }
666
667 rv = fout_pass_rustls_to_tls(fctx);
668cleanup:
669 return rv;
670}
671
673{
674 apr_status_t rv;
675
676 rv = fout_pass_all_to_tls(fctx);
677 if (APR_SUCCESS != rv) goto cleanup;
678 if (flush) {
681 }
682 rv = fout_pass_tls_to_net(fctx);
683cleanup:
684 return rv;
685}
686
688{
689 const char *data;
692
693 ap_assert((apr_size_t)-1 != b->length);
694 if (b->length == 0) {
696 goto cleanup;
697 }
698
700 if (buf_remain == 0) {
701 rv = fout_pass_all_to_tls(fctx);
702 if (APR_SUCCESS != rv) goto cleanup;
705 }
706 if (b->length > buf_remain) {
708 }
710 if (APR_SUCCESS != rv) goto cleanup;
711 /*if (dlen > TLS_PREF_PLAIN_CHUNK_SIZE)*/
714 fctx->fout_buf_plain_len += dlen;
716cleanup:
717 return rv;
718}
719
721{
722 apr_status_t rv;
723
724 rv = fout_pass_all_to_tls(fctx);
725 if (APR_SUCCESS != rv) goto cleanup;
728 if (AP_BUCKET_IS_EOC(b)) {
731 rv = fout_pass_rustls_to_tls(fctx);
732 if (APR_SUCCESS != rv) goto cleanup;
733 }
734cleanup:
735 return rv;
736}
737
739{
740 const char *data;
744 const char *lbuf = NULL;
745 int flush = 0;
746
747 if (b) {
748 /* if our plain buffer is full, now is a good time to flush it. */
750 if (buf_remain == 0) {
751 rv = fout_pass_all_to_tls(fctx);
752 if (APR_SUCCESS != rv) goto cleanup;
755 }
756
757 /* Resolve any indeterminate bucket to a "real" one by reading it. */
758 if ((apr_size_t)-1 == b->length) {
760 if (APR_STATUS_IS_EOF(rv)) {
762 goto maybe_flush;
763 }
764 else if (APR_SUCCESS != rv) goto cleanup;
765 }
766 /* Now `b` is the bucket that we need to append and consume */
768 /* outgoing buckets:
769 * [PLAINDATA META PLAINDATA META META]
770 * need to become:
771 * [TLSDATA META TLSDATA META META]
772 * because we need to send the meta buckets down the
773 * network filters. */
774 rv = fout_add_bucket_to_tls(fctx, b);
775 flush = 1;
776 }
777 else if (b->length == 0) {
779 }
780 else if (b->length < 1024 || fctx->fout_buf_plain_len > 0) {
781 /* we want to buffer small chunks to create larger TLS records and
782 * not leak security relevant information. So, we buffer small
783 * chunks and add (parts of) later, larger chunks if the plain
784 * buffer contains data. */
785 rv = fout_add_bucket_to_plain(fctx, b);
786 if (APR_SUCCESS != rv) goto cleanup;
787 }
788 else {
789 /* we have a large chunk and our plain buffer is empty, write it
790 * directly into rustls. */
791#define TLS_FILE_CHUNK_SIZE 4 * TLS_PREF_PLAIN_CHUNK_SIZE
792 if (b->length > TLS_FILE_CHUNK_SIZE) {
794 }
795
797 && (lbuf = malloc(b->length))) {
798 /* A file bucket is a most wonderous thing. Since the dawn of time,
799 * it has been subject to many optimizations for efficient handling
800 * of large data in the server:
801 * - unless one reads from it, it will just consist of a file handle
802 * and the offset+length information.
803 * - a apr_bucket_read() will transform itself to a bucket holding
804 * some 8000 bytes of data (APR_BUCKET_BUFF_SIZE), plus a following
805 * bucket that continues to hold the file handle and updated offsets/length
806 * information.
807 * Using standard bucket brigade handling, one would send 8000 bytes
808 * chunks to the network and that is fine for many occasions.
809 * - to have improved performance, the http: network handler takes
810 * the file handle directly and uses sendfile() when the OS supports it.
811 * - But there is not sendfile() for TLS (netflix did some experiments).
812 * So.
813 * rustls will try to collect max length traffic data into ont TLS
814 * message, but it can only work with what we gave it. If we give it buffers
815 * that fit what it wants to assemble already, its work is much easier.
816 *
817 * We can read file buckets in large chunks than APR_BUCKET_BUFF_SIZE,
818 * with a bit of knowledge about how they work.
819 */
821 apr_file_t *fd = f->fd;
822 apr_off_t offset = b->start;
823
824 dlen = b->length;
826 if (APR_SUCCESS != rv) goto cleanup;
827 rv = apr_file_read(fd, (void*)lbuf, &dlen);
828 if (APR_SUCCESS != rv && !APR_STATUS_IS_EOF(rv)) goto cleanup;
829 rv = fout_pass_buf_to_rustls(fctx, lbuf, dlen);
830 if (APR_SUCCESS != rv) goto cleanup;
832 }
833 else {
835 if (APR_SUCCESS != rv) goto cleanup;
836 rv = fout_pass_buf_to_rustls(fctx, data, dlen);
837 if (APR_SUCCESS != rv) goto cleanup;
839 }
840 }
841 }
842
844 if (flush) {
845 rv = fout_pass_all_to_net(fctx, 1);
846 if (APR_SUCCESS != rv) goto cleanup;
847 }
848
849cleanup:
850 if (lbuf) free((void*)lbuf);
851 if (rr != RUSTLS_RESULT_OK) {
852 const char *err_descr = "";
853 rv = tls_core_error(fctx->c, rr, &err_descr);
854 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10359)
855 "write_bucket_to_rustls: [%d] %s", (int)rr, err_descr);
856 }
857 return rv;
858}
859
874{
875 tls_filter_ctx_t *fctx = f->ctx;
878
879 if (f->c->aborted) {
881 "tls_filter_conn_output: aborted conn");
883 rv = APR_ECONNABORTED; goto cleanup;
884 }
885
887 if (APR_SUCCESS != rv) goto cleanup; /* this also leaves on APR_EAGAIN */
888
889 if (fctx->cc->state == TLS_CONN_ST_DONE) {
890 /* have done everything, just pass through */
892 "tls_filter_conn_output: tls session is already done");
893 rv = ap_pass_brigade(f->next, bb);
894 goto cleanup;
895 }
896
898 "tls_filter_conn_output, server=%s", fctx->cc->server->server_hostname);
899 if (APLOGctrace5(fctx->c)) {
900 tls_util_bb_log(fctx->c, APLOG_TRACE5, "filter_conn_output", bb);
901 }
902
903 while (!APR_BRIGADE_EMPTY(bb)) {
904 rv = fout_append_plain(fctx, APR_BRIGADE_FIRST(bb));
905 if (APR_SUCCESS != rv) goto cleanup;
906 }
907
908 if (APLOGctrace5(fctx->c)) {
909 tls_util_bb_log(fctx->c, APLOG_TRACE5, "filter_conn_output, processed plain", bb);
910 tls_util_bb_log(fctx->c, APLOG_TRACE5, "filter_conn_output, tls", fctx->fout_tls_bb);
911 }
912
913cleanup:
914 if (rr != RUSTLS_RESULT_OK) {
915 const char *err_descr = "";
916 rv = tls_core_error(fctx->c, rr, &err_descr);
917 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10360)
918 "tls_filter_conn_output: [%d] %s", (int)rr, err_descr);
919 }
920 else {
922 "tls_filter_conn_output: done");
923 }
924 return rv;
925}
926
928{
929 tls_conf_conn_t *cc;
930 tls_filter_ctx_t *fctx;
931
932 if (OK != tls_core_pre_conn_init(c)) {
933 return DECLINED;
934 }
935
936 ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server,
937 "tls_filter_pre_conn_init on %s", c->base_server->server_hostname);
938
939 cc = tls_conf_conn_get(c);
940 ap_assert(cc);
941
942 fctx = apr_pcalloc(c->pool, sizeof(*fctx));
943 fctx->c = c;
944 fctx->cc = cc;
945 cc->filter_ctx = fctx;
946
947 /* a bit tricky: registering out filters returns the ap_filter_t*
948 * that it created for it. The ->next field points always
949 * to the filter "below" our filter. That will be other registered
950 * filters and last, but not least, the network filter on the socket.
951 *
952 * Therefore, wenn we need to read/write TLS data during handshake, we can
953 * pass the data to/call on ->next- Since ->next can change during the setup of
954 * a connections (other modules register also sth.), we keep the ap_filter_t*
955 * returned here, since httpd core will update the ->next whenever someone
956 * adds a filter or removes one. This can potentially happen all the time.
957 */
959 fctx->fin_tls_bb = apr_brigade_create(c->pool, c->bucket_alloc);
960 fctx->fin_tls_buffer_bb = NULL;
961 fctx->fin_plain_bb = apr_brigade_create(c->pool, c->bucket_alloc);
963 fctx->fout_tls_bb = apr_brigade_create(c->pool, c->bucket_alloc);
965 fctx->fout_buf_plain = apr_pcalloc(c->pool, fctx->fout_buf_plain_size);
966 fctx->fout_buf_plain_len = 0;
967
968 /* Let the filters have 2 max-length TLS Messages in the rustls buffers.
969 * The effects we would like to achieve here are:
970 * 1. pass data out, so that every bucket becomes its own TLS message.
971 * This hides, if possible, the length of response parts.
972 * If we give rustls enough plain data, it will use the max TLS message
973 * size and things are more hidden. But we can only write what the application
974 * or protocol gives us.
975 * 2. max length records result in less overhead for all layers involved.
976 * 3. a TLS message from the client can only be decrypted when it has
977 * completely arrived. If we provide rustls with enough data (if the
978 * network has it for us), it should always be able to decrypt at least
979 * one TLS message and we have plain bytes to forward to the protocol
980 * handler.
981 */
985
986 return OK;
987}
988
990{
992
993 if (cc && cc->filter_ctx && !cc->outgoing) {
994 /* We are one in a row of hooks that - possibly - want to process this
995 * connection, the (HTTP) protocol handlers among them.
996 *
997 * For incoming connections, we need to select the protocol to use NOW,
998 * so that the later protocol handlers do the right thing.
999 * Send an INIT down the input filter chain to trigger the TLS handshake,
1000 * which will select a protocol via ALPN. */
1002
1003 ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server,
1004 "tls_filter_conn_init on %s, triggering handshake", c->base_server->server_hostname);
1005 temp = apr_brigade_create(c->pool, c->bucket_alloc);
1006 ap_get_brigade(c->input_filters, temp, AP_MODE_INIT, APR_BLOCK_READ, 0);
1008 }
1009}
1010
int n
Definition ap_regex.h:278
const char apr_size_t len
Definition ap_regex.h:187
Small object cache provider interface.
APR general purpose library routines.
apr_size_t const unsigned char unsigned int unsigned int d
Definition apr_siphash.h:72
APR Strings library.
#define APLOG_USE_MODULE(foo)
#define AP_BUCKET_IS_EOC(e)
int flush
#define HUGE_STRING_LEN
Definition httpd.h:303
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
apr_status_t ap_pass_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket)
ap_filter_t * ap_add_input_filter(const char *name, void *ctx, request_rec *r, conn_rec *c)
ap_filter_rec_t * ap_register_output_filter(const char *name, ap_out_filter_func filter_func, ap_init_filter_func filter_init, ap_filter_type ftype)
ap_filter_t * ap_add_output_filter(const char *name, void *ctx, request_rec *r, conn_rec *c)
apr_status_t ap_filter_rec_t * ap_register_input_filter(const char *name, ap_in_filter_func filter_func, ap_init_filter_func filter_init, ap_filter_type ftype)
apr_status_t ap_get_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
@ AP_FTYPE_CONNECTION
#define APLOGctrace5(c)
Definition http_log.h:261
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_TRACE4
Definition http_log.h:75
#define APLOG_INFO
Definition http_log.h:70
#define APLOG_ERR
Definition http_log.h:67
#define APLOG_TRACE3
Definition http_log.h:74
#define ap_log_error
Definition http_log.h:370
#define ap_log_cerror
Definition http_log.h:498
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_WARNING
Definition http_log.h:68
#define APLOG_TRACE2
Definition http_log.h:73
#define APLOGctrace3(c)
Definition http_log.h:259
#define APLOG_TRACE5
Definition http_log.h:76
#define APLOG_DEBUG
Definition http_log.h:71
const unsigned char * buf
Definition util_md5.h:50
#define APR_EAGAIN
Definition apr_errno.h:730
#define APR_ECONNRESET
Definition apr_errno.h:776
#define APR_EOF
Definition apr_errno.h:461
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_ECONNABORTED
Definition apr_errno.h:769
unsigned int count
Definition apr_md5.h:152
#define APR_STATUS_IS_EAGAIN(s)
Definition apr_errno.h:1272
#define APR_STATUS_IS_EOF(s)
Definition apr_errno.h:567
apr_file_t * f
#define APR_BUCKET_IS_FILE(e)
#define APR_BUCKET_REMOVE(e)
#define APR_BUCKET_IS_METADATA(e)
#define APR_BRIGADE_INSERT_TAIL(b, e)
#define apr_bucket_split(e, point)
apr_read_type_e
Definition apr_buckets.h:57
#define APR_BRIGADE_CONCAT(a, b)
#define APR_BUCKET_BUFF_SIZE
Definition apr_buckets.h:54
#define APR_BRIGADE_EMPTY(b)
#define apr_bucket_delete(e)
#define APR_BUCKET_IS_EOS(e)
#define APR_BRIGADE_FIRST(b)
apr_file_t * fd
#define apr_bucket_read(e, str, len, block)
@ APR_BLOCK_READ
Definition apr_buckets.h:58
@ APR_NONBLOCK_READ
Definition apr_buckets.h:59
apr_dbd_transaction_t int mode
Definition apr_dbd.h:261
void * ap_calloc(size_t nelem, size_t size) __attribute__((malloc))
Definition util.c:3160
#define ap_assert(exp)
Definition httpd.h:2271
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_FROM_OS_ERROR(e)
Definition apr_errno.h:1214
#define APR_TO_OS_ERROR(e)
Definition apr_errno.h:1215
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
apr_seek_where_t apr_off_t * offset
void * data
void const char apr_status_t(* cleanup)(void *))
#define APR_SET
apr_vformatter_buff_t * c
Definition apr_lib.h:175
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
Apache connection library.
CORE HTTP Daemon.
Apache Logging library.
Apache Request library.
HTTP Daemon routines.
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
The representation of a filter chain.
ap_filter_t * next
apr_bucket_alloc_t * bucket_alloc
Structure to store things which are per connection.
Definition httpd.h:1152
apr_pool_t * pool
Definition httpd.h:1154
struct apr_bucket_alloc_t * bucket_alloc
Definition httpd.h:1201
unsigned aborted
Definition httpd.h:1219
char * server_hostname
Definition httpd.h:1365
struct tls_filter_ctx_t * filter_ctx
Definition tls_core.h:52
rustls_connection * rustls_connection
Definition tls_core.h:49
server_rec * server
Definition tls_core.h:40
int client_hello_seen
Definition tls_core.h:47
const char * last_error_descr
Definition tls_core.h:73
tls_conn_state_t state
Definition tls_core.h:43
apr_size_t len
Definition tls_util.h:28
apr_bucket_brigade * fout_tls_bb
Definition tls_filter.h:38
ap_filter_t * fin_ctx
Definition tls_filter.h:27
apr_bucket_brigade * fin_plain_bb
Definition tls_filter.h:30
apr_off_t fout_bytes_in_rustls
Definition tls_filter.h:39
apr_size_t fin_max_in_rustls
Definition tls_filter.h:42
tls_conf_conn_t * cc
Definition tls_filter.h:25
apr_read_type_e fin_block
Definition tls_filter.h:32
apr_size_t fout_buf_plain_len
Definition tls_filter.h:36
ap_filter_t * fout_ctx
Definition tls_filter.h:34
apr_size_t fout_max_in_rustls
Definition tls_filter.h:43
apr_bucket_brigade * fin_tls_buffer_bb
Definition tls_filter.h:29
char * fout_buf_plain
Definition tls_filter.h:35
apr_off_t fout_bytes_in_tls_bb
Definition tls_filter.h:40
conn_rec * c
Definition tls_filter.h:24
apr_size_t fout_buf_plain_size
Definition tls_filter.h:37
apr_off_t fin_bytes_in_rustls
Definition tls_filter.h:31
apr_size_t fout_auto_flush_size
Definition tls_filter.h:45
apr_bucket_brigade * fin_tls_bb
Definition tls_filter.h:28
apr_status_t tls_core_conn_post_handshake(conn_rec *c)
Definition tls_core.c:1257
apr_status_t tls_core_conn_init(conn_rec *c)
Definition tls_core.c:934
apr_status_t tls_core_error(conn_rec *c, rustls_result rr, const char **perrstr)
Definition tls_core.c:1384
int tls_core_pre_conn_init(conn_rec *c)
Definition tls_core.c:904
tls_conf_conn_t * tls_conf_conn_get(conn_rec *c)
Definition tls_core.c:45
apr_status_t tls_core_conn_seen_client_hello(conn_rec *c)
Definition tls_core.c:1186
tls_conn_state_t
Definition tls_core.h:21
@ TLS_CONN_ST_TRAFFIC
Definition tls_core.h:26
@ TLS_CONN_ST_NOTIFIED
Definition tls_core.h:27
@ TLS_CONN_ST_CLIENT_HELLO
Definition tls_core.h:24
@ TLS_CONN_ST_DONE
Definition tls_core.h:28
@ TLS_CONN_ST_HANDSHAKE
Definition tls_core.h:25
static apr_status_t filter_conn_input(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
Definition tls_filter.c:380
static rustls_io_result tls_write_vectored_callback(void *userdata, const rustls_iovec *riov, size_t count, size_t *out_n)
Definition tls_filter.c:547
static apr_status_t fout_add_bucket_to_tls(tls_filter_ctx_t *fctx, apr_bucket *b)
Definition tls_filter.c:720
static apr_status_t filter_conn_output(ap_filter_t *f, apr_bucket_brigade *bb)
Definition tls_filter.c:872
#define TLS_FILE_CHUNK_SIZE
static apr_status_t progress_tls_atleast_to(tls_filter_ctx_t *fctx, tls_conn_state_t state)
Definition tls_filter.c:314
static apr_status_t fout_pass_all_to_net(tls_filter_ctx_t *fctx, int flush)
Definition tls_filter.c:672
static apr_status_t filter_do_handshake(tls_filter_ctx_t *fctx)
Definition tls_filter.c:274
static apr_status_t filter_abort(tls_filter_ctx_t *fctx)
Definition tls_filter.c:181
void tls_filter_register(apr_pool_t *pool)
static apr_status_t read_tls_to_rustls(tls_filter_ctx_t *fctx, apr_size_t len, apr_read_type_e block, int errors_expected)
Definition tls_filter.c:63
static apr_status_t fout_pass_buf_to_rustls(tls_filter_ctx_t *fctx, const char *buf, apr_size_t len)
Definition tls_filter.c:614
static apr_status_t fout_pass_tls_to_net(tls_filter_ctx_t *fctx)
Definition tls_filter.c:163
static apr_status_t fout_pass_rustls_to_tls(tls_filter_ctx_t *fctx)
Definition tls_filter.c:576
static apr_status_t fout_append_plain(tls_filter_ctx_t *fctx, apr_bucket *b)
Definition tls_filter.c:738
static apr_status_t fout_add_bucket_to_plain(tls_filter_ctx_t *fctx, apr_bucket *b)
Definition tls_filter.c:687
void tls_filter_conn_init(conn_rec *c)
Definition tls_filter.c:989
static apr_status_t filter_send_client_hello(tls_filter_ctx_t *fctx)
Definition tls_filter.c:248
int tls_filter_pre_conn_init(conn_rec *c)
Definition tls_filter.c:927
#define TLS_WRITE_VECTORED
Definition tls_filter.c:569
static apr_status_t fout_pass_all_to_tls(tls_filter_ctx_t *fctx)
Definition tls_filter.c:654
static rustls_io_result tls_read_callback(void *userdata, unsigned char *buf, size_t n, size_t *out_n)
Definition tls_filter.c:40
static apr_status_t filter_recv_client_hello(tls_filter_ctx_t *fctx)
Definition tls_filter.c:198
static rustls_io_result tls_write_callback(void *userdata, const unsigned char *buf, size_t n, size_t *out_n)
Definition tls_filter.c:522
#define TLS_FILTER_RAW
Definition tls_filter.h:19
#define TLS_REC_MAX_SIZE
Definition tls_filter.h:88
#define TLS_PREF_PLAIN_CHUNK_SIZE
Definition tls_filter.h:76
apr_status_t tls_util_brigade_transfer(apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length, apr_off_t *pnout)
Definition tls_util.c:175
apr_status_t tls_util_brigade_copy(apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length, apr_off_t *pnout)
Definition tls_util.c:219
apr_status_t tls_util_brigade_split_line(apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_read_type_e block, apr_off_t length, apr_off_t *pnout)
Definition tls_util.c:265
#define tls_util_bb_log(c, level, tag, bb)
Definition tls_util.h:145
ap_input_mode_t
input filtering modes
Definition util_filter.h:41
@ AP_MODE_SPECULATIVE
Definition util_filter.h:53
@ AP_MODE_READBYTES
Definition util_filter.h:43
@ AP_MODE_INIT
Definition util_filter.h:62
@ AP_MODE_EXHAUSTIVE
Definition util_filter.h:58
@ AP_MODE_GETLINE
Definition util_filter.h:48