Blame buckets/ssl_buckets.c

Packit 3adb1e
/* ====================================================================
Packit 3adb1e
 *    Licensed to the Apache Software Foundation (ASF) under one
Packit 3adb1e
 *    or more contributor license agreements.  See the NOTICE file
Packit 3adb1e
 *    distributed with this work for additional information
Packit 3adb1e
 *    regarding copyright ownership.  The ASF licenses this file
Packit 3adb1e
 *    to you under the Apache License, Version 2.0 (the
Packit 3adb1e
 *    "License"); you may not use this file except in compliance
Packit 3adb1e
 *    with the License.  You may obtain a copy of the License at
Packit 3adb1e
 *
Packit 3adb1e
 *      http://www.apache.org/licenses/LICENSE-2.0
Packit 3adb1e
 *
Packit 3adb1e
 *    Unless required by applicable law or agreed to in writing,
Packit 3adb1e
 *    software distributed under the License is distributed on an
Packit 3adb1e
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
Packit 3adb1e
 *    KIND, either express or implied.  See the License for the
Packit 3adb1e
 *    specific language governing permissions and limitations
Packit 3adb1e
 *    under the License.
Packit 3adb1e
 * ====================================================================
Packit 3adb1e
 *
Packit 3adb1e
 * ----
Packit 3adb1e
 *
Packit 3adb1e
 * Originally developed by Aaron Bannert and Justin Erenkrantz, eBuilt.
Packit 3adb1e
 */
Packit 3adb1e
Packit 3adb1e
#include <apr_pools.h>
Packit 3adb1e
#include <apr_network_io.h>
Packit 3adb1e
#include <apr_portable.h>
Packit 3adb1e
#include <apr_strings.h>
Packit 3adb1e
#include <apr_base64.h>
Packit 3adb1e
#include <apr_version.h>
Packit 3adb1e
#include <apr_atomic.h>
Packit 3adb1e
Packit 3adb1e
#include "serf.h"
Packit 3adb1e
#include "serf_private.h"
Packit 3adb1e
#include "serf_bucket_util.h"
Packit 3adb1e
Packit 3adb1e
#include <openssl/bio.h>
Packit 3adb1e
#include <openssl/ssl.h>
Packit 3adb1e
#include <openssl/err.h>
Packit 3adb1e
#include <openssl/pkcs12.h>
Packit 3adb1e
#include <openssl/x509v3.h>
Packit 3adb1e
Packit 3adb1e
#ifndef APR_VERSION_AT_LEAST /* Introduced in APR 1.3.0 */
Packit 3adb1e
#define APR_VERSION_AT_LEAST(major,minor,patch)                           \
Packit 3adb1e
    (((major) < APR_MAJOR_VERSION)                                        \
Packit 3adb1e
      || ((major) == APR_MAJOR_VERSION && (minor) < APR_MINOR_VERSION)    \
Packit 3adb1e
      || ((major) == APR_MAJOR_VERSION && (minor) == APR_MINOR_VERSION && \
Packit 3adb1e
               (patch) <= APR_PATCH_VERSION))
Packit 3adb1e
#endif /* APR_VERSION_AT_LEAST */
Packit 3adb1e
Packit 3adb1e
#ifndef APR_ARRAY_PUSH
Packit 3adb1e
#define APR_ARRAY_PUSH(ary,type) (*((type *)apr_array_push(ary)))
Packit 3adb1e
#endif
Packit 3adb1e
Packit 3adb1e
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L
Packit 3adb1e
#define USE_OPENSSL_1_1_API
Packit 3adb1e
#endif
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
/*
Packit 3adb1e
 * Here's an overview of the SSL bucket's relationship to OpenSSL and serf.
Packit 3adb1e
 *
Packit 3adb1e
 * HTTP request:  SSLENCRYPT(REQUEST)
Packit 3adb1e
 *   [context.c reads from SSLENCRYPT and writes out to the socket]
Packit 3adb1e
 * HTTP response: RESPONSE(SSLDECRYPT(SOCKET))
Packit 3adb1e
 *   [handler function reads from RESPONSE which in turn reads from SSLDECRYPT]
Packit 3adb1e
 *
Packit 3adb1e
 * HTTP request read call path:
Packit 3adb1e
 *
Packit 3adb1e
 * write_to_connection
Packit 3adb1e
 *  |- serf_bucket_read on SSLENCRYPT
Packit 3adb1e
 *    |- serf_ssl_read
Packit 3adb1e
 *      |- serf_databuf_read
Packit 3adb1e
 *        |- common_databuf_prep
Packit 3adb1e
 *          |- ssl_encrypt
Packit 3adb1e
 *            |- 1. Try to read pending encrypted data; If available, return.
Packit 3adb1e
 *            |- 2. Try to read from ctx->stream [REQUEST bucket]
Packit 3adb1e
 *            |- 3. Call SSL_write with read data
Packit 3adb1e
 *              |- ...
Packit 3adb1e
 *                |- bio_bucket_read can be called
Packit 3adb1e
 *                |- bio_bucket_write with encrypted data
Packit 3adb1e
 *                  |- store in sink
Packit 3adb1e
 *            |- 4. If successful, read pending encrypted data and return.
Packit 3adb1e
 *            |- 5. If fails, place read data back in ctx->stream
Packit 3adb1e
 *
Packit 3adb1e
 * HTTP response read call path:
Packit 3adb1e
 *
Packit 3adb1e
 * read_from_connection
Packit 3adb1e
 *  |- acceptor
Packit 3adb1e
 *  |- handler
Packit 3adb1e
 *    |- ...
Packit 3adb1e
 *      |- serf_bucket_read(SSLDECRYPT)
Packit 3adb1e
 *        |- serf_ssl_read
Packit 3adb1e
 *          |- serf_databuf_read
Packit 3adb1e
 *            |- ssl_decrypt
Packit 3adb1e
 *              |- 1. SSL_read() for pending decrypted data; if any, return.
Packit 3adb1e
 *              |- 2. Try to read from ctx->stream [SOCKET bucket]
Packit 3adb1e
 *              |- 3. Append data to ssl_ctx->source
Packit 3adb1e
 *              |- 4. Call SSL_read()
Packit 3adb1e
 *                |- ...
Packit 3adb1e
 *                  |- bio_bucket_write can be called
Packit 3adb1e
 *                  |- bio_bucket_read
Packit 3adb1e
 *                    |- read data from ssl_ctx->source
Packit 3adb1e
 *              |- If data read, return it.
Packit 3adb1e
 *              |- If an error, set the STATUS value and return.
Packit 3adb1e
 *
Packit 3adb1e
 */
Packit 3adb1e
Packit 3adb1e
typedef struct bucket_list {
Packit 3adb1e
    serf_bucket_t *bucket;
Packit 3adb1e
    struct bucket_list *next;
Packit 3adb1e
} bucket_list_t;
Packit 3adb1e
Packit 3adb1e
typedef struct {
Packit 3adb1e
    /* Helper to read data. Wraps stream. */
Packit 3adb1e
    serf_databuf_t databuf;
Packit 3adb1e
Packit 3adb1e
    /* Our source for more data. */
Packit 3adb1e
    serf_bucket_t *stream;
Packit 3adb1e
Packit 3adb1e
    /* The next set of buckets */
Packit 3adb1e
    bucket_list_t *stream_next;
Packit 3adb1e
Packit 3adb1e
    /* The status of the last thing we read. */
Packit 3adb1e
    apr_status_t status;
Packit 3adb1e
    apr_status_t exhausted;
Packit 3adb1e
    int exhausted_reset;
Packit 3adb1e
Packit 3adb1e
    /* Data we've read but not processed. */
Packit 3adb1e
    serf_bucket_t *pending;
Packit 3adb1e
} serf_ssl_stream_t;
Packit 3adb1e
Packit 3adb1e
struct serf_ssl_context_t {
Packit 3adb1e
    /* How many open buckets refer to this context. */
Packit 3adb1e
    int refcount;
Packit 3adb1e
Packit 3adb1e
    /* The pool that this context uses. */
Packit 3adb1e
    apr_pool_t *pool;
Packit 3adb1e
Packit 3adb1e
    /* The allocator associated with the above pool. */
Packit 3adb1e
    serf_bucket_alloc_t *allocator;
Packit 3adb1e
Packit 3adb1e
    /* Internal OpenSSL parameters */
Packit 3adb1e
    SSL_CTX *ctx;
Packit 3adb1e
    SSL *ssl;
Packit 3adb1e
    BIO *bio;
Packit 3adb1e
    BIO_METHOD *biom;
Packit 3adb1e
Packit 3adb1e
    serf_ssl_stream_t encrypt;
Packit 3adb1e
    serf_ssl_stream_t decrypt;
Packit 3adb1e
Packit 3adb1e
    /* Client cert callbacks */
Packit 3adb1e
    serf_ssl_need_client_cert_t cert_callback;
Packit 3adb1e
    void *cert_userdata;
Packit 3adb1e
    apr_pool_t *cert_cache_pool;
Packit 3adb1e
    const char *cert_file_success;
Packit 3adb1e
Packit 3adb1e
    /* Client cert PW callbacks */
Packit 3adb1e
    serf_ssl_need_cert_password_t cert_pw_callback;
Packit 3adb1e
    void *cert_pw_userdata;
Packit 3adb1e
    apr_pool_t *cert_pw_cache_pool;
Packit 3adb1e
    const char *cert_pw_success;
Packit 3adb1e
Packit 3adb1e
    /* Server cert callbacks */
Packit 3adb1e
    serf_ssl_need_server_cert_t server_cert_callback;
Packit 3adb1e
    serf_ssl_server_cert_chain_cb_t server_cert_chain_callback;
Packit 3adb1e
    void *server_cert_userdata;
Packit 3adb1e
Packit 3adb1e
    const char *cert_path;
Packit 3adb1e
Packit 3adb1e
    X509 *cached_cert;
Packit 3adb1e
    EVP_PKEY *cached_cert_pw;
Packit 3adb1e
Packit 3adb1e
    apr_status_t pending_err;
Packit 3adb1e
Packit 3adb1e
    /* Status of a fatal error, returned on subsequent encrypt or decrypt
Packit 3adb1e
       requests. */
Packit 3adb1e
    apr_status_t fatal_err;
Packit 3adb1e
};
Packit 3adb1e
Packit 3adb1e
typedef struct {
Packit 3adb1e
    /* The bucket-independent ssl context that this bucket is associated with */
Packit 3adb1e
    serf_ssl_context_t *ssl_ctx;
Packit 3adb1e
Packit 3adb1e
    /* Pointer to the 'right' databuf. */
Packit 3adb1e
    serf_databuf_t *databuf;
Packit 3adb1e
Packit 3adb1e
    /* Pointer to our stream, so we can find it later. */
Packit 3adb1e
    serf_bucket_t **our_stream;
Packit 3adb1e
} ssl_context_t;
Packit 3adb1e
Packit 3adb1e
struct serf_ssl_certificate_t {
Packit 3adb1e
    X509 *ssl_cert;
Packit 3adb1e
    int depth;
Packit 3adb1e
};
Packit 3adb1e
Packit 3adb1e
static void disable_compression(serf_ssl_context_t *ssl_ctx);
Packit 3adb1e
static char *
Packit 3adb1e
    pstrdup_escape_nul_bytes(const char *buf, int len, apr_pool_t *pool);
Packit 3adb1e
Packit 3adb1e
#if SSL_VERBOSE
Packit 3adb1e
/* Log all ssl alerts that we receive from the server. */
Packit 3adb1e
static void
Packit 3adb1e
apps_ssl_info_callback(const SSL *s, int where, int ret)
Packit 3adb1e
{
Packit 3adb1e
    const char *str;
Packit 3adb1e
    int w;
Packit 3adb1e
    w = where & ~SSL_ST_MASK;
Packit 3adb1e
Packit 3adb1e
    if (w & SSL_ST_CONNECT)
Packit 3adb1e
        str = "SSL_connect";
Packit 3adb1e
    else if (w & SSL_ST_ACCEPT)
Packit 3adb1e
        str = "SSL_accept";
Packit 3adb1e
    else
Packit 3adb1e
        str = "undefined";
Packit 3adb1e
Packit 3adb1e
    if (where & SSL_CB_LOOP) {
Packit 3adb1e
        serf__log(SSL_VERBOSE, __FILE__, "%s:%s\n", str,
Packit 3adb1e
                  SSL_state_string_long(s));
Packit 3adb1e
    }
Packit 3adb1e
    else if (where & SSL_CB_ALERT) {
Packit 3adb1e
        str = (where & SSL_CB_READ) ? "read" : "write";
Packit 3adb1e
        serf__log(SSL_VERBOSE, __FILE__, "SSL3 alert %s:%s:%s\n",
Packit 3adb1e
               str,
Packit 3adb1e
               SSL_alert_type_string_long(ret),
Packit 3adb1e
               SSL_alert_desc_string_long(ret));
Packit 3adb1e
    }
Packit 3adb1e
    else if (where & SSL_CB_EXIT) {
Packit 3adb1e
        if (ret == 0)
Packit 3adb1e
            serf__log(SSL_VERBOSE, __FILE__, "%s:failed in %s\n", str,
Packit 3adb1e
                      SSL_state_string_long(s));
Packit 3adb1e
        else if (ret < 0) {
Packit 3adb1e
            serf__log(SSL_VERBOSE, __FILE__, "%s:error in %s\n", str,
Packit 3adb1e
                      SSL_state_string_long(s));
Packit 3adb1e
        }
Packit 3adb1e
    }
Packit 3adb1e
}
Packit 3adb1e
#endif
Packit 3adb1e
Packit 3adb1e
static void bio_set_data(BIO *bio, void *data)
Packit 3adb1e
{
Packit 3adb1e
#ifdef USE_OPENSSL_1_1_API
Packit 3adb1e
    BIO_set_data(bio, data);
Packit 3adb1e
#else
Packit 3adb1e
    bio->ptr = data;
Packit 3adb1e
#endif
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static void *bio_get_data(BIO *bio)
Packit 3adb1e
{
Packit 3adb1e
#ifdef USE_OPENSSL_1_1_API
Packit 3adb1e
    return BIO_get_data(bio);
Packit 3adb1e
#else
Packit 3adb1e
    return bio->ptr;
Packit 3adb1e
#endif
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
/* Returns the amount read. */
Packit 3adb1e
static int bio_bucket_read(BIO *bio, char *in, int inlen)
Packit 3adb1e
{
Packit 3adb1e
    serf_ssl_context_t *ctx = bio_get_data(bio);
Packit 3adb1e
    const char *data;
Packit 3adb1e
    apr_status_t status;
Packit 3adb1e
    apr_size_t len;
Packit 3adb1e
Packit 3adb1e
    serf__log(SSL_VERBOSE, __FILE__, "bio_bucket_read called for %d bytes\n",
Packit 3adb1e
              inlen);
Packit 3adb1e
Packit 3adb1e
    if (ctx->encrypt.status == SERF_ERROR_WAIT_CONN
Packit 3adb1e
        && BIO_should_read(ctx->bio)) {
Packit 3adb1e
        serf__log(SSL_VERBOSE, __FILE__,
Packit 3adb1e
                  "bio_bucket_read waiting: (%d %d %d)\n",
Packit 3adb1e
           BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
Packit 3adb1e
           BIO_get_retry_flags(ctx->bio));
Packit 3adb1e
        /* Falling back... */
Packit 3adb1e
        ctx->encrypt.exhausted_reset = 1;
Packit 3adb1e
        BIO_clear_retry_flags(bio);
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    status = serf_bucket_read(ctx->decrypt.pending, inlen, &data, &len;;
Packit 3adb1e
Packit 3adb1e
    ctx->decrypt.status = status;
Packit 3adb1e
Packit 3adb1e
    serf__log(SSL_VERBOSE, __FILE__, "bio_bucket_read received %d bytes (%d)\n",
Packit 3adb1e
              len, status);
Packit 3adb1e
Packit 3adb1e
    if (!SERF_BUCKET_READ_ERROR(status)) {
Packit 3adb1e
        /* Oh suck. */
Packit 3adb1e
        if (len) {
Packit 3adb1e
            memcpy(in, data, len);
Packit 3adb1e
            return len;
Packit 3adb1e
        }
Packit 3adb1e
        if (APR_STATUS_IS_EOF(status)) {
Packit 3adb1e
            BIO_set_retry_read(bio);
Packit 3adb1e
            return -1;
Packit 3adb1e
        }
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    return -1;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
/* Returns the amount written. */
Packit 3adb1e
static int bio_bucket_write(BIO *bio, const char *in, int inl)
Packit 3adb1e
{
Packit 3adb1e
    serf_ssl_context_t *ctx = bio_get_data(bio);
Packit 3adb1e
    serf_bucket_t *tmp;
Packit 3adb1e
Packit 3adb1e
    serf__log(SSL_VERBOSE, __FILE__, "bio_bucket_write called for %d bytes\n",
Packit 3adb1e
              inl);
Packit 3adb1e
Packit 3adb1e
    if (ctx->encrypt.status == SERF_ERROR_WAIT_CONN
Packit 3adb1e
        && !BIO_should_read(ctx->bio)) {
Packit 3adb1e
        serf__log(SSL_VERBOSE, __FILE__,
Packit 3adb1e
                  "bio_bucket_write waiting: (%d %d %d)\n",
Packit 3adb1e
           BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
Packit 3adb1e
           BIO_get_retry_flags(ctx->bio));
Packit 3adb1e
        /* Falling back... */
Packit 3adb1e
        ctx->encrypt.exhausted_reset = 1;
Packit 3adb1e
        BIO_clear_retry_flags(bio);
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    tmp = serf_bucket_simple_copy_create(in, inl,
Packit 3adb1e
                                         ctx->encrypt.pending->allocator);
Packit 3adb1e
Packit 3adb1e
    serf_bucket_aggregate_append(ctx->encrypt.pending, tmp);
Packit 3adb1e
Packit 3adb1e
    return inl;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
/* Returns the amount read. */
Packit 3adb1e
static int bio_file_read(BIO *bio, char *in, int inlen)
Packit 3adb1e
{
Packit 3adb1e
    apr_file_t *file = bio_get_data(bio);
Packit 3adb1e
    apr_status_t status;
Packit 3adb1e
    apr_size_t len;
Packit 3adb1e
Packit 3adb1e
    len = inlen;
Packit 3adb1e
    status = apr_file_read(file, in, &len;;
Packit 3adb1e
Packit 3adb1e
    if (!SERF_BUCKET_READ_ERROR(status)) {
Packit 3adb1e
        /* Oh suck. */
Packit 3adb1e
        if (APR_STATUS_IS_EOF(status)) {
Packit 3adb1e
            return -1;
Packit 3adb1e
        } else {
Packit 3adb1e
            return len;
Packit 3adb1e
        }
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    return -1;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
/* Returns the amount written. */
Packit 3adb1e
static int bio_file_write(BIO *bio, const char *in, int inl)
Packit 3adb1e
{
Packit 3adb1e
    apr_file_t *file = bio_get_data(bio);
Packit 3adb1e
    apr_size_t nbytes;
Packit 3adb1e
Packit 3adb1e
    BIO_clear_retry_flags(bio);
Packit 3adb1e
Packit 3adb1e
    nbytes = inl;
Packit 3adb1e
    apr_file_write(file, in, &nbytes);
Packit 3adb1e
Packit 3adb1e
    return nbytes;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static int bio_file_gets(BIO *bio, char *in, int inlen)
Packit 3adb1e
{
Packit 3adb1e
    apr_file_t *file = bio_get_data(bio);
Packit 3adb1e
    apr_status_t status;
Packit 3adb1e
Packit 3adb1e
    status = apr_file_gets(in, inlen, file);
Packit 3adb1e
Packit 3adb1e
    if (! status) {
Packit 3adb1e
        return (int)strlen(in);
Packit 3adb1e
    } else if (APR_STATUS_IS_EOF(status)) {
Packit 3adb1e
        return 0;
Packit 3adb1e
    } else {
Packit 3adb1e
        return -1; /* Signal generic error */
Packit 3adb1e
    }
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static int bio_bucket_create(BIO *bio)
Packit 3adb1e
{
Packit 3adb1e
#ifdef USE_OPENSSL_1_1_API
Packit 3adb1e
    BIO_set_shutdown(bio, 1);
Packit 3adb1e
    BIO_set_init(bio, 1);
Packit 3adb1e
    BIO_set_data(bio, NULL);
Packit 3adb1e
#else
Packit 3adb1e
    bio->shutdown = 1;
Packit 3adb1e
    bio->init = 1;
Packit 3adb1e
    bio->num = -1;
Packit 3adb1e
    bio->ptr = NULL;
Packit 3adb1e
#endif
Packit 3adb1e
Packit 3adb1e
    return 1;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static int bio_bucket_destroy(BIO *bio)
Packit 3adb1e
{
Packit 3adb1e
    /* Did we already free this? */
Packit 3adb1e
    if (bio == NULL) {
Packit 3adb1e
        return 0;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    return 1;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static long bio_bucket_ctrl(BIO *bio, int cmd, long num, void *ptr)
Packit 3adb1e
{
Packit 3adb1e
    long ret = 1;
Packit 3adb1e
Packit 3adb1e
    switch (cmd) {
Packit 3adb1e
    default:
Packit 3adb1e
        /* abort(); */
Packit 3adb1e
        break;
Packit 3adb1e
    case BIO_CTRL_FLUSH:
Packit 3adb1e
        /* At this point we can't force a flush. */
Packit 3adb1e
        break;
Packit 3adb1e
    case BIO_CTRL_PUSH:
Packit 3adb1e
    case BIO_CTRL_POP:
Packit 3adb1e
        ret = 0;
Packit 3adb1e
        break;
Packit 3adb1e
    }
Packit 3adb1e
    return ret;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
#ifndef USE_OPENSSL_1_1_API
Packit 3adb1e
static BIO_METHOD bio_bucket_method = {
Packit 3adb1e
    BIO_TYPE_MEM,
Packit 3adb1e
    "Serf SSL encryption and decryption buckets",
Packit 3adb1e
    bio_bucket_write,
Packit 3adb1e
    bio_bucket_read,
Packit 3adb1e
    NULL,                        /* Is this called? */
Packit 3adb1e
    NULL,                        /* Is this called? */
Packit 3adb1e
    bio_bucket_ctrl,
Packit 3adb1e
    bio_bucket_create,
Packit 3adb1e
    bio_bucket_destroy,
Packit 3adb1e
#ifdef OPENSSL_VERSION_NUMBER
Packit 3adb1e
    NULL /* sslc does not have the callback_ctrl field */
Packit 3adb1e
#endif
Packit 3adb1e
};
Packit 3adb1e
Packit 3adb1e
static BIO_METHOD bio_file_method = {
Packit 3adb1e
    BIO_TYPE_FILE,
Packit 3adb1e
    "Wrapper around APR file structures",
Packit 3adb1e
    bio_file_write,
Packit 3adb1e
    bio_file_read,
Packit 3adb1e
    NULL,                        /* Is this called? */
Packit 3adb1e
    bio_file_gets,               /* Is this called? */
Packit 3adb1e
    bio_bucket_ctrl,
Packit 3adb1e
    bio_bucket_create,
Packit 3adb1e
    bio_bucket_destroy,
Packit 3adb1e
#ifdef OPENSSL_VERSION_NUMBER
Packit 3adb1e
    NULL /* sslc does not have the callback_ctrl field */
Packit 3adb1e
#endif
Packit 3adb1e
};
Packit 3adb1e
#endif
Packit 3adb1e
Packit 3adb1e
static BIO_METHOD *bio_meth_bucket_new(void)
Packit 3adb1e
{
Packit 3adb1e
    BIO_METHOD *biom = NULL;
Packit 3adb1e
Packit 3adb1e
#ifdef USE_OPENSSL_1_1_API
Packit 3adb1e
    biom = BIO_meth_new(BIO_TYPE_MEM,
Packit 3adb1e
                        "Serf SSL encryption and decryption buckets");
Packit 3adb1e
    if (biom) {
Packit 3adb1e
        BIO_meth_set_write(biom, bio_bucket_write);
Packit 3adb1e
        BIO_meth_set_read(biom, bio_bucket_read);
Packit 3adb1e
        BIO_meth_set_ctrl(biom, bio_bucket_ctrl);
Packit 3adb1e
        BIO_meth_set_create(biom, bio_bucket_create);
Packit 3adb1e
        BIO_meth_set_destroy(biom, bio_bucket_destroy);
Packit 3adb1e
    }
Packit 3adb1e
#else
Packit 3adb1e
    biom = &bio_bucket_method;
Packit 3adb1e
#endif
Packit 3adb1e
Packit 3adb1e
    return biom;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static BIO_METHOD *bio_meth_file_new(void)
Packit 3adb1e
{
Packit 3adb1e
    BIO_METHOD *biom = NULL;
Packit 3adb1e
Packit 3adb1e
#ifdef USE_OPENSSL_1_1_API
Packit 3adb1e
    biom = BIO_meth_new(BIO_TYPE_FILE,
Packit 3adb1e
                        "Wrapper around APR file structures");
Packit 3adb1e
    BIO_meth_set_write(biom, bio_file_write);
Packit 3adb1e
    BIO_meth_set_read(biom, bio_file_read);
Packit 3adb1e
    BIO_meth_set_gets(biom, bio_file_gets);
Packit 3adb1e
    BIO_meth_set_ctrl(biom, bio_bucket_ctrl);
Packit 3adb1e
    BIO_meth_set_create(biom, bio_bucket_create);
Packit 3adb1e
    BIO_meth_set_destroy(biom, bio_bucket_destroy);
Packit 3adb1e
#else
Packit 3adb1e
    biom = &bio_file_method;
Packit 3adb1e
#endif
Packit 3adb1e
Packit 3adb1e
    return biom;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static void bio_meth_free(BIO_METHOD *biom)
Packit 3adb1e
{
Packit 3adb1e
#ifdef USE_OPENSSL_1_1_API
Packit 3adb1e
    BIO_meth_free(biom);
Packit 3adb1e
#endif
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
typedef enum san_copy_t {
Packit 3adb1e
    EscapeNulAndCopy = 0,
Packit 3adb1e
    ErrorOnNul = 1,
Packit 3adb1e
} san_copy_t;
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
static apr_status_t
Packit 3adb1e
get_subject_alt_names(apr_array_header_t **san_arr, X509 *ssl_cert,
Packit 3adb1e
                      san_copy_t copy_action, apr_pool_t *pool)
Packit 3adb1e
{
Packit 3adb1e
    STACK_OF(GENERAL_NAME) *names;
Packit 3adb1e
Packit 3adb1e
    /* assert: copy_action == ErrorOnNul || (san_arr && pool) */
Packit 3adb1e
Packit 3adb1e
    if (san_arr) {
Packit 3adb1e
        *san_arr = NULL;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    /* Get subjectAltNames */
Packit 3adb1e
    names = X509_get_ext_d2i(ssl_cert, NID_subject_alt_name, NULL, NULL);
Packit 3adb1e
    if (names) {
Packit 3adb1e
        int names_count = sk_GENERAL_NAME_num(names);
Packit 3adb1e
        int name_idx;
Packit 3adb1e
Packit 3adb1e
        if (san_arr)
Packit 3adb1e
            *san_arr = apr_array_make(pool, names_count, sizeof(char*));
Packit 3adb1e
        for (name_idx = 0; name_idx < names_count; name_idx++) {
Packit 3adb1e
            char *p = NULL;
Packit 3adb1e
            GENERAL_NAME *nm = sk_GENERAL_NAME_value(names, name_idx);
Packit 3adb1e
Packit 3adb1e
            switch (nm->type) {
Packit 3adb1e
                case GEN_DNS:
Packit 3adb1e
                    if (copy_action == ErrorOnNul &&
Packit 3adb1e
                        strlen(nm->d.ia5->data) != nm->d.ia5->length)
Packit 3adb1e
                        return SERF_ERROR_SSL_CERT_FAILED;
Packit 3adb1e
                    if (san_arr && *san_arr)
Packit 3adb1e
                        p = pstrdup_escape_nul_bytes((const char *)nm->d.ia5->data,
Packit 3adb1e
                                                     nm->d.ia5->length,
Packit 3adb1e
                                                     pool);
Packit 3adb1e
                    break;
Packit 3adb1e
                default:
Packit 3adb1e
                    /* Don't know what to do - skip. */
Packit 3adb1e
                    break;
Packit 3adb1e
            }
Packit 3adb1e
Packit 3adb1e
            if (p) {
Packit 3adb1e
                APR_ARRAY_PUSH(*san_arr, char*) = p;
Packit 3adb1e
            }
Packit 3adb1e
        }
Packit 3adb1e
        sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
Packit 3adb1e
    }
Packit 3adb1e
    
Packit 3adb1e
    return APR_SUCCESS;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static apr_status_t validate_cert_hostname(X509 *server_cert, apr_pool_t *pool)
Packit 3adb1e
{
Packit 3adb1e
    char buf[1024];
Packit 3adb1e
    int length;
Packit 3adb1e
    apr_status_t ret;
Packit 3adb1e
Packit 3adb1e
    ret = get_subject_alt_names(NULL, server_cert, ErrorOnNul, NULL);
Packit 3adb1e
    if (ret) {
Packit 3adb1e
      return ret;
Packit 3adb1e
    } else {
Packit 3adb1e
        /* Fail if the subject's CN field contains \0 characters. */
Packit 3adb1e
        X509_NAME *subject = X509_get_subject_name(server_cert);
Packit 3adb1e
        if (!subject)
Packit 3adb1e
            return SERF_ERROR_SSL_CERT_FAILED;
Packit 3adb1e
Packit 3adb1e
        length = X509_NAME_get_text_by_NID(subject, NID_commonName, buf, 1024);
Packit 3adb1e
        if (length != -1)
Packit 3adb1e
            if (strlen(buf) != length)
Packit 3adb1e
                return SERF_ERROR_SSL_CERT_FAILED;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    return APR_SUCCESS;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static int
Packit 3adb1e
validate_server_certificate(int cert_valid, X509_STORE_CTX *store_ctx)
Packit 3adb1e
{
Packit 3adb1e
    SSL *ssl;
Packit 3adb1e
    serf_ssl_context_t *ctx;
Packit 3adb1e
    X509 *server_cert;
Packit 3adb1e
    int err, depth;
Packit 3adb1e
    int failures = 0;
Packit 3adb1e
    apr_status_t status;
Packit 3adb1e
Packit 3adb1e
    ssl = X509_STORE_CTX_get_ex_data(store_ctx,
Packit 3adb1e
                                     SSL_get_ex_data_X509_STORE_CTX_idx());
Packit 3adb1e
    ctx = SSL_get_app_data(ssl);
Packit 3adb1e
Packit 3adb1e
    server_cert = X509_STORE_CTX_get_current_cert(store_ctx);
Packit 3adb1e
    depth = X509_STORE_CTX_get_error_depth(store_ctx);
Packit 3adb1e
Packit 3adb1e
    /* If the certification was found invalid, get the error and convert it to
Packit 3adb1e
       something our caller will understand. */
Packit 3adb1e
    if (! cert_valid) {
Packit 3adb1e
        err = X509_STORE_CTX_get_error(store_ctx);
Packit 3adb1e
Packit 3adb1e
        switch(err) {
Packit 3adb1e
            case X509_V_ERR_CERT_NOT_YET_VALID: 
Packit 3adb1e
                    failures |= SERF_SSL_CERT_NOTYETVALID;
Packit 3adb1e
                    break;
Packit 3adb1e
            case X509_V_ERR_CERT_HAS_EXPIRED:
Packit 3adb1e
                    failures |= SERF_SSL_CERT_EXPIRED;
Packit 3adb1e
                    break;
Packit 3adb1e
            case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
Packit 3adb1e
            case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
Packit 3adb1e
                    failures |= SERF_SSL_CERT_SELF_SIGNED;
Packit 3adb1e
                    break;
Packit 3adb1e
            case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
Packit 3adb1e
            case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
Packit 3adb1e
            case X509_V_ERR_CERT_UNTRUSTED:
Packit 3adb1e
            case X509_V_ERR_INVALID_CA:
Packit 3adb1e
            case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
Packit 3adb1e
                    failures |= SERF_SSL_CERT_UNKNOWNCA;
Packit 3adb1e
                    break;
Packit 3adb1e
            case X509_V_ERR_CERT_REVOKED:
Packit 3adb1e
                    failures |= SERF_SSL_CERT_REVOKED;
Packit 3adb1e
                    break;
Packit 3adb1e
            default:
Packit 3adb1e
                    failures |= SERF_SSL_CERT_UNKNOWN_FAILURE;
Packit 3adb1e
                    break;
Packit 3adb1e
        }
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    /* Validate hostname */
Packit 3adb1e
    status = validate_cert_hostname(server_cert, ctx->pool);
Packit 3adb1e
    if (status)
Packit 3adb1e
        failures |= SERF_SSL_CERT_UNKNOWN_FAILURE;
Packit 3adb1e
Packit 3adb1e
    /* Check certificate expiry dates. */
Packit 3adb1e
    if (X509_cmp_current_time(X509_get_notBefore(server_cert)) >= 0) {
Packit 3adb1e
        failures |= SERF_SSL_CERT_NOTYETVALID;
Packit 3adb1e
    }
Packit 3adb1e
    else if (X509_cmp_current_time(X509_get_notAfter(server_cert)) <= 0) {
Packit 3adb1e
        failures |= SERF_SSL_CERT_EXPIRED;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    if (ctx->server_cert_callback &&
Packit 3adb1e
        (depth == 0 || failures)) {
Packit 3adb1e
        serf_ssl_certificate_t *cert;
Packit 3adb1e
        apr_pool_t *subpool;
Packit 3adb1e
Packit 3adb1e
        apr_pool_create(&subpool, ctx->pool);
Packit 3adb1e
Packit 3adb1e
        cert = apr_palloc(subpool, sizeof(serf_ssl_certificate_t));
Packit 3adb1e
        cert->ssl_cert = server_cert;
Packit 3adb1e
        cert->depth = depth;
Packit 3adb1e
Packit 3adb1e
        /* Callback for further verification. */
Packit 3adb1e
        status = ctx->server_cert_callback(ctx->server_cert_userdata,
Packit 3adb1e
                                           failures, cert);
Packit 3adb1e
        if (status == APR_SUCCESS)
Packit 3adb1e
            cert_valid = 1;
Packit 3adb1e
        else {
Packit 3adb1e
            /* Even if openssl found the certificate valid, the application
Packit 3adb1e
               told us to reject it. */
Packit 3adb1e
            cert_valid = 0;
Packit 3adb1e
            /* Pass the error back to the caller through the context-run. */
Packit 3adb1e
            ctx->pending_err = status;
Packit 3adb1e
        }
Packit 3adb1e
        apr_pool_destroy(subpool);
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    if (ctx->server_cert_chain_callback
Packit 3adb1e
        && (depth == 0 || failures)) {
Packit 3adb1e
        STACK_OF(X509) *chain;
Packit 3adb1e
        const serf_ssl_certificate_t **certs;
Packit 3adb1e
        int certs_len;
Packit 3adb1e
        apr_pool_t *subpool;
Packit 3adb1e
Packit 3adb1e
        apr_pool_create(&subpool, ctx->pool);
Packit 3adb1e
Packit 3adb1e
        /* Borrow the chain to pass to the callback. */
Packit 3adb1e
        chain = X509_STORE_CTX_get_chain(store_ctx);
Packit 3adb1e
Packit 3adb1e
        /* If the chain can't be retrieved, just pass the current
Packit 3adb1e
           certificate. */
Packit 3adb1e
        /* ### can this actually happen with _get_chain() ?  */
Packit 3adb1e
        if (!chain) {
Packit 3adb1e
            serf_ssl_certificate_t *cert = apr_palloc(subpool, sizeof(*cert));
Packit 3adb1e
Packit 3adb1e
            cert->ssl_cert = server_cert;
Packit 3adb1e
            cert->depth = depth;
Packit 3adb1e
Packit 3adb1e
            /* Room for the server_cert and a trailing NULL.  */
Packit 3adb1e
            certs = apr_palloc(subpool, sizeof(*certs) * 2);
Packit 3adb1e
            certs[0] = cert;
Packit 3adb1e
Packit 3adb1e
            certs_len = 1;
Packit 3adb1e
        } else {
Packit 3adb1e
            int i;
Packit 3adb1e
Packit 3adb1e
            certs_len = sk_X509_num(chain);
Packit 3adb1e
Packit 3adb1e
            /* Room for all the certs and a trailing NULL.  */
Packit 3adb1e
            certs = apr_palloc(subpool, sizeof(*certs) * (certs_len + 1));
Packit 3adb1e
            for (i = 0; i < certs_len; ++i) {
Packit 3adb1e
                serf_ssl_certificate_t *cert;
Packit 3adb1e
Packit 3adb1e
                cert = apr_palloc(subpool, sizeof(*cert));
Packit 3adb1e
                cert->ssl_cert = sk_X509_value(chain, i);
Packit 3adb1e
                cert->depth = i;
Packit 3adb1e
Packit 3adb1e
                certs[i] = cert;
Packit 3adb1e
            }
Packit 3adb1e
        }
Packit 3adb1e
        certs[certs_len] = NULL;
Packit 3adb1e
Packit 3adb1e
        /* Callback for further verification. */
Packit 3adb1e
        status = ctx->server_cert_chain_callback(ctx->server_cert_userdata,
Packit 3adb1e
                                                 failures, depth,
Packit 3adb1e
                                                 certs, certs_len);
Packit 3adb1e
        if (status == APR_SUCCESS) {
Packit 3adb1e
            cert_valid = 1;
Packit 3adb1e
        } else {
Packit 3adb1e
            /* Even if openssl found the certificate valid, the application
Packit 3adb1e
               told us to reject it. */
Packit 3adb1e
            cert_valid = 0;
Packit 3adb1e
            /* Pass the error back to the caller through the context-run. */
Packit 3adb1e
            ctx->pending_err = status;
Packit 3adb1e
        }
Packit 3adb1e
Packit 3adb1e
        apr_pool_destroy(subpool);
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    /* Return a specific error if the server certificate is not accepted by
Packit 3adb1e
       OpenSSL and the application has not set callbacks to override this. */
Packit 3adb1e
    if (!cert_valid &&
Packit 3adb1e
        !ctx->server_cert_chain_callback &&
Packit 3adb1e
        !ctx->server_cert_callback)
Packit 3adb1e
    {
Packit 3adb1e
        ctx->pending_err = SERF_ERROR_SSL_CERT_FAILED;
Packit 3adb1e
    }
Packit 3adb1e
        
Packit 3adb1e
    return cert_valid;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
/* This function reads an encrypted stream and returns the decrypted stream. */
Packit 3adb1e
static apr_status_t ssl_decrypt(void *baton, apr_size_t bufsize,
Packit 3adb1e
                                char *buf, apr_size_t *len)
Packit 3adb1e
{
Packit 3adb1e
    serf_ssl_context_t *ctx = baton;
Packit 3adb1e
    apr_size_t priv_len;
Packit 3adb1e
    apr_status_t status;
Packit 3adb1e
    const char *data;
Packit 3adb1e
    int ssl_len;
Packit 3adb1e
Packit 3adb1e
    if (ctx->fatal_err)
Packit 3adb1e
        return ctx->fatal_err;
Packit 3adb1e
Packit 3adb1e
    serf__log(SSL_VERBOSE, __FILE__, "ssl_decrypt: begin %d\n", bufsize);
Packit 3adb1e
Packit 3adb1e
    /* Is there some data waiting to be read? */
Packit 3adb1e
    ssl_len = SSL_read(ctx->ssl, buf, bufsize);
Packit 3adb1e
    if (ssl_len > 0) {
Packit 3adb1e
        serf__log(SSL_VERBOSE, __FILE__,
Packit 3adb1e
                  "ssl_decrypt: %d bytes (%d); status: %d; flags: %d\n",
Packit 3adb1e
                  ssl_len, bufsize, ctx->decrypt.status,
Packit 3adb1e
                  BIO_get_retry_flags(ctx->bio));
Packit 3adb1e
        *len = ssl_len;
Packit 3adb1e
        return APR_SUCCESS;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    status = serf_bucket_read(ctx->decrypt.stream, bufsize, &data, &priv_len);
Packit 3adb1e
Packit 3adb1e
    if (!SERF_BUCKET_READ_ERROR(status) && priv_len) {
Packit 3adb1e
        serf_bucket_t *tmp;
Packit 3adb1e
Packit 3adb1e
        serf__log(SSL_VERBOSE, __FILE__,
Packit 3adb1e
                  "ssl_decrypt: read %d bytes (%d); status: %d\n",
Packit 3adb1e
                  priv_len, bufsize, status);
Packit 3adb1e
Packit 3adb1e
        tmp = serf_bucket_simple_copy_create(data, priv_len,
Packit 3adb1e
                                             ctx->decrypt.pending->allocator);
Packit 3adb1e
Packit 3adb1e
        serf_bucket_aggregate_append(ctx->decrypt.pending, tmp);
Packit 3adb1e
Packit 3adb1e
        ssl_len = SSL_read(ctx->ssl, buf, bufsize);
Packit 3adb1e
        if (ssl_len < 0) {
Packit 3adb1e
            int ssl_err;
Packit 3adb1e
Packit 3adb1e
            ssl_err = SSL_get_error(ctx->ssl, ssl_len);
Packit 3adb1e
            switch (ssl_err) {
Packit 3adb1e
            case SSL_ERROR_SYSCALL:
Packit 3adb1e
                *len = 0;
Packit 3adb1e
                /* Return the underlying network error that caused OpenSSL
Packit 3adb1e
                   to fail. ### This can be a crypt error! */
Packit 3adb1e
                status = ctx->decrypt.status;
Packit 3adb1e
                break;
Packit 3adb1e
            case SSL_ERROR_WANT_READ:
Packit 3adb1e
            case SSL_ERROR_WANT_WRITE:
Packit 3adb1e
                *len = 0;
Packit 3adb1e
                status = APR_EAGAIN;
Packit 3adb1e
                break;
Packit 3adb1e
            case SSL_ERROR_SSL:
Packit 3adb1e
                *len = 0;
Packit 3adb1e
                if (ctx->pending_err) {
Packit 3adb1e
                    status = ctx->pending_err;
Packit 3adb1e
                    ctx->pending_err = 0;
Packit 3adb1e
                } else {
Packit 3adb1e
                    ctx->fatal_err = status = SERF_ERROR_SSL_COMM_FAILED;
Packit 3adb1e
                }
Packit 3adb1e
                break;
Packit 3adb1e
            default:
Packit 3adb1e
                *len = 0;
Packit 3adb1e
                ctx->fatal_err = status = SERF_ERROR_SSL_COMM_FAILED;
Packit 3adb1e
                break;
Packit 3adb1e
            }
Packit 3adb1e
        } else if (ssl_len == 0) {
Packit 3adb1e
            /* The server shut down the connection. */
Packit 3adb1e
            int ssl_err, shutdown;
Packit 3adb1e
            *len = 0;
Packit 3adb1e
Packit 3adb1e
            /* Check for SSL_RECEIVED_SHUTDOWN */
Packit 3adb1e
            shutdown = SSL_get_shutdown(ctx->ssl);
Packit 3adb1e
            /* Check for SSL_ERROR_ZERO_RETURN */
Packit 3adb1e
            ssl_err = SSL_get_error(ctx->ssl, ssl_len);
Packit 3adb1e
Packit 3adb1e
            if (shutdown == SSL_RECEIVED_SHUTDOWN &&
Packit 3adb1e
                ssl_err == SSL_ERROR_ZERO_RETURN) {
Packit 3adb1e
                /* The server closed the SSL session. While this doesn't
Packit 3adb1e
                necessary mean the connection is closed, let's close
Packit 3adb1e
                it here anyway.
Packit 3adb1e
                We can optimize this later. */
Packit 3adb1e
                serf__log(SSL_VERBOSE, __FILE__, 
Packit 3adb1e
                          "ssl_decrypt: SSL read error: server"
Packit 3adb1e
                          " shut down connection!\n");
Packit 3adb1e
                status = APR_EOF;
Packit 3adb1e
            } else {
Packit 3adb1e
                /* A fatal error occurred. */
Packit 3adb1e
                ctx->fatal_err = status = SERF_ERROR_SSL_COMM_FAILED;
Packit 3adb1e
            }
Packit 3adb1e
        } else {
Packit 3adb1e
            *len = ssl_len;
Packit 3adb1e
            serf__log(SSL_MSG_VERBOSE, __FILE__, 
Packit 3adb1e
                      "---\n%.*s\n-(%d)-\n", *len, buf, *len);
Packit 3adb1e
        }
Packit 3adb1e
    }
Packit 3adb1e
    else {
Packit 3adb1e
        *len = 0;
Packit 3adb1e
    }
Packit 3adb1e
    serf__log(SSL_VERBOSE, __FILE__, 
Packit 3adb1e
              "ssl_decrypt: %d %d %d\n", status, *len,
Packit 3adb1e
              BIO_get_retry_flags(ctx->bio));
Packit 3adb1e
Packit 3adb1e
    return status;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
/* This function reads a decrypted stream and returns an encrypted stream. */
Packit 3adb1e
static apr_status_t ssl_encrypt(void *baton, apr_size_t bufsize,
Packit 3adb1e
                                char *buf, apr_size_t *len)
Packit 3adb1e
{
Packit 3adb1e
    const char *data;
Packit 3adb1e
    apr_size_t interim_bufsize;
Packit 3adb1e
    serf_ssl_context_t *ctx = baton;
Packit 3adb1e
    apr_status_t status;
Packit 3adb1e
Packit 3adb1e
    if (ctx->fatal_err)
Packit 3adb1e
        return ctx->fatal_err;
Packit 3adb1e
Packit 3adb1e
    serf__log(SSL_VERBOSE, __FILE__, "ssl_encrypt: begin %d\n", bufsize);
Packit 3adb1e
Packit 3adb1e
    /* Try to read already encrypted but unread data first. */
Packit 3adb1e
    status = serf_bucket_read(ctx->encrypt.pending, bufsize, &data, len);
Packit 3adb1e
    if (SERF_BUCKET_READ_ERROR(status)) {
Packit 3adb1e
        return status;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    /* Aha, we read something.  Return that now. */
Packit 3adb1e
    if (*len) {
Packit 3adb1e
        memcpy(buf, data, *len);
Packit 3adb1e
        if (APR_STATUS_IS_EOF(status)) {
Packit 3adb1e
            status = APR_SUCCESS;
Packit 3adb1e
        }
Packit 3adb1e
Packit 3adb1e
        serf__log(SSL_VERBOSE, __FILE__, "ssl_encrypt: %d %d %d (quick read)\n",
Packit 3adb1e
                  status, *len, BIO_get_retry_flags(ctx->bio));
Packit 3adb1e
Packit 3adb1e
        return status;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    if (BIO_should_retry(ctx->bio) && BIO_should_write(ctx->bio)) {
Packit 3adb1e
        serf__log(SSL_VERBOSE, __FILE__,
Packit 3adb1e
                  "ssl_encrypt: %d %d %d (should write exit)\n",
Packit 3adb1e
                  status, *len, BIO_get_retry_flags(ctx->bio));
Packit 3adb1e
Packit 3adb1e
        return APR_EAGAIN;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    /* If we were previously blocked, unblock ourselves now. */
Packit 3adb1e
    if (BIO_should_read(ctx->bio)) {
Packit 3adb1e
        serf__log(SSL_VERBOSE, __FILE__, "ssl_encrypt: reset %d %d (%d %d %d)\n",
Packit 3adb1e
                  status, ctx->encrypt.status,
Packit 3adb1e
                  BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
Packit 3adb1e
                  BIO_get_retry_flags(ctx->bio));
Packit 3adb1e
Packit 3adb1e
        ctx->encrypt.status = APR_SUCCESS;
Packit 3adb1e
        ctx->encrypt.exhausted_reset = 0;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    /* Oh well, read from our stream now. */
Packit 3adb1e
    interim_bufsize = bufsize;
Packit 3adb1e
    do {
Packit 3adb1e
        apr_size_t interim_len;
Packit 3adb1e
Packit 3adb1e
        if (!ctx->encrypt.status) {
Packit 3adb1e
            struct iovec vecs[64];
Packit 3adb1e
            int vecs_read;
Packit 3adb1e
Packit 3adb1e
            status = serf_bucket_read_iovec(ctx->encrypt.stream,
Packit 3adb1e
                                            interim_bufsize, 64, vecs,
Packit 3adb1e
                                            &vecs_read);
Packit 3adb1e
Packit 3adb1e
            if (!SERF_BUCKET_READ_ERROR(status) && vecs_read) {
Packit 3adb1e
                char *vecs_data;
Packit 3adb1e
                int i, cur, vecs_data_len;
Packit 3adb1e
                int ssl_len;
Packit 3adb1e
Packit 3adb1e
                /* Combine the buffers of the iovec into one buffer, as
Packit 3adb1e
                   that is with SSL_write requires. */
Packit 3adb1e
                vecs_data_len = 0;
Packit 3adb1e
                for (i = 0; i < vecs_read; i++) {
Packit 3adb1e
                    vecs_data_len += vecs[i].iov_len;
Packit 3adb1e
                }
Packit 3adb1e
Packit 3adb1e
                vecs_data = serf_bucket_mem_alloc(ctx->allocator,
Packit 3adb1e
                                                  vecs_data_len);
Packit 3adb1e
Packit 3adb1e
                cur = 0;
Packit 3adb1e
                for (i = 0; i < vecs_read; i++) {
Packit 3adb1e
                    memcpy(vecs_data + cur, vecs[i].iov_base, vecs[i].iov_len);
Packit 3adb1e
                    cur += vecs[i].iov_len;
Packit 3adb1e
                }
Packit 3adb1e
Packit 3adb1e
                interim_bufsize -= vecs_data_len;
Packit 3adb1e
                interim_len = vecs_data_len;
Packit 3adb1e
Packit 3adb1e
                serf__log(SSL_VERBOSE, __FILE__,
Packit 3adb1e
                          "ssl_encrypt: bucket read %d bytes; "\
Packit 3adb1e
                          "status %d\n", interim_len, status);
Packit 3adb1e
                serf__log(SSL_MSG_VERBOSE, __FILE__, "---\n%.*s\n-(%d)-\n",
Packit 3adb1e
                          interim_len, vecs_data, interim_len);
Packit 3adb1e
Packit 3adb1e
                /* Stash our status away. */
Packit 3adb1e
                ctx->encrypt.status = status;
Packit 3adb1e
Packit 3adb1e
                ssl_len = SSL_write(ctx->ssl, vecs_data, interim_len);
Packit 3adb1e
Packit 3adb1e
                serf__log(SSL_VERBOSE, __FILE__, 
Packit 3adb1e
                          "ssl_encrypt: SSL write: %d\n", ssl_len);
Packit 3adb1e
Packit 3adb1e
                /* If we failed to write... */
Packit 3adb1e
                if (ssl_len < 0) {
Packit 3adb1e
                    int ssl_err;
Packit 3adb1e
Packit 3adb1e
                    /* Ah, bugger. We need to put that data back.
Packit 3adb1e
                       Note: use the copy here, we do not own the original iovec
Packit 3adb1e
                       data buffer so it will be freed on next read. */
Packit 3adb1e
                    serf_bucket_t *vecs_copy =
Packit 3adb1e
                        serf_bucket_simple_own_create(vecs_data,
Packit 3adb1e
                                                      vecs_data_len,
Packit 3adb1e
                                                      ctx->allocator);
Packit 3adb1e
                    serf_bucket_aggregate_prepend(ctx->encrypt.stream,
Packit 3adb1e
                                                  vecs_copy);
Packit 3adb1e
Packit 3adb1e
                    ssl_err = SSL_get_error(ctx->ssl, ssl_len);
Packit 3adb1e
Packit 3adb1e
                    serf__log(SSL_VERBOSE, __FILE__, 
Packit 3adb1e
                              "ssl_encrypt: SSL write error: %d\n", ssl_err);
Packit 3adb1e
Packit 3adb1e
                    if (ssl_err == SSL_ERROR_SYSCALL) {
Packit 3adb1e
                        /* Return the underlying network error that caused OpenSSL
Packit 3adb1e
                           to fail. ### This can be a decrypt error! */
Packit 3adb1e
                        status = ctx->encrypt.status;
Packit 3adb1e
                        if (SERF_BUCKET_READ_ERROR(status)) {
Packit 3adb1e
                            return status;
Packit 3adb1e
                        }
Packit 3adb1e
                    }
Packit 3adb1e
                    else {
Packit 3adb1e
                        /* Oh, no. */
Packit 3adb1e
                        if (ssl_err == SSL_ERROR_WANT_READ) {
Packit 3adb1e
                            status = SERF_ERROR_WAIT_CONN;
Packit 3adb1e
                        }
Packit 3adb1e
                        else {
Packit 3adb1e
                            ctx->fatal_err = status =
Packit 3adb1e
                                SERF_ERROR_SSL_COMM_FAILED;
Packit 3adb1e
                        }
Packit 3adb1e
                    }
Packit 3adb1e
Packit 3adb1e
                    serf__log(SSL_VERBOSE, __FILE__, 
Packit 3adb1e
                              "ssl_encrypt: SSL write error: %d %d\n",
Packit 3adb1e
                              status, *len);
Packit 3adb1e
                } else {
Packit 3adb1e
                    /* We're done with this data. */
Packit 3adb1e
                    serf_bucket_mem_free(ctx->allocator, vecs_data);
Packit 3adb1e
                }
Packit 3adb1e
            }
Packit 3adb1e
        }
Packit 3adb1e
        else {
Packit 3adb1e
            interim_len = 0;
Packit 3adb1e
            *len = 0;
Packit 3adb1e
            status = ctx->encrypt.status;
Packit 3adb1e
        }
Packit 3adb1e
Packit 3adb1e
    } while (!status && interim_bufsize);
Packit 3adb1e
Packit 3adb1e
    /* Okay, we exhausted our underlying stream. */
Packit 3adb1e
    if (!SERF_BUCKET_READ_ERROR(status)) {
Packit 3adb1e
        apr_status_t agg_status;
Packit 3adb1e
        struct iovec vecs[64];
Packit 3adb1e
        int vecs_read, i;
Packit 3adb1e
Packit 3adb1e
        /* We read something! */
Packit 3adb1e
        agg_status = serf_bucket_read_iovec(ctx->encrypt.pending, bufsize,
Packit 3adb1e
                                            64, vecs, &vecs_read);
Packit 3adb1e
        *len = 0;
Packit 3adb1e
        for (i = 0; i < vecs_read; i++) {
Packit 3adb1e
            memcpy(buf + *len, vecs[i].iov_base, vecs[i].iov_len);
Packit 3adb1e
            *len += vecs[i].iov_len;
Packit 3adb1e
        }
Packit 3adb1e
Packit 3adb1e
        serf__log(SSL_VERBOSE, __FILE__,
Packit 3adb1e
                  "ssl_encrypt read agg: %d %d %d %d\n", status, agg_status,
Packit 3adb1e
            ctx->encrypt.status, *len);
Packit 3adb1e
Packit 3adb1e
        if (!agg_status) {
Packit 3adb1e
            status = agg_status;
Packit 3adb1e
        }
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    if (status == SERF_ERROR_WAIT_CONN
Packit 3adb1e
        && BIO_should_retry(ctx->bio) && BIO_should_read(ctx->bio)) {
Packit 3adb1e
        ctx->encrypt.exhausted = ctx->encrypt.status;
Packit 3adb1e
        ctx->encrypt.status = SERF_ERROR_WAIT_CONN;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    serf__log(SSL_VERBOSE, __FILE__,
Packit 3adb1e
              "ssl_encrypt finished: %d %d (%d %d %d)\n", status, *len,
Packit 3adb1e
              BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
Packit 3adb1e
              BIO_get_retry_flags(ctx->bio));
Packit 3adb1e
Packit 3adb1e
    return status;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
#if APR_HAS_THREADS && !defined(USE_OPENSSL_1_1_API)
Packit 3adb1e
static apr_pool_t *ssl_pool;
Packit 3adb1e
static apr_thread_mutex_t **ssl_locks;
Packit 3adb1e
Packit 3adb1e
typedef struct CRYPTO_dynlock_value {
Packit 3adb1e
    apr_thread_mutex_t *lock;
Packit 3adb1e
} CRYPTO_dynlock_value;
Packit 3adb1e
Packit 3adb1e
static CRYPTO_dynlock_value *ssl_dyn_create(const char* file, int line)
Packit 3adb1e
{
Packit 3adb1e
    CRYPTO_dynlock_value *l;
Packit 3adb1e
    apr_status_t rv;
Packit 3adb1e
Packit 3adb1e
    l = apr_palloc(ssl_pool, sizeof(CRYPTO_dynlock_value));
Packit 3adb1e
    rv = apr_thread_mutex_create(&l->lock, APR_THREAD_MUTEX_DEFAULT, ssl_pool);
Packit 3adb1e
    if (rv != APR_SUCCESS) {
Packit 3adb1e
        /* FIXME: return error here */
Packit 3adb1e
    }
Packit 3adb1e
    return l;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static void ssl_dyn_lock(int mode, CRYPTO_dynlock_value *l, const char *file,
Packit 3adb1e
                         int line)
Packit 3adb1e
{
Packit 3adb1e
    if (mode & CRYPTO_LOCK) {
Packit 3adb1e
        apr_thread_mutex_lock(l->lock);
Packit 3adb1e
    }
Packit 3adb1e
    else if (mode & CRYPTO_UNLOCK) {
Packit 3adb1e
        apr_thread_mutex_unlock(l->lock);
Packit 3adb1e
    }
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static void ssl_dyn_destroy(CRYPTO_dynlock_value *l, const char *file,
Packit 3adb1e
                            int line)
Packit 3adb1e
{
Packit 3adb1e
    apr_thread_mutex_destroy(l->lock);
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static void ssl_lock(int mode, int n, const char *file, int line)
Packit 3adb1e
{
Packit 3adb1e
    if (mode & CRYPTO_LOCK) {
Packit 3adb1e
        apr_thread_mutex_lock(ssl_locks[n]);
Packit 3adb1e
    }
Packit 3adb1e
    else if (mode & CRYPTO_UNLOCK) {
Packit 3adb1e
        apr_thread_mutex_unlock(ssl_locks[n]);
Packit 3adb1e
    }
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static unsigned long ssl_id(void)
Packit 3adb1e
{
Packit 3adb1e
    /* FIXME: This is lame and not portable. -aaron */
Packit 3adb1e
    return (unsigned long) apr_os_thread_current();
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static apr_status_t cleanup_ssl(void *data)
Packit 3adb1e
{
Packit 3adb1e
    CRYPTO_set_locking_callback(NULL);
Packit 3adb1e
    CRYPTO_set_id_callback(NULL);
Packit 3adb1e
    CRYPTO_set_dynlock_create_callback(NULL);
Packit 3adb1e
    CRYPTO_set_dynlock_lock_callback(NULL);
Packit 3adb1e
    CRYPTO_set_dynlock_destroy_callback(NULL);
Packit 3adb1e
Packit 3adb1e
    return APR_SUCCESS;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
#endif
Packit 3adb1e
Packit 3adb1e
#if !APR_VERSION_AT_LEAST(1,0,0)
Packit 3adb1e
#define apr_atomic_cas32(mem, with, cmp) apr_atomic_cas(mem, with, cmp)
Packit 3adb1e
#endif
Packit 3adb1e
Packit 3adb1e
enum ssl_init_e
Packit 3adb1e
{
Packit 3adb1e
   INIT_UNINITIALIZED = 0,
Packit 3adb1e
   INIT_BUSY = 1,
Packit 3adb1e
   INIT_DONE = 2
Packit 3adb1e
};
Packit 3adb1e
Packit 3adb1e
static volatile apr_uint32_t have_init_ssl = INIT_UNINITIALIZED;
Packit 3adb1e
Packit 3adb1e
static void init_ssl_libraries(void)
Packit 3adb1e
{
Packit 3adb1e
    apr_uint32_t val;
Packit 3adb1e
Packit 3adb1e
    val = apr_atomic_cas32(&have_init_ssl, INIT_BUSY, INIT_UNINITIALIZED);
Packit 3adb1e
Packit 3adb1e
    if (!val) {
Packit 3adb1e
#if APR_HAS_THREADS && !defined(USE_OPENSSL_1_1_API)
Packit 3adb1e
        int i, numlocks;
Packit 3adb1e
#endif
Packit 3adb1e
Packit 3adb1e
#ifdef SSL_VERBOSE
Packit 3adb1e
        /* Warn when compile-time and run-time version of OpenSSL differ in
Packit 3adb1e
           major/minor version number. */
Packit 3adb1e
        long libver = SSLeay();
Packit 3adb1e
Packit 3adb1e
        if ((libver ^ OPENSSL_VERSION_NUMBER) & 0xFFF00000) {
Packit 3adb1e
            serf__log(SSL_VERBOSE, __FILE__,
Packit 3adb1e
                      "Warning: OpenSSL library version mismatch, compile-time "
Packit 3adb1e
                      "was %lx, runtime is %lx.\n",
Packit 3adb1e
                      OPENSSL_VERSION_NUMBER, libver);
Packit 3adb1e
        }
Packit 3adb1e
#endif
Packit 3adb1e
Packit 3adb1e
#ifdef USE_OPENSSL_1_1_API
Packit 3adb1e
        OPENSSL_malloc_init();
Packit 3adb1e
#else
Packit 3adb1e
        CRYPTO_malloc_init();
Packit 3adb1e
#endif
Packit 3adb1e
        ERR_load_crypto_strings();
Packit 3adb1e
        SSL_load_error_strings();
Packit 3adb1e
        SSL_library_init();
Packit 3adb1e
        OpenSSL_add_all_algorithms();
Packit 3adb1e
Packit 3adb1e
#if APR_HAS_THREADS && !defined(USE_OPENSSL_1_1_API)
Packit 3adb1e
        numlocks = CRYPTO_num_locks();
Packit 3adb1e
        apr_pool_create(&ssl_pool, NULL);
Packit 3adb1e
        ssl_locks = apr_palloc(ssl_pool, sizeof(apr_thread_mutex_t*)*numlocks);
Packit 3adb1e
        for (i = 0; i < numlocks; i++) {
Packit 3adb1e
            apr_status_t rv;
Packit 3adb1e
Packit 3adb1e
            /* Intraprocess locks don't /need/ a filename... */
Packit 3adb1e
            rv = apr_thread_mutex_create(&ssl_locks[i],
Packit 3adb1e
                                         APR_THREAD_MUTEX_DEFAULT, ssl_pool);
Packit 3adb1e
            if (rv != APR_SUCCESS) {
Packit 3adb1e
                /* FIXME: error out here */
Packit 3adb1e
            }
Packit 3adb1e
        }
Packit 3adb1e
        CRYPTO_set_locking_callback(ssl_lock);
Packit 3adb1e
        CRYPTO_set_id_callback(ssl_id);
Packit 3adb1e
        CRYPTO_set_dynlock_create_callback(ssl_dyn_create);
Packit 3adb1e
        CRYPTO_set_dynlock_lock_callback(ssl_dyn_lock);
Packit 3adb1e
        CRYPTO_set_dynlock_destroy_callback(ssl_dyn_destroy);
Packit 3adb1e
Packit 3adb1e
        apr_pool_cleanup_register(ssl_pool, NULL, cleanup_ssl, cleanup_ssl);
Packit 3adb1e
#endif
Packit 3adb1e
        apr_atomic_cas32(&have_init_ssl, INIT_DONE, INIT_BUSY);
Packit 3adb1e
    }
Packit 3adb1e
  else
Packit 3adb1e
    {
Packit 3adb1e
        /* Make sure we don't continue before the initialization in another
Packit 3adb1e
           thread has completed */
Packit 3adb1e
        while (val != INIT_DONE) {
Packit 3adb1e
            apr_sleep(APR_USEC_PER_SEC / 1000);
Packit 3adb1e
      
Packit 3adb1e
            val = apr_atomic_cas32(&have_init_ssl,
Packit 3adb1e
                                   INIT_UNINITIALIZED,
Packit 3adb1e
                                   INIT_UNINITIALIZED);            
Packit 3adb1e
        }
Packit 3adb1e
    }
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey)
Packit 3adb1e
{
Packit 3adb1e
    serf_ssl_context_t *ctx = SSL_get_app_data(ssl);
Packit 3adb1e
    apr_status_t status;
Packit 3adb1e
Packit 3adb1e
    if (ctx->cached_cert) {
Packit 3adb1e
        *cert = ctx->cached_cert;
Packit 3adb1e
        *pkey = ctx->cached_cert_pw;
Packit 3adb1e
        return 1;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    while (ctx->cert_callback) {
Packit 3adb1e
        const char *cert_path;
Packit 3adb1e
        apr_file_t *cert_file;
Packit 3adb1e
        BIO *bio;
Packit 3adb1e
        BIO_METHOD *biom;
Packit 3adb1e
        PKCS12 *p12;
Packit 3adb1e
        int i;
Packit 3adb1e
        int retrying_success = 0;
Packit 3adb1e
Packit 3adb1e
        if (ctx->cert_file_success) {
Packit 3adb1e
            status = APR_SUCCESS;
Packit 3adb1e
            cert_path = ctx->cert_file_success;
Packit 3adb1e
            ctx->cert_file_success = NULL;
Packit 3adb1e
            retrying_success = 1;
Packit 3adb1e
        } else {
Packit 3adb1e
            status = ctx->cert_callback(ctx->cert_userdata, &cert_path);
Packit 3adb1e
        }
Packit 3adb1e
Packit 3adb1e
        if (status || !cert_path) {
Packit 3adb1e
            break;
Packit 3adb1e
        }
Packit 3adb1e
Packit 3adb1e
        /* Load the x.509 cert file stored in PKCS12 */
Packit 3adb1e
        status = apr_file_open(&cert_file, cert_path, APR_READ, APR_OS_DEFAULT,
Packit 3adb1e
                               ctx->pool);
Packit 3adb1e
Packit 3adb1e
        if (status) {
Packit 3adb1e
            continue;
Packit 3adb1e
        }
Packit 3adb1e
Packit 3adb1e
        biom = bio_meth_file_new();
Packit 3adb1e
        bio = BIO_new(biom);
Packit 3adb1e
        bio_set_data(bio, cert_file);
Packit 3adb1e
Packit 3adb1e
        ctx->cert_path = cert_path;
Packit 3adb1e
        p12 = d2i_PKCS12_bio(bio, NULL);
Packit 3adb1e
        apr_file_close(cert_file);
Packit 3adb1e
Packit 3adb1e
        i = PKCS12_parse(p12, NULL, pkey, cert, NULL);
Packit 3adb1e
Packit 3adb1e
        if (i == 1) {
Packit 3adb1e
            PKCS12_free(p12);
Packit 3adb1e
            bio_meth_free(biom);
Packit 3adb1e
            ctx->cached_cert = *cert;
Packit 3adb1e
            ctx->cached_cert_pw = *pkey;
Packit 3adb1e
            if (!retrying_success && ctx->cert_cache_pool) {
Packit 3adb1e
                const char *c;
Packit 3adb1e
Packit 3adb1e
                c = apr_pstrdup(ctx->cert_cache_pool, ctx->cert_path);
Packit 3adb1e
Packit 3adb1e
                apr_pool_userdata_setn(c, "serf:ssl:cert",
Packit 3adb1e
                                       apr_pool_cleanup_null,
Packit 3adb1e
                                       ctx->cert_cache_pool);
Packit 3adb1e
            }
Packit 3adb1e
            return 1;
Packit 3adb1e
        }
Packit 3adb1e
        else {
Packit 3adb1e
            int err = ERR_get_error();
Packit 3adb1e
            ERR_clear_error();
Packit 3adb1e
            if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
Packit 3adb1e
                ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
Packit 3adb1e
                if (ctx->cert_pw_callback) {
Packit 3adb1e
                    const char *password;
Packit 3adb1e
Packit 3adb1e
                    if (ctx->cert_pw_success) {
Packit 3adb1e
                        status = APR_SUCCESS;
Packit 3adb1e
                        password = ctx->cert_pw_success;
Packit 3adb1e
                        ctx->cert_pw_success = NULL;
Packit 3adb1e
                    } else {
Packit 3adb1e
                        status = ctx->cert_pw_callback(ctx->cert_pw_userdata,
Packit 3adb1e
                                                       ctx->cert_path,
Packit 3adb1e
                                                       &password);
Packit 3adb1e
                    }
Packit 3adb1e
Packit 3adb1e
                    if (!status && password) {
Packit 3adb1e
                        i = PKCS12_parse(p12, password, pkey, cert, NULL);
Packit 3adb1e
                        if (i == 1) {
Packit 3adb1e
                            PKCS12_free(p12);
Packit 3adb1e
                            bio_meth_free(biom);
Packit 3adb1e
                            ctx->cached_cert = *cert;
Packit 3adb1e
                            ctx->cached_cert_pw = *pkey;
Packit 3adb1e
                            if (!retrying_success && ctx->cert_cache_pool) {
Packit 3adb1e
                                const char *c;
Packit 3adb1e
Packit 3adb1e
                                c = apr_pstrdup(ctx->cert_cache_pool,
Packit 3adb1e
                                                ctx->cert_path);
Packit 3adb1e
Packit 3adb1e
                                apr_pool_userdata_setn(c, "serf:ssl:cert",
Packit 3adb1e
                                                       apr_pool_cleanup_null,
Packit 3adb1e
                                                       ctx->cert_cache_pool);
Packit 3adb1e
                            }
Packit 3adb1e
                            if (!retrying_success && ctx->cert_pw_cache_pool) {
Packit 3adb1e
                                const char *c;
Packit 3adb1e
Packit 3adb1e
                                c = apr_pstrdup(ctx->cert_pw_cache_pool,
Packit 3adb1e
                                                password);
Packit 3adb1e
Packit 3adb1e
                                apr_pool_userdata_setn(c, "serf:ssl:certpw",
Packit 3adb1e
                                                       apr_pool_cleanup_null,
Packit 3adb1e
                                                       ctx->cert_pw_cache_pool);
Packit 3adb1e
                            }
Packit 3adb1e
                            return 1;
Packit 3adb1e
                        }
Packit 3adb1e
                    }
Packit 3adb1e
                }
Packit 3adb1e
                PKCS12_free(p12);
Packit 3adb1e
                bio_meth_free(biom);
Packit 3adb1e
                return 0;
Packit 3adb1e
            }
Packit 3adb1e
            else {
Packit 3adb1e
                printf("OpenSSL cert error: %d %d %d\n", ERR_GET_LIB(err),
Packit 3adb1e
                       ERR_GET_FUNC(err),
Packit 3adb1e
                       ERR_GET_REASON(err));
Packit 3adb1e
                PKCS12_free(p12);
Packit 3adb1e
                bio_meth_free(biom);
Packit 3adb1e
            }
Packit 3adb1e
        }
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    return 0;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
void serf_ssl_client_cert_provider_set(
Packit 3adb1e
    serf_ssl_context_t *context,
Packit 3adb1e
    serf_ssl_need_client_cert_t callback,
Packit 3adb1e
    void *data,
Packit 3adb1e
    void *cache_pool)
Packit 3adb1e
{
Packit 3adb1e
    context->cert_callback = callback;
Packit 3adb1e
    context->cert_userdata = data;
Packit 3adb1e
    context->cert_cache_pool = cache_pool;
Packit 3adb1e
    if (context->cert_cache_pool) {
Packit 3adb1e
        apr_pool_userdata_get((void**)&context->cert_file_success,
Packit 3adb1e
                              "serf:ssl:cert", cache_pool);
Packit 3adb1e
    }
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
void serf_ssl_client_cert_password_set(
Packit 3adb1e
    serf_ssl_context_t *context,
Packit 3adb1e
    serf_ssl_need_cert_password_t callback,
Packit 3adb1e
    void *data,
Packit 3adb1e
    void *cache_pool)
Packit 3adb1e
{
Packit 3adb1e
    context->cert_pw_callback = callback;
Packit 3adb1e
    context->cert_pw_userdata = data;
Packit 3adb1e
    context->cert_pw_cache_pool = cache_pool;
Packit 3adb1e
    if (context->cert_pw_cache_pool) {
Packit 3adb1e
        apr_pool_userdata_get((void**)&context->cert_pw_success,
Packit 3adb1e
                              "serf:ssl:certpw", cache_pool);
Packit 3adb1e
    }
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
void serf_ssl_server_cert_callback_set(
Packit 3adb1e
    serf_ssl_context_t *context,
Packit 3adb1e
    serf_ssl_need_server_cert_t callback,
Packit 3adb1e
    void *data)
Packit 3adb1e
{
Packit 3adb1e
    context->server_cert_callback = callback;
Packit 3adb1e
    context->server_cert_userdata = data;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
void serf_ssl_server_cert_chain_callback_set(
Packit 3adb1e
    serf_ssl_context_t *context,
Packit 3adb1e
    serf_ssl_need_server_cert_t cert_callback,
Packit 3adb1e
    serf_ssl_server_cert_chain_cb_t cert_chain_callback,
Packit 3adb1e
    void *data)
Packit 3adb1e
{
Packit 3adb1e
    context->server_cert_callback = cert_callback;
Packit 3adb1e
    context->server_cert_chain_callback = cert_chain_callback;
Packit 3adb1e
    context->server_cert_userdata = data;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static serf_ssl_context_t *ssl_init_context(serf_bucket_alloc_t *allocator)
Packit 3adb1e
{
Packit 3adb1e
    serf_ssl_context_t *ssl_ctx;
Packit 3adb1e
Packit 3adb1e
    init_ssl_libraries();
Packit 3adb1e
Packit 3adb1e
    ssl_ctx = serf_bucket_mem_alloc(allocator, sizeof(*ssl_ctx));
Packit 3adb1e
Packit 3adb1e
    ssl_ctx->refcount = 0;
Packit 3adb1e
    ssl_ctx->pool = serf_bucket_allocator_get_pool(allocator);
Packit 3adb1e
    ssl_ctx->allocator = allocator;
Packit 3adb1e
Packit 3adb1e
    /* Use the best possible protocol version, but disable the broken SSLv2/3 */
Packit 3adb1e
    ssl_ctx->ctx = SSL_CTX_new(SSLv23_client_method());
Packit 3adb1e
    SSL_CTX_set_options(ssl_ctx->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
Packit 3adb1e
Packit 3adb1e
    SSL_CTX_set_client_cert_cb(ssl_ctx->ctx, ssl_need_client_cert);
Packit 3adb1e
    ssl_ctx->cached_cert = 0;
Packit 3adb1e
    ssl_ctx->cached_cert_pw = 0;
Packit 3adb1e
    ssl_ctx->pending_err = APR_SUCCESS;
Packit 3adb1e
    ssl_ctx->fatal_err = APR_SUCCESS;
Packit 3adb1e
Packit 3adb1e
    ssl_ctx->cert_callback = NULL;
Packit 3adb1e
    ssl_ctx->cert_pw_callback = NULL;
Packit 3adb1e
    ssl_ctx->server_cert_callback = NULL;
Packit 3adb1e
    ssl_ctx->server_cert_chain_callback = NULL;
Packit 3adb1e
Packit 3adb1e
    SSL_CTX_set_verify(ssl_ctx->ctx, SSL_VERIFY_PEER,
Packit 3adb1e
                       validate_server_certificate);
Packit 3adb1e
    SSL_CTX_set_options(ssl_ctx->ctx, SSL_OP_ALL);
Packit 3adb1e
    /* Disable SSL compression by default. */
Packit 3adb1e
    disable_compression(ssl_ctx);
Packit 3adb1e
Packit 3adb1e
    ssl_ctx->ssl = SSL_new(ssl_ctx->ctx);
Packit 3adb1e
    ssl_ctx->biom = bio_meth_bucket_new();
Packit 3adb1e
    ssl_ctx->bio = BIO_new(ssl_ctx->biom);
Packit 3adb1e
    bio_set_data(ssl_ctx->bio, ssl_ctx);
Packit 3adb1e
Packit 3adb1e
    SSL_set_bio(ssl_ctx->ssl, ssl_ctx->bio, ssl_ctx->bio);
Packit 3adb1e
Packit 3adb1e
    SSL_set_connect_state(ssl_ctx->ssl);
Packit 3adb1e
Packit 3adb1e
    SSL_set_app_data(ssl_ctx->ssl, ssl_ctx);
Packit 3adb1e
Packit 3adb1e
#if SSL_VERBOSE
Packit 3adb1e
    SSL_CTX_set_info_callback(ssl_ctx->ctx, apps_ssl_info_callback);
Packit 3adb1e
#endif
Packit 3adb1e
Packit 3adb1e
    ssl_ctx->encrypt.stream = NULL;
Packit 3adb1e
    ssl_ctx->encrypt.stream_next = NULL;
Packit 3adb1e
    ssl_ctx->encrypt.pending = serf_bucket_aggregate_create(allocator);
Packit 3adb1e
    ssl_ctx->encrypt.status = APR_SUCCESS;
Packit 3adb1e
    serf_databuf_init(&ssl_ctx->encrypt.databuf);
Packit 3adb1e
    ssl_ctx->encrypt.databuf.read = ssl_encrypt;
Packit 3adb1e
    ssl_ctx->encrypt.databuf.read_baton = ssl_ctx;
Packit 3adb1e
Packit 3adb1e
    ssl_ctx->decrypt.stream = NULL;
Packit 3adb1e
    ssl_ctx->decrypt.pending = serf_bucket_aggregate_create(allocator);
Packit 3adb1e
    ssl_ctx->decrypt.status = APR_SUCCESS;
Packit 3adb1e
    serf_databuf_init(&ssl_ctx->decrypt.databuf);
Packit 3adb1e
    ssl_ctx->decrypt.databuf.read = ssl_decrypt;
Packit 3adb1e
    ssl_ctx->decrypt.databuf.read_baton = ssl_ctx;
Packit 3adb1e
Packit 3adb1e
    return ssl_ctx;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static apr_status_t ssl_free_context(
Packit 3adb1e
    serf_ssl_context_t *ssl_ctx)
Packit 3adb1e
{
Packit 3adb1e
    /* If never had the pending buckets, don't try to free them. */
Packit 3adb1e
    if (ssl_ctx->decrypt.pending != NULL) {
Packit 3adb1e
        serf_bucket_destroy(ssl_ctx->decrypt.pending);
Packit 3adb1e
    }
Packit 3adb1e
    if (ssl_ctx->encrypt.pending != NULL) {
Packit 3adb1e
        serf_bucket_destroy(ssl_ctx->encrypt.pending);
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    /* SSL_free implicitly frees the underlying BIO. */
Packit 3adb1e
    SSL_free(ssl_ctx->ssl);
Packit 3adb1e
    bio_meth_free(ssl_ctx->biom);
Packit 3adb1e
    SSL_CTX_free(ssl_ctx->ctx);
Packit 3adb1e
Packit 3adb1e
    serf_bucket_mem_free(ssl_ctx->allocator, ssl_ctx);
Packit 3adb1e
Packit 3adb1e
    return APR_SUCCESS;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static serf_bucket_t * serf_bucket_ssl_create(
Packit 3adb1e
    serf_ssl_context_t *ssl_ctx,
Packit 3adb1e
    serf_bucket_alloc_t *allocator,
Packit 3adb1e
    const serf_bucket_type_t *type)
Packit 3adb1e
{
Packit 3adb1e
    ssl_context_t *ctx;
Packit 3adb1e
Packit 3adb1e
    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
Packit 3adb1e
    if (!ssl_ctx) {
Packit 3adb1e
        ctx->ssl_ctx = ssl_init_context(allocator);
Packit 3adb1e
    }
Packit 3adb1e
    else {
Packit 3adb1e
        ctx->ssl_ctx = ssl_ctx;
Packit 3adb1e
    }
Packit 3adb1e
    ctx->ssl_ctx->refcount++;
Packit 3adb1e
Packit 3adb1e
    return serf_bucket_create(type, allocator, ctx);
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
apr_status_t serf_ssl_set_hostname(serf_ssl_context_t *context,
Packit 3adb1e
                                   const char * hostname)
Packit 3adb1e
{
Packit 3adb1e
#ifdef SSL_set_tlsext_host_name
Packit 3adb1e
    if (SSL_set_tlsext_host_name(context->ssl, hostname) != 1) {
Packit 3adb1e
        ERR_clear_error();
Packit 3adb1e
    }
Packit 3adb1e
#endif
Packit 3adb1e
    return APR_SUCCESS;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
apr_status_t serf_ssl_use_default_certificates(serf_ssl_context_t *ssl_ctx)
Packit 3adb1e
{
Packit 3adb1e
    X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx->ctx);
Packit 3adb1e
Packit 3adb1e
    int result = X509_STORE_set_default_paths(store);
Packit 3adb1e
Packit 3adb1e
    return result ? APR_SUCCESS : SERF_ERROR_SSL_CERT_FAILED;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
apr_status_t serf_ssl_load_cert_file(
Packit 3adb1e
    serf_ssl_certificate_t **cert,
Packit 3adb1e
    const char *file_path,
Packit 3adb1e
    apr_pool_t *pool)
Packit 3adb1e
{
Packit 3adb1e
    FILE *fp = fopen(file_path, "r");
Packit 3adb1e
Packit 3adb1e
    if (fp) {
Packit 3adb1e
        X509 *ssl_cert = PEM_read_X509(fp, NULL, NULL, NULL);
Packit 3adb1e
        fclose(fp);
Packit 3adb1e
Packit 3adb1e
        if (ssl_cert) {
Packit 3adb1e
            *cert = apr_palloc(pool, sizeof(serf_ssl_certificate_t));
Packit 3adb1e
            (*cert)->ssl_cert = ssl_cert;
Packit 3adb1e
Packit 3adb1e
            return APR_SUCCESS;
Packit 3adb1e
        }
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    return SERF_ERROR_SSL_CERT_FAILED;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
apr_status_t serf_ssl_trust_cert(
Packit 3adb1e
    serf_ssl_context_t *ssl_ctx,
Packit 3adb1e
    serf_ssl_certificate_t *cert)
Packit 3adb1e
{
Packit 3adb1e
    X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx->ctx);
Packit 3adb1e
Packit 3adb1e
    int result = X509_STORE_add_cert(store, cert->ssl_cert);
Packit 3adb1e
Packit 3adb1e
    return result ? APR_SUCCESS : SERF_ERROR_SSL_CERT_FAILED;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
serf_bucket_t *serf_bucket_ssl_decrypt_create(
Packit 3adb1e
    serf_bucket_t *stream,
Packit 3adb1e
    serf_ssl_context_t *ssl_ctx,
Packit 3adb1e
    serf_bucket_alloc_t *allocator)
Packit 3adb1e
{
Packit 3adb1e
    serf_bucket_t *bkt;
Packit 3adb1e
    ssl_context_t *ctx;
Packit 3adb1e
Packit 3adb1e
    bkt = serf_bucket_ssl_create(ssl_ctx, allocator,
Packit 3adb1e
                                 &serf_bucket_type_ssl_decrypt);
Packit 3adb1e
Packit 3adb1e
    ctx = bkt->data;
Packit 3adb1e
Packit 3adb1e
    ctx->databuf = &ctx->ssl_ctx->decrypt.databuf;
Packit 3adb1e
    if (ctx->ssl_ctx->decrypt.stream != NULL) {
Packit 3adb1e
        return NULL;
Packit 3adb1e
    }
Packit 3adb1e
    ctx->ssl_ctx->decrypt.stream = stream;
Packit 3adb1e
    ctx->our_stream = &ctx->ssl_ctx->decrypt.stream;
Packit 3adb1e
Packit 3adb1e
    return bkt;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
serf_ssl_context_t *serf_bucket_ssl_decrypt_context_get(
Packit 3adb1e
     serf_bucket_t *bucket)
Packit 3adb1e
{
Packit 3adb1e
    ssl_context_t *ctx = bucket->data;
Packit 3adb1e
    return ctx->ssl_ctx;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
serf_bucket_t *serf_bucket_ssl_encrypt_create(
Packit 3adb1e
    serf_bucket_t *stream,
Packit 3adb1e
    serf_ssl_context_t *ssl_ctx,
Packit 3adb1e
    serf_bucket_alloc_t *allocator)
Packit 3adb1e
{
Packit 3adb1e
    serf_bucket_t *bkt;
Packit 3adb1e
    ssl_context_t *ctx;
Packit 3adb1e
Packit 3adb1e
    bkt = serf_bucket_ssl_create(ssl_ctx, allocator,
Packit 3adb1e
                                 &serf_bucket_type_ssl_encrypt);
Packit 3adb1e
Packit 3adb1e
    ctx = bkt->data;
Packit 3adb1e
Packit 3adb1e
    ctx->databuf = &ctx->ssl_ctx->encrypt.databuf;
Packit 3adb1e
    ctx->our_stream = &ctx->ssl_ctx->encrypt.stream;
Packit 3adb1e
    if (ctx->ssl_ctx->encrypt.stream == NULL) {
Packit 3adb1e
        serf_bucket_t *tmp = serf_bucket_aggregate_create(stream->allocator);
Packit 3adb1e
        serf_bucket_aggregate_append(tmp, stream);
Packit 3adb1e
        ctx->ssl_ctx->encrypt.stream = tmp;
Packit 3adb1e
    }
Packit 3adb1e
    else {
Packit 3adb1e
        bucket_list_t *new_list;
Packit 3adb1e
Packit 3adb1e
        new_list = serf_bucket_mem_alloc(ctx->ssl_ctx->allocator,
Packit 3adb1e
                                         sizeof(*new_list));
Packit 3adb1e
        new_list->bucket = stream;
Packit 3adb1e
        new_list->next = NULL;
Packit 3adb1e
        if (ctx->ssl_ctx->encrypt.stream_next == NULL) {
Packit 3adb1e
            ctx->ssl_ctx->encrypt.stream_next = new_list;
Packit 3adb1e
        }
Packit 3adb1e
        else {
Packit 3adb1e
            bucket_list_t *scan = ctx->ssl_ctx->encrypt.stream_next;
Packit 3adb1e
Packit 3adb1e
            while (scan->next != NULL)
Packit 3adb1e
                scan = scan->next;
Packit 3adb1e
            scan->next = new_list;
Packit 3adb1e
        }
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    return bkt;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
serf_ssl_context_t *serf_bucket_ssl_encrypt_context_get(
Packit 3adb1e
     serf_bucket_t *bucket)
Packit 3adb1e
{
Packit 3adb1e
    ssl_context_t *ctx = bucket->data;
Packit 3adb1e
    return ctx->ssl_ctx;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
/* Functions to read a serf_ssl_certificate structure. */
Packit 3adb1e
Packit 3adb1e
/* Takes a counted length string and escapes any NUL bytes so that
Packit 3adb1e
 * it can be used as a C string.  NUL bytes are escaped as 3 characters
Packit 3adb1e
 * "\00" (that's a literal backslash).
Packit 3adb1e
 * The returned string is allocated in POOL.
Packit 3adb1e
 */
Packit 3adb1e
static char *
Packit 3adb1e
pstrdup_escape_nul_bytes(const char *buf, int len, apr_pool_t *pool)
Packit 3adb1e
{
Packit 3adb1e
    int i, nul_count = 0;
Packit 3adb1e
    char *ret;
Packit 3adb1e
Packit 3adb1e
    /* First determine if there are any nul bytes in the string. */
Packit 3adb1e
    for (i = 0; i < len; i++) {
Packit 3adb1e
        if (buf[i] == '\0')
Packit 3adb1e
            nul_count++;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    if (nul_count == 0) {
Packit 3adb1e
        /* There aren't so easy case to just copy the string */
Packit 3adb1e
        ret = apr_pstrdup(pool, buf);
Packit 3adb1e
    } else {
Packit 3adb1e
        /* There are so we have to replace nul bytes with escape codes
Packit 3adb1e
         * Proper length is the length of the original string, plus
Packit 3adb1e
         * 2 times the number of nulls (for two digit hex code for
Packit 3adb1e
         * the value) + the trailing null. */
Packit 3adb1e
        char *pos;
Packit 3adb1e
        ret = pos = apr_palloc(pool, len + 2 * nul_count + 1);
Packit 3adb1e
        for (i = 0; i < len; i++) {
Packit 3adb1e
            if (buf[i] != '\0') {
Packit 3adb1e
                *(pos++) = buf[i];
Packit 3adb1e
            } else {
Packit 3adb1e
                *(pos++) = '\\';
Packit 3adb1e
                *(pos++) = '0';
Packit 3adb1e
                *(pos++) = '0';
Packit 3adb1e
            }
Packit 3adb1e
        }
Packit 3adb1e
        *pos = '\0';
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    return ret;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
/* Creates a hash_table with keys (E, CN, OU, O, L, ST and C). Any NUL bytes in
Packit 3adb1e
   these fields in the certificate will be escaped as \00. */
Packit 3adb1e
static apr_hash_t *
Packit 3adb1e
convert_X509_NAME_to_table(X509_NAME *org, apr_pool_t *pool)
Packit 3adb1e
{
Packit 3adb1e
    char buf[1024];
Packit 3adb1e
    int ret;
Packit 3adb1e
Packit 3adb1e
    apr_hash_t *tgt = apr_hash_make(pool);
Packit 3adb1e
Packit 3adb1e
    ret = X509_NAME_get_text_by_NID(org,
Packit 3adb1e
                                    NID_commonName,
Packit 3adb1e
                                    buf, 1024);
Packit 3adb1e
    if (ret != -1)
Packit 3adb1e
        apr_hash_set(tgt, "CN", APR_HASH_KEY_STRING,
Packit 3adb1e
                     pstrdup_escape_nul_bytes(buf, ret, pool));
Packit 3adb1e
    ret = X509_NAME_get_text_by_NID(org,
Packit 3adb1e
                                    NID_pkcs9_emailAddress,
Packit 3adb1e
                                    buf, 1024);
Packit 3adb1e
    if (ret != -1)
Packit 3adb1e
        apr_hash_set(tgt, "E", APR_HASH_KEY_STRING,
Packit 3adb1e
                     pstrdup_escape_nul_bytes(buf, ret, pool));
Packit 3adb1e
    ret = X509_NAME_get_text_by_NID(org,
Packit 3adb1e
                                    NID_organizationalUnitName,
Packit 3adb1e
                                    buf, 1024);
Packit 3adb1e
    if (ret != -1)
Packit 3adb1e
        apr_hash_set(tgt, "OU", APR_HASH_KEY_STRING,
Packit 3adb1e
                     pstrdup_escape_nul_bytes(buf, ret, pool));
Packit 3adb1e
    ret = X509_NAME_get_text_by_NID(org,
Packit 3adb1e
                                    NID_organizationName,
Packit 3adb1e
                                    buf, 1024);
Packit 3adb1e
    if (ret != -1)
Packit 3adb1e
        apr_hash_set(tgt, "O", APR_HASH_KEY_STRING,
Packit 3adb1e
                     pstrdup_escape_nul_bytes(buf, ret, pool));
Packit 3adb1e
    ret = X509_NAME_get_text_by_NID(org,
Packit 3adb1e
                                    NID_localityName,
Packit 3adb1e
                                    buf, 1024);
Packit 3adb1e
    if (ret != -1)
Packit 3adb1e
        apr_hash_set(tgt, "L", APR_HASH_KEY_STRING,
Packit 3adb1e
                     pstrdup_escape_nul_bytes(buf, ret, pool));
Packit 3adb1e
    ret = X509_NAME_get_text_by_NID(org,
Packit 3adb1e
                                    NID_stateOrProvinceName,
Packit 3adb1e
                                    buf, 1024);
Packit 3adb1e
    if (ret != -1)
Packit 3adb1e
        apr_hash_set(tgt, "ST", APR_HASH_KEY_STRING,
Packit 3adb1e
                     pstrdup_escape_nul_bytes(buf, ret, pool));
Packit 3adb1e
    ret = X509_NAME_get_text_by_NID(org,
Packit 3adb1e
                                    NID_countryName,
Packit 3adb1e
                                    buf, 1024);
Packit 3adb1e
    if (ret != -1)
Packit 3adb1e
        apr_hash_set(tgt, "C", APR_HASH_KEY_STRING,
Packit 3adb1e
                     pstrdup_escape_nul_bytes(buf, ret, pool));
Packit 3adb1e
Packit 3adb1e
    return tgt;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
int serf_ssl_cert_depth(const serf_ssl_certificate_t *cert)
Packit 3adb1e
{
Packit 3adb1e
    return cert->depth;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
apr_hash_t *serf_ssl_cert_issuer(
Packit 3adb1e
    const serf_ssl_certificate_t *cert,
Packit 3adb1e
    apr_pool_t *pool)
Packit 3adb1e
{
Packit 3adb1e
    X509_NAME *issuer = X509_get_issuer_name(cert->ssl_cert);
Packit 3adb1e
Packit 3adb1e
    if (!issuer)
Packit 3adb1e
        return NULL;
Packit 3adb1e
Packit 3adb1e
    return convert_X509_NAME_to_table(issuer, pool);
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
apr_hash_t *serf_ssl_cert_subject(
Packit 3adb1e
    const serf_ssl_certificate_t *cert,
Packit 3adb1e
    apr_pool_t *pool)
Packit 3adb1e
{
Packit 3adb1e
    X509_NAME *subject = X509_get_subject_name(cert->ssl_cert);
Packit 3adb1e
Packit 3adb1e
    if (!subject)
Packit 3adb1e
        return NULL;
Packit 3adb1e
Packit 3adb1e
    return convert_X509_NAME_to_table(subject, pool);
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
apr_hash_t *serf_ssl_cert_certificate(
Packit 3adb1e
    const serf_ssl_certificate_t *cert,
Packit 3adb1e
    apr_pool_t *pool)
Packit 3adb1e
{
Packit 3adb1e
    apr_hash_t *tgt = apr_hash_make(pool);
Packit 3adb1e
    unsigned int md_size, i;
Packit 3adb1e
    unsigned char md[EVP_MAX_MD_SIZE];
Packit 3adb1e
    BIO *bio;
Packit 3adb1e
    apr_array_header_t *san_arr;
Packit 3adb1e
Packit 3adb1e
    /* sha1 fingerprint */
Packit 3adb1e
    if (X509_digest(cert->ssl_cert, EVP_sha1(), md, &md_size)) {
Packit 3adb1e
        const char hex[] = "0123456789ABCDEF";
Packit 3adb1e
        char fingerprint[EVP_MAX_MD_SIZE * 3];
Packit 3adb1e
Packit 3adb1e
        for (i=0; i
Packit 3adb1e
            fingerprint[3*i] = hex[(md[i] & 0xf0) >> 4];
Packit 3adb1e
            fingerprint[(3*i)+1] = hex[(md[i] & 0x0f)];
Packit 3adb1e
            fingerprint[(3*i)+2] = ':';
Packit 3adb1e
        }
Packit 3adb1e
        if (md_size > 0)
Packit 3adb1e
            fingerprint[(3*(md_size-1))+2] = '\0';
Packit 3adb1e
        else
Packit 3adb1e
            fingerprint[0] = '\0';
Packit 3adb1e
Packit 3adb1e
        apr_hash_set(tgt, "sha1", APR_HASH_KEY_STRING,
Packit 3adb1e
                     apr_pstrdup(pool, fingerprint));
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    /* set expiry dates */
Packit 3adb1e
    bio = BIO_new(BIO_s_mem());
Packit 3adb1e
    if (bio) {
Packit 3adb1e
        ASN1_TIME *notBefore, *notAfter;
Packit 3adb1e
        char buf[256];
Packit 3adb1e
Packit 3adb1e
        memset (buf, 0, sizeof (buf));
Packit 3adb1e
        notBefore = X509_get_notBefore(cert->ssl_cert);
Packit 3adb1e
        if (ASN1_TIME_print(bio, notBefore)) {
Packit 3adb1e
            BIO_read(bio, buf, 255);
Packit 3adb1e
            apr_hash_set(tgt, "notBefore", APR_HASH_KEY_STRING,
Packit 3adb1e
                         apr_pstrdup(pool, buf));
Packit 3adb1e
        }
Packit 3adb1e
        memset (buf, 0, sizeof (buf));
Packit 3adb1e
        notAfter = X509_get_notAfter(cert->ssl_cert);
Packit 3adb1e
        if (ASN1_TIME_print(bio, notAfter)) {
Packit 3adb1e
            BIO_read(bio, buf, 255);
Packit 3adb1e
            apr_hash_set(tgt, "notAfter", APR_HASH_KEY_STRING,
Packit 3adb1e
                         apr_pstrdup(pool, buf));
Packit 3adb1e
        }
Packit 3adb1e
    }
Packit 3adb1e
    BIO_free(bio);
Packit 3adb1e
Packit 3adb1e
    /* Get subjectAltNames */
Packit 3adb1e
    if (!get_subject_alt_names(&san_arr, cert->ssl_cert, EscapeNulAndCopy, pool))
Packit 3adb1e
        apr_hash_set(tgt, "subjectAltName", APR_HASH_KEY_STRING, san_arr);
Packit 3adb1e
Packit 3adb1e
    return tgt;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
const char *serf_ssl_cert_export(
Packit 3adb1e
    const serf_ssl_certificate_t *cert,
Packit 3adb1e
    apr_pool_t *pool)
Packit 3adb1e
{
Packit 3adb1e
    char *binary_cert;
Packit 3adb1e
    char *encoded_cert;
Packit 3adb1e
    int len;
Packit 3adb1e
    unsigned char *unused;
Packit 3adb1e
Packit 3adb1e
    /* find the length of the DER encoding. */
Packit 3adb1e
    len = i2d_X509(cert->ssl_cert, NULL);
Packit 3adb1e
    if (len < 0) {
Packit 3adb1e
        return NULL;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    binary_cert = apr_palloc(pool, len);
Packit 3adb1e
    unused = (unsigned char *)binary_cert;
Packit 3adb1e
    len = i2d_X509(cert->ssl_cert, &unused);  /* unused is incremented  */
Packit 3adb1e
    if (len < 0) {
Packit 3adb1e
        return NULL;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    encoded_cert = apr_palloc(pool, apr_base64_encode_len(len));
Packit 3adb1e
    apr_base64_encode(encoded_cert, binary_cert, len);
Packit 3adb1e
    
Packit 3adb1e
    return encoded_cert;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
/* Disables compression for all SSL sessions. */
Packit 3adb1e
static void disable_compression(serf_ssl_context_t *ssl_ctx)
Packit 3adb1e
{
Packit 3adb1e
#ifdef SSL_OP_NO_COMPRESSION
Packit 3adb1e
    SSL_CTX_set_options(ssl_ctx->ctx, SSL_OP_NO_COMPRESSION);
Packit 3adb1e
#endif
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
apr_status_t serf_ssl_use_compression(serf_ssl_context_t *ssl_ctx, int enabled)
Packit 3adb1e
{
Packit 3adb1e
    if (enabled) {
Packit 3adb1e
#ifdef SSL_OP_NO_COMPRESSION
Packit 3adb1e
        SSL_clear_options(ssl_ctx->ssl, SSL_OP_NO_COMPRESSION);
Packit 3adb1e
        return APR_SUCCESS;
Packit 3adb1e
#endif
Packit 3adb1e
    } else {
Packit 3adb1e
#ifdef SSL_OP_NO_COMPRESSION
Packit 3adb1e
        SSL_set_options(ssl_ctx->ssl, SSL_OP_NO_COMPRESSION);
Packit 3adb1e
        return APR_SUCCESS;
Packit 3adb1e
#endif
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    return APR_EGENERAL;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static void serf_ssl_destroy_and_data(serf_bucket_t *bucket)
Packit 3adb1e
{
Packit 3adb1e
    ssl_context_t *ctx = bucket->data;
Packit 3adb1e
Packit 3adb1e
    if (!--ctx->ssl_ctx->refcount) {
Packit 3adb1e
        ssl_free_context(ctx->ssl_ctx);
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    serf_default_destroy_and_data(bucket);
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static void serf_ssl_decrypt_destroy_and_data(serf_bucket_t *bucket)
Packit 3adb1e
{
Packit 3adb1e
    ssl_context_t *ctx = bucket->data;
Packit 3adb1e
Packit 3adb1e
    serf_bucket_destroy(*ctx->our_stream);
Packit 3adb1e
Packit 3adb1e
    serf_ssl_destroy_and_data(bucket);
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static void serf_ssl_encrypt_destroy_and_data(serf_bucket_t *bucket)
Packit 3adb1e
{
Packit 3adb1e
    ssl_context_t *ctx = bucket->data;
Packit 3adb1e
    serf_ssl_context_t *ssl_ctx = ctx->ssl_ctx;
Packit 3adb1e
Packit 3adb1e
    if (ssl_ctx->encrypt.stream == *ctx->our_stream) {
Packit 3adb1e
        serf_bucket_destroy(*ctx->our_stream);
Packit 3adb1e
        serf_bucket_destroy(ssl_ctx->encrypt.pending);
Packit 3adb1e
Packit 3adb1e
        /* Reset our encrypted status and databuf. */
Packit 3adb1e
        ssl_ctx->encrypt.status = APR_SUCCESS;
Packit 3adb1e
        ssl_ctx->encrypt.databuf.status = APR_SUCCESS;
Packit 3adb1e
Packit 3adb1e
        /* Advance to the next stream - if we have one. */
Packit 3adb1e
        if (ssl_ctx->encrypt.stream_next == NULL) {
Packit 3adb1e
            ssl_ctx->encrypt.stream = NULL;
Packit 3adb1e
            ssl_ctx->encrypt.pending = NULL;
Packit 3adb1e
        }
Packit 3adb1e
        else {
Packit 3adb1e
            bucket_list_t *cur;
Packit 3adb1e
Packit 3adb1e
            cur = ssl_ctx->encrypt.stream_next;
Packit 3adb1e
            ssl_ctx->encrypt.stream = cur->bucket;
Packit 3adb1e
            ssl_ctx->encrypt.pending =
Packit 3adb1e
                serf_bucket_aggregate_create(cur->bucket->allocator);
Packit 3adb1e
            ssl_ctx->encrypt.stream_next = cur->next;
Packit 3adb1e
            serf_bucket_mem_free(ssl_ctx->allocator, cur);
Packit 3adb1e
        }
Packit 3adb1e
    }
Packit 3adb1e
    else {
Packit 3adb1e
        /* Ah, darn.  We haven't sent this one along yet. */
Packit 3adb1e
        return;
Packit 3adb1e
    }
Packit 3adb1e
    serf_ssl_destroy_and_data(bucket);
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static apr_status_t serf_ssl_read(serf_bucket_t *bucket,
Packit 3adb1e
                                  apr_size_t requested,
Packit 3adb1e
                                  const char **data, apr_size_t *len)
Packit 3adb1e
{
Packit 3adb1e
    ssl_context_t *ctx = bucket->data;
Packit 3adb1e
Packit 3adb1e
    return serf_databuf_read(ctx->databuf, requested, data, len);
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static apr_status_t serf_ssl_readline(serf_bucket_t *bucket,
Packit 3adb1e
                                      int acceptable, int *found,
Packit 3adb1e
                                      const char **data,
Packit 3adb1e
                                      apr_size_t *len)
Packit 3adb1e
{
Packit 3adb1e
    ssl_context_t *ctx = bucket->data;
Packit 3adb1e
Packit 3adb1e
    return serf_databuf_readline(ctx->databuf, acceptable, found, data, len);
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
static apr_status_t serf_ssl_peek(serf_bucket_t *bucket,
Packit 3adb1e
                                  const char **data,
Packit 3adb1e
                                  apr_size_t *len)
Packit 3adb1e
{
Packit 3adb1e
    ssl_context_t *ctx = bucket->data;
Packit 3adb1e
Packit 3adb1e
    return serf_databuf_peek(ctx->databuf, data, len);
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
const serf_bucket_type_t serf_bucket_type_ssl_encrypt = {
Packit 3adb1e
    "SSLENCRYPT",
Packit 3adb1e
    serf_ssl_read,
Packit 3adb1e
    serf_ssl_readline,
Packit 3adb1e
    serf_default_read_iovec,
Packit 3adb1e
    serf_default_read_for_sendfile,
Packit 3adb1e
    serf_default_read_bucket,
Packit 3adb1e
    serf_ssl_peek,
Packit 3adb1e
    serf_ssl_encrypt_destroy_and_data,
Packit 3adb1e
};
Packit 3adb1e
Packit 3adb1e
const serf_bucket_type_t serf_bucket_type_ssl_decrypt = {
Packit 3adb1e
    "SSLDECRYPT",
Packit 3adb1e
    serf_ssl_read,
Packit 3adb1e
    serf_ssl_readline,
Packit 3adb1e
    serf_default_read_iovec,
Packit 3adb1e
    serf_default_read_for_sendfile,
Packit 3adb1e
    serf_default_read_bucket,
Packit 3adb1e
    serf_ssl_peek,
Packit 3adb1e
    serf_ssl_decrypt_destroy_and_data,
Packit 3adb1e
};