ssl_engine_io.c revision 5d92fff82718cd018f0b61a10b9ad4d2b8064c95
3802a3d3d7af51ddff31943d5514382f01265770Lennart Poettering/* Licensed to the Apache Software Foundation (ASF) under one or more
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * contributor license agreements. See the NOTICE file distributed with
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * this work for additional information regarding copyright ownership.
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * The ASF licenses this file to You under the Apache License, Version 2.0
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * (the "License"); you may not use this file except in compliance with
b975b0d514321f169b3c4599a8ea92e13741b4e4Zbigniew Jędrzejewski-Szmek * the License. You may obtain a copy of the License at
b975b0d514321f169b3c4599a8ea92e13741b4e4Zbigniew Jędrzejewski-Szmek * http://www.apache.org/licenses/LICENSE-2.0
b975b0d514321f169b3c4599a8ea92e13741b4e4Zbigniew Jędrzejewski-Szmek * Unless required by applicable law or agreed to in writing, software
b975b0d514321f169b3c4599a8ea92e13741b4e4Zbigniew Jędrzejewski-Szmek * distributed under the License is distributed on an "AS IS" BASIS,
b975b0d514321f169b3c4599a8ea92e13741b4e4Zbigniew Jędrzejewski-Szmek * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
b975b0d514321f169b3c4599a8ea92e13741b4e4Zbigniew Jędrzejewski-Szmek * See the License for the specific language governing permissions and
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * limitations under the License.
b975b0d514321f169b3c4599a8ea92e13741b4e4Zbigniew Jędrzejewski-Szmek * _ __ ___ ___ __| | ___ ___| | mod_ssl
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
b975b0d514321f169b3c4599a8ea92e13741b4e4Zbigniew Jędrzejewski-Szmek * | | | | | | (_) | (_| | \__ \__ \ |
b975b0d514321f169b3c4599a8ea92e13741b4e4Zbigniew Jędrzejewski-Szmek * |_| |_| |_|\___/ \__,_|___|___/___/_|
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek /* ``MY HACK: This universe.
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek Just one little problem:
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek core keeps dumping.''
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek/* _________________________________________________________________
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek** _________________________________________________________________
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek/* This file is designed to be the bridge between OpenSSL and httpd.
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * However, we really don't expect anyone (let alone ourselves) to
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * remember what is in this file. So, first, a quick overview.
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * In this file, you will find:
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * - ssl_io_filter_input (Apache input filter)
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * - ssl_io_filter_output (Apache output filter)
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * - bio_filter_in_* (OpenSSL input filter)
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * - bio_filter_out_* (OpenSSL output filter)
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * The input chain is roughly:
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * ssl_io_filter_input->ssl_io_input_read->SSL_read->...
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * ...->bio_filter_in_read->ap_get_brigade/next-httpd-filter
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * In mortal terminology, we do the following:
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * - Receive a request for data to the SSL input filter
847ae0ae7f29e7bfb245d692409fc2948eab7d1dLennart Poettering * - Call a helper function once we know we should perform a read
299a55075d1bf478b9190191caefd5c1b934340dMark Eichin * - Call OpenSSL's SSL_read()
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * - SSL_read() will then call bio_filter_in_read
3fde5f30bda2a70d97f3dc8fa918e42e1c07cc2cLennart Poettering * - bio_filter_in_read will then try to fetch data from the next httpd filter
299a55075d1bf478b9190191caefd5c1b934340dMark Eichin * - bio_filter_in_read will flatten that data and return it to SSL_read
299a55075d1bf478b9190191caefd5c1b934340dMark Eichin * - SSL_read will then decrypt the data
3fde5f30bda2a70d97f3dc8fa918e42e1c07cc2cLennart Poettering * - ssl_io_input_read will then receive decrypted data as a char* and
299a55075d1bf478b9190191caefd5c1b934340dMark Eichin * ensure that there were no read errors
3fde5f30bda2a70d97f3dc8fa918e42e1c07cc2cLennart Poettering * - The char* is placed in a brigade and returned
3fde5f30bda2a70d97f3dc8fa918e42e1c07cc2cLennart Poettering * Since connection-level input filters in httpd need to be able to
847ae0ae7f29e7bfb245d692409fc2948eab7d1dLennart Poettering * handle AP_MODE_GETLINE calls (namely identifying LF-terminated strings),
847ae0ae7f29e7bfb245d692409fc2948eab7d1dLennart Poettering * ssl_io_input_getline which will handle this special case.
847ae0ae7f29e7bfb245d692409fc2948eab7d1dLennart Poettering * Due to AP_MODE_GETLINE and AP_MODE_SPECULATIVE, we may sometimes have
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * 'leftover' decoded data which must be setaside for the next read. That
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * is currently handled by the char_buffer_{read|write} functions. So,
fbce11397f4d19821a9dfe66ee3ebe11cad90057Jan Engelhardt * ssl_io_input_read may be able to fulfill reads without invoking
847ae0ae7f29e7bfb245d692409fc2948eab7d1dLennart Poettering * Note that the filter context of ssl_io_filter_input and bio_filter_in_*
847ae0ae7f29e7bfb245d692409fc2948eab7d1dLennart Poettering * are shared as bio_filter_in_ctx_t.
847ae0ae7f29e7bfb245d692409fc2948eab7d1dLennart Poettering * Note that the filter is by choice limited to reading at most
847ae0ae7f29e7bfb245d692409fc2948eab7d1dLennart Poettering * AP_IOBUFSIZE (8192 bytes) per call.
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek/* this custom BIO allows us to hook SSL_write directly into
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * an apr_bucket_brigade and use transient buckets with the SSL
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * malloc-ed buffer, rather than copying into a mem BIO.
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * also allows us to pass the brigade as data is being written
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * rather than buffering up the entire response in the mem BIO.
3fde5f30bda2a70d97f3dc8fa918e42e1c07cc2cLennart Poettering * when SSL needs to flush (e.g. SSL_accept()), it will call BIO_flush()
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * which will trigger a call to bio_filter_out_ctrl() -> bio_filter_out_flush().
3fde5f30bda2a70d97f3dc8fa918e42e1c07cc2cLennart Poettering * so we only need to flush the output ourselves if we receive an
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * EOS or FLUSH bucket. this was not possible with the mem BIO where we
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek * had to flush all over the place not really knowing when it was required
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek int nobuffer; /* non-zero to prevent buffering */
3fde5f30bda2a70d97f3dc8fa918e42e1c07cc2cLennart Poettering apr_bucket_brigade *bb; /* Brigade used as a buffer. */
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmek apr_size_t length; /* Number of bytes stored in ->bb brigade. */
847ae0ae7f29e7bfb245d692409fc2948eab7d1dLennart Poettering char buffer[AP_IOBUFSIZE]; /* Fixed-size buffer */
847ae0ae7f29e7bfb245d692409fc2948eab7d1dLennart Poettering apr_size_t blen; /* Number of bytes of ->buffer used. */
d868475ad62547f0a034dfaf038aff31b3d05372Zbigniew Jędrzejewski-Szmekstatic bio_filter_out_ctx_t *bio_filter_out_ctx_new(ssl_filter_ctx_t *filter_ctx,
outctx->c = c;
return outctx;
apr_bucket *e;
return inl;
char **pptr;
switch (cmd) {
case BIO_CTRL_RESET:
case BIO_CTRL_EOF:
case BIO_CTRL_INFO:
if (ptr) {
case BIO_CTRL_GET_CLOSE:
case BIO_CTRL_SET_CLOSE:
case BIO_CTRL_PENDING:
ret = 0L;
case BIO_CTRL_WPENDING:
case BIO_CTRL_FLUSH:
case BIO_CTRL_DUP:
case BIO_C_SET_BUF_MEM:
case BIO_C_GET_BUF_MEM_PTR:
case BIO_CTRL_PUSH:
case BIO_CTRL_POP:
ret = 0;
return ret;
#ifdef OPENSSL_VERSION_NUMBER
int length;
char *value;
ap_filter_t *f;
return inl;
return inl;
const char *str;
if (APR_BUCKET_IS_EOS(b)) {
if (str_len > 0) {
c += consume;
else if (b->length == 0) {
return status;
if (!in)
inl);
return (int)inl;
return (int)inl;
return (int)inl;
#ifdef OPENSSL_VERSION_NUMBER
char *buf,
int rc;
*len = 0;
return APR_SUCCESS;
return APR_SUCCESS;
return APR_SUCCESS;
if (rc > 0) {
else if (rc == 0) {
if (*len > 0) {
if (*len > 0) {
if (*len > 0) {
if (*len > 0) {
char *buf,
*len = 0;
while (tmplen > 0) {
return status;
if (pos) {
char *value;
int length;
return APR_SUCCESS;
const char *data,
int res;
return APR_EGENERAL;
if (res < 0) {
conn_rec *c = f->c;
#define HTTP_ON_HTTPS_PORT \
switch (status) {
case MODSSL_ERROR_BAD_GATEWAY:
f->c->pool,
f->c->bucket_alloc);
return status;
return APR_SUCCESS;
int shutdown_type;
if (!ssl) {
if (abortive) {
shutdown_type = 0;
if (abortive) {
return APR_SUCCESS;
int ssl_err;
long verify_result;
return APR_SUCCESS;
const char *hostname_note;
return MODSSL_ERROR_BAD_GATEWAY;
if (!cert
if (cert) {
return HTTP_BAD_GATEWAY;
&& ((hostname_note =
const char *hostname;
return HTTP_BAD_GATEWAY;
return APR_SUCCESS;
* borrowed from openssl_state_machine.c [mod_tls].
return APR_EAGAIN;
return MODSSL_ERROR_HTTP_ON_HTTPS;
return APR_ECONNABORTED;
return APR_ECONNABORTED;
return APR_SUCCESS;
if (f->c->aborted) {
return APR_ECONNABORTED;
return APR_ENOTIMPL;
if (is_init) {
return APR_SUCCESS;
const char *pos;
if (len > 0) {
return APR_SUCCESS;
if (f->c->aborted) {
return APR_ECONNABORTED;
return status;
return status;
const char *data;
return status;
struct modssl_buffer_ctx {
if (rv) {
return HTTP_INTERNAL_SERVER_ERROR;
const char *data;
if (APR_BUCKET_IS_EOS(e)) {
} else if (!APR_BUCKET_IS_METADATA(e)) {
return HTTP_INTERNAL_SERVER_ERROR;
return HTTP_INTERNAL_SERVER_ERROR;
return HTTP_REQUEST_ENTITY_TOO_LARGE;
} while (!eos);
return APR_ENOTIMPL;
return APR_SUCCESS;
apr_bucket *e;
return rv;
e = APR_BUCKET_PREV(e);
if (rv) {
return rv;
return APR_SUCCESS;
filter_ctx, r, c);
long len)
unsigned char ch;
trunc = 0;
trunc++;
rows++;
for(i = 0 ; i< rows; i++) {
j = DUMP_WIDTH;
j = DUMP_WIDTH;
for (j = 0; j < DUMP_WIDTH; j++) {
for (j = 0; j < DUMP_WIDTH; j++) {
if (trunc > 0)
conn_rec *c;
server_rec *s;
return rc;
return rc;
s = mySrvFromConn(c);
if (rc >= 0) {
return rc;