ssl_engine_io.c revision 135402675e89e6df0e17735e48f428a1e1d8eb16
c330021bf3f45cbf187fa644781e67f7e470a58awrowe/* Licensed to the Apache Software Foundation (ASF) under one or more
7d5ac94fda90b837211dadf2585c0fe8c5dc3e5djerenkrantz * contributor license agreements. See the NOTICE file distributed with
c330021bf3f45cbf187fa644781e67f7e470a58awrowe * this work for additional information regarding copyright ownership.
ecf8d72af432e53e4c0661fb99dfda8061507bfajerenkrantz * The ASF licenses this file to You under the Apache License, Version 2.0
62f7716b14b71603a8004434ca3536902bfb8899wrowe * (the "License"); you may not use this file except in compliance with
62f7716b14b71603a8004434ca3536902bfb8899wrowe * the License. You may obtain a copy of the License at
c330021bf3f45cbf187fa644781e67f7e470a58awrowe * Unless required by applicable law or agreed to in writing, software
87d944bf70927764edf8ef69e46d3b4b8fa09131pquerna * distributed under the License is distributed on an "AS IS" BASIS,
87d944bf70927764edf8ef69e46d3b4b8fa09131pquerna * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
39dbd3f60b93f5e0fbf46d9ae237f6742e113442pquerna * See the License for the specific language governing permissions and
7e97354b25d4291fc5d89aabe22c2e1df05059efstriker * limitations under the License.
84cbf7ab5adeca6b94c462a46d74f17388b6ff6fjerenkrantz * _ __ ___ ___ __| | ___ ___| | mod_ssl
2a6c49cfaef5979a5a06098f3ce987cd76769409manoj * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
ecf8d72af432e53e4c0661fb99dfda8061507bfajerenkrantz * | | | | | | (_) | (_| | \__ \__ \ |
af4c982a7cf4515f124935f99a329744035fc699slive * |_| |_| |_|\___/ \__,_|___|___/___/_|
62f7716b14b71603a8004434ca3536902bfb8899wrowe * I/O Functions
62f7716b14b71603a8004434ca3536902bfb8899wrowe /* ``MY HACK: This universe.
62f7716b14b71603a8004434ca3536902bfb8899wrowe Just one little problem:
62f7716b14b71603a8004434ca3536902bfb8899wrowe core keeps dumping.''
af4c982a7cf4515f124935f99a329744035fc699slive -- Unknown */
2b8a78eefeba261ced96c3e57527d8ae3fce2f1aerikabele/* _________________________________________________________________
ecf8d72af432e53e4c0661fb99dfda8061507bfajerenkrantz** _________________________________________________________________
ecf8d72af432e53e4c0661fb99dfda8061507bfajerenkrantz/* This file is designed to be the bridge between OpenSSL and httpd.
ecf8d72af432e53e4c0661fb99dfda8061507bfajerenkrantz * However, we really don't expect anyone (let alone ourselves) to
ecf8d72af432e53e4c0661fb99dfda8061507bfajerenkrantz * remember what is in this file. So, first, a quick overview.
d96ee8cda2799e1f2743c1603adeb4833ed0e15fslive * In this file, you will find:
f610c7c704235bc327dbe9b62982f5b3f8e30a77wrowe * - ssl_io_filter_input (Apache input filter)
62f7716b14b71603a8004434ca3536902bfb8899wrowe * - ssl_io_filter_output (Apache output filter)
5ca8e11fadb6f7a8d9d0367c1800205c99d4bcd6jerenkrantz * - bio_filter_in_* (OpenSSL input filter)
62f7716b14b71603a8004434ca3536902bfb8899wrowe * - bio_filter_out_* (OpenSSL output filter)
dbec4658981e4f9127e8676457c28d42932be7cdtrawick * The input chain is roughly:
f6a9b598f78b2e745456bfc4bbc4afd2d1572aa9stas * ssl_io_filter_input->ssl_io_input_read->SSL_read->...
47c81da11264e8870b146dbdf3ac0384d3290ae9jerenkrantz * ...->bio_filter_in_read->ap_get_brigade/next-httpd-filter
0db0abcbe4211435c08e0c0e8f5daa278bed3524wsanchez * In mortal terminology, we do the following:
0db0abcbe4211435c08e0c0e8f5daa278bed3524wsanchez * - Receive a request for data to the SSL input filter
f6a9b598f78b2e745456bfc4bbc4afd2d1572aa9stas * - Call a helper function once we know we should perform a read
f6a9b598f78b2e745456bfc4bbc4afd2d1572aa9stas * - Call OpenSSL's SSL_read()
f6a9b598f78b2e745456bfc4bbc4afd2d1572aa9stas * - SSL_read() will then call bio_filter_in_read
0db0abcbe4211435c08e0c0e8f5daa278bed3524wsanchez * - bio_filter_in_read will then try to fetch data from the next httpd filter
47c81da11264e8870b146dbdf3ac0384d3290ae9jerenkrantz * - bio_filter_in_read will flatten that data and return it to SSL_read
0db0abcbe4211435c08e0c0e8f5daa278bed3524wsanchez * - SSL_read will then decrypt the data
d64eb0a76ec10c2405d14b892b0eb0f7ce27a613stas * - ssl_io_input_read will then receive decrypted data as a char* and
d64eb0a76ec10c2405d14b892b0eb0f7ce27a613stas * ensure that there were no read errors
d64eb0a76ec10c2405d14b892b0eb0f7ce27a613stas * - The char* is placed in a brigade and returned
62f7716b14b71603a8004434ca3536902bfb8899wrowe * Since connection-level input filters in httpd need to be able to
f4cb04eb78da02a38fcdd87489dc7b660107d55fjerenkrantz * handle AP_MODE_GETLINE calls (namely identifying LF-terminated strings),
f4cb04eb78da02a38fcdd87489dc7b660107d55fjerenkrantz * ssl_io_input_getline which will handle this special case.
f95a0b59eb24c631f15bd83e20c6cf823c432d83trawick * Due to AP_MODE_GETLINE and AP_MODE_SPECULATIVE, we may sometimes have
f95a0b59eb24c631f15bd83e20c6cf823c432d83trawick * 'leftover' decoded data which must be setaside for the next read. That
c95a8116bde20ab75f2e54d0e867bdf2e13643c3jim * is currently handled by the char_buffer_{read|write} functions. So,
b08ed1b8a8afa3d8466300f4607b9d1179d2f1eaerikabele * ssl_io_input_read may be able to fulfill reads without invoking
b08ed1b8a8afa3d8466300f4607b9d1179d2f1eaerikabele * SSL_read().
f95a0b59eb24c631f15bd83e20c6cf823c432d83trawick * Note that the filter context of ssl_io_filter_input and bio_filter_in_*
f95a0b59eb24c631f15bd83e20c6cf823c432d83trawick * are shared as bio_filter_in_ctx_t.
cc22a72861c58dda7f3768613aec864e4c4e0353striker * Note that the filter is by choice limited to reading at most
f95a0b59eb24c631f15bd83e20c6cf823c432d83trawick * AP_IOBUFSIZE (8192 bytes) per call.
0db0abcbe4211435c08e0c0e8f5daa278bed3524wsanchez/* this custom BIO allows us to hook SSL_write directly into
ddafc111b94558ef4e2d7357ceda623315566ce3slive * an apr_bucket_brigade and use transient buckets with the SSL
93f189f1198f539d3cfa75a15b23dcde60ee35ffrbb * malloc-ed buffer, rather than copying into a mem BIO.
93f189f1198f539d3cfa75a15b23dcde60ee35ffrbb * also allows us to pass the brigade as data is being written
bca5b27d271b6e1690134a83963424b9825d93bdstriker * rather than buffering up the entire response in the mem BIO.
b08ed1b8a8afa3d8466300f4607b9d1179d2f1eaerikabele * when SSL needs to flush (e.g. SSL_accept()), it will call BIO_flush()
13402b2193f52031b2acfbee2b0965e02f3f29b4wrowe * which will trigger a call to bio_filter_out_ctrl() -> bio_filter_out_flush().
13402b2193f52031b2acfbee2b0965e02f3f29b4wrowe * so we only need to flush the output ourselves if we receive an
38d2c5d41cdb5eb28668d0290b59f8c76ae2a4bfjim * EOS or FLUSH bucket. this was not possible with the mem BIO where we
38d2c5d41cdb5eb28668d0290b59f8c76ae2a4bfjim * had to flush all over the place not really knowing when it was required
38d2c5d41cdb5eb28668d0290b59f8c76ae2a4bfjim * to do so.
f4cb04eb78da02a38fcdd87489dc7b660107d55fjerenkrantztypedef struct {
f4cb04eb78da02a38fcdd87489dc7b660107d55fjerenkrantz int nobuffer; /* non-zero to prevent buffering */
38d2c5d41cdb5eb28668d0290b59f8c76ae2a4bfjimtypedef struct {
82455c2e3b6991846fbcbf0c9e41f57dbc681217brianpstatic bio_filter_out_ctx_t *bio_filter_out_ctx_new(ssl_filter_ctx_t *filter_ctx,
f4cb04eb78da02a38fcdd87489dc7b660107d55fjerenkrantz bio_filter_out_ctx_t *outctx = apr_palloc(c->pool, sizeof(*outctx));
d96ee8cda2799e1f2743c1603adeb4833ed0e15fslive outctx->bb = apr_brigade_create(c->pool, c->bucket_alloc);
0723420d6007137272f4f140ffd17035b17c1563nd bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
016f2545c9375ec7fc5e9cb70aa1ae0cace83c98jerenkrantz e = apr_bucket_transient_create(outctx->buffer, outctx->blen,
016f2545c9375ec7fc5e9cb70aa1ae0cace83c98jerenkrantz /* we filled this buffer first so add it to the
016f2545c9375ec7fc5e9cb70aa1ae0cace83c98jerenkrantz * head of the brigade
f610c7c704235bc327dbe9b62982f5b3f8e30a77wrowe e = apr_bucket_flush_create(outctx->bb->bucket_alloc);
f610c7c704235bc327dbe9b62982f5b3f8e30a77wrowe outctx->rc = ap_pass_brigade(outctx->filter_ctx->pOutputFilter->next,
f610c7c704235bc327dbe9b62982f5b3f8e30a77wrowe /* Fail if the connection was reset: */
f610c7c704235bc327dbe9b62982f5b3f8e30a77wrowe if (outctx->rc == APR_SUCCESS && outctx->c->aborted) {
4c7dab038d90d7feb67ef8ddbfacc77be8c9dbf0jwoolley /* nothing to free here.
4c7dab038d90d7feb67ef8ddbfacc77be8c9dbf0jwoolley * apache will destroy the bucket brigade for us
f9b8e29cfca92cf0a996e8ab17fa1a1f447cecc7stoddardstatic int bio_filter_out_read(BIO *bio, char *out, int outl)
f9b8e29cfca92cf0a996e8ab17fa1a1f447cecc7stoddard /* this is never called */
2fb49a1d25f38421a68d31b4cbb5d9293fdeafbewrowestatic int bio_filter_out_write(BIO *bio, const char *in, int inl)
2fb49a1d25f38421a68d31b4cbb5d9293fdeafbewrowe bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
2fb49a1d25f38421a68d31b4cbb5d9293fdeafbewrowe /* when handshaking we'll have a small number of bytes.
2fb49a1d25f38421a68d31b4cbb5d9293fdeafbewrowe * max size SSL will pass us here is about 16k.
2fb49a1d25f38421a68d31b4cbb5d9293fdeafbewrowe * (16413 bytes to be exact)
2fb49a1d25f38421a68d31b4cbb5d9293fdeafbewrowe if (!outctx->length && (inl + outctx->blen < sizeof(outctx->buffer)) &&
2fb49a1d25f38421a68d31b4cbb5d9293fdeafbewrowe /* the first two SSL_writes (of 1024 and 261 bytes)
2fb49a1d25f38421a68d31b4cbb5d9293fdeafbewrowe * need to be in the same packet (vec[0].iov_base)
2fb49a1d25f38421a68d31b4cbb5d9293fdeafbewrowe /* XXX: could use apr_brigade_write() to make code look cleaner
2fb49a1d25f38421a68d31b4cbb5d9293fdeafbewrowe * but this way we avoid the malloc(APR_BUCKET_BUFF_SIZE)
2fb49a1d25f38421a68d31b4cbb5d9293fdeafbewrowe * and free() of it later
db2d668e6233d8949b35ee7f9f42f444758f9ce9rbb /* pass along the encrypted data
db2d668e6233d8949b35ee7f9f42f444758f9ce9rbb * need to flush since we're using SSL's malloc-ed buffer
db2d668e6233d8949b35ee7f9f42f444758f9ce9rbb * which will be overwritten once we leave here
db2d668e6233d8949b35ee7f9f42f444758f9ce9rbb apr_bucket *bucket = apr_bucket_transient_create(in, inl,
0bcb1fe39dfaacf9745b6633f5cc9ebc8e2596caaaronstatic long bio_filter_out_ctrl(BIO *bio, int cmd, long num, void *ptr)
33f5961d34a8b5390cebad0543b3ebe67830e5d7jerenkrantz bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
48c0c81cd6fabac9d3386406d97633780365b839coar /* we don't care */
7fe18c15b669db9d191859695901dc4fcf3829dawrowestatic int bio_filter_out_gets(BIO *bio, char *buf, int size)
7fe18c15b669db9d191859695901dc4fcf3829dawrowe /* this is never called */
cc22a72861c58dda7f3768613aec864e4c4e0353strikerstatic int bio_filter_out_puts(BIO *bio, const char *str)
60d567a0c2aae815ee6fc20c0d65032bea52c92cwrowe /* this is never called */
2fb49a1d25f38421a68d31b4cbb5d9293fdeafbewrowe "APR output filter",
0bff2f28ef945280c17099c142126178a78e1e54manojtypedef struct {
e0427bf8e52a8fb920cb8b6adb5cdb3b6535b7fecoartypedef struct {
79d5106a9b65b956d646f5daae4b94bc79e315b8trawick * this char_buffer api might seem silly, but we don't need to copy
79d5106a9b65b956d646f5daae4b94bc79e315b8trawick * any of this data and we need to remember the length.
cf6bf6c34c936e6a6fe731dbce4a5c3c8bf8e9a3gsteinstatic int char_buffer_read(char_buffer_t *buffer, char *in, int inl)
14cccaddba3a9263cf0d0ddc311e18f3e3dc9b0fgstein /* we have have enough to fill the caller's buffer */
e636eba7474e0010b5c7198af1c2fe5ad8652dbbmanoj /* swallow remainder of the buffer */
60d567a0c2aae815ee6fc20c0d65032bea52c92cwrowestatic int char_buffer_write(char_buffer_t *buffer, char *in, int inl)
b3b4e853e4958357ee2d50e2fe41effecfde9eedwrowe/* This function will read from a brigade and discard the read buckets as it
27757f6699a924d4b493a1b6cceb27df27a43287dreid * proceeds. It will read at most *len bytes.
21e01f13f717faeca3e498d7d9c9b4d3af98ae27trawickstatic apr_status_t brigade_consume(apr_bucket_brigade *bb,
05cd8b63829a8a9047076ffbce8dd6cd1cb2db92thommay const char *str;
05cd8b63829a8a9047076ffbce8dd6cd1cb2db92thommay /* Justin points out this is an http-ism that might
05cd8b63829a8a9047076ffbce8dd6cd1cb2db92thommay * not fit if brigade_consume is added to APR. Perhaps
05cd8b63829a8a9047076ffbce8dd6cd1cb2db92thommay * apr_bucket_read(eos_bucket) should return APR_EOF?
9f95877e5e3f99a43eb6f3f632f87f144da3b8e6pquerna * Then this becomes mainline instead of a one-off.
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe /* The reason I'm not offering brigade_consume yet
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe * across to apr-util is that the following call
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe * illustrates how borked that API really is. For
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe * this sort of case (caller provided buffer) it
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe * would be much more trivial for apr_bucket_consume
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe * to do all the work that follows, based on the
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe * particular characteristics of the bucket we are
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe * consuming here.
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe /* This stream bucket was consumed */
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe /* Do not block once some data has been consumed */
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe /* Assure we don't overflow. */
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe consume = (str_len + actual > *len) ? *len - actual : str_len;
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe /* This physical bucket was consumed */
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe /* Only part of this physical bucket was consumed */
afbd720d176856630fed7c6576cdd3ae25a407edstoddard else if (b->length == 0) {
afbd720d176856630fed7c6576cdd3ae25a407edstoddard /* This could probably be actual == *len, but be safe from stray
28c4fe67d75f8f26504d75b7aa8dc5d868032888wrowe * photons. */
74def8815c725f8128a4e76ab1f5704df80b024ajerenkrantz * this is the function called by SSL_read()
74def8815c725f8128a4e76ab1f5704df80b024ajerenkrantzstatic int bio_filter_in_read(BIO *bio, char *in, int inlen)
ddd44b06b04507cae083c52451e28f54f0bdb5afstoddard bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)(bio->ptr);
ddd44b06b04507cae083c52451e28f54f0bdb5afstoddard /* OpenSSL catches this case, so should we. */
ddd44b06b04507cae083c52451e28f54f0bdb5afstoddard /* XXX: flush here only required for SSLv2;
ddd44b06b04507cae083c52451e28f54f0bdb5afstoddard * OpenSSL calls BIO_flush() at the appropriate times for
ddd44b06b04507cae083c52451e28f54f0bdb5afstoddard * the other protocols.
ddd44b06b04507cae083c52451e28f54f0bdb5afstoddard if ((SSL_version(inctx->ssl) == SSL2_VERSION) || sslconn->is_proxy) {
ec0315cdf832eac2b78e50ad636af84fe4c9118cgstein inctx->rc = ap_get_brigade(inctx->f->next, inctx->bb,
ec0315cdf832eac2b78e50ad636af84fe4c9118cgstein /* If the read returns EAGAIN or success with an empty
ec0315cdf832eac2b78e50ad636af84fe4c9118cgstein * brigade, return an error after setting the retry flag;
ec0315cdf832eac2b78e50ad636af84fe4c9118cgstein * SSL_read() will then return -1, and SSL_get_error() will
ec0315cdf832eac2b78e50ad636af84fe4c9118cgstein * indicate SSL_ERROR_WANT_READ. */
62f7716b14b71603a8004434ca3536902bfb8899wrowe if (APR_STATUS_IS_EAGAIN(inctx->rc) || APR_STATUS_IS_EINTR(inctx->rc)
62f7716b14b71603a8004434ca3536902bfb8899wrowe || (inctx->rc == APR_SUCCESS && APR_BRIGADE_EMPTY(inctx->bb))) {
62f7716b14b71603a8004434ca3536902bfb8899wrowe /* Unexpected errors discard the brigade */
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 HTTP_BAD_REQUEST:
return status;
return APR_SUCCESS;
conn_rec *c,
int abortive)
int shutdown_type;
if (!ssl) {
return APR_SUCCESS;
if (abortive) {
shutdown_type = 0;
if (abortive) {
return APR_SUCCESS;
return APR_SUCCESS;
int ssl_err;
long verify_result;
return APR_SUCCESS;
return HTTP_BAD_GATEWAY;
return APR_SUCCESS;
* borrowed from openssl_state_machine.c [mod_tls].
return SSL_ERROR_WANT_READ;
return HTTP_BAD_REQUEST;
return APR_SUCCESS;
const char *upgrade;
request_rec *r = f->r;
apr_bucket *b;
if (rv) {
return AP_FILTER_ERROR;
ssl_init_ssl_connection(f->c);
return AP_FILTER_ERROR;
if (f->c->aborted) {
return APR_ECONNABORTED;
return APR_ENOTIMPL;
if (is_init) {
return APR_SUCCESS;
return APR_ENOTIMPL;
if (len > 0) {
return APR_SUCCESS;
if (f->c->aborted) {
return APR_ECONNABORTED;
return status;
return status;
const char *data;
return status;
#ifndef SSL_MAX_IO_BUFFER
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;
apr_bucket *e;
return rv;
e = APR_BUCKET_PREV(e);
if (rv) {
return rv;
return APR_SUCCESS;
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 = c->base_server;
if (rc >= 0) {
return rc;