1251877Speter/* Copyright 2002-2004 Justin Erenkrantz and Greg Stein
2251877Speter *
3251877Speter * Licensed under the Apache License, Version 2.0 (the "License");
4251877Speter * you may not use this file except in compliance with the License.
5251877Speter * You may obtain a copy of the License at
6251877Speter *
7251877Speter *     http://www.apache.org/licenses/LICENSE-2.0
8251877Speter *
9251877Speter * Unless required by applicable law or agreed to in writing, software
10251877Speter * distributed under the License is distributed on an "AS IS" BASIS,
11251877Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12251877Speter * See the License for the specific language governing permissions and
13251877Speter * limitations under the License.
14251877Speter *
15251877Speter * ----
16251877Speter *
17251877Speter * For the OpenSSL thread-safety locking code:
18251877Speter *
19251877Speter * Licensed to the Apache Software Foundation (ASF) under one or more
20251877Speter * contributor license agreements.  See the NOTICE file distributed with
21251877Speter * this work for additional information regarding copyright ownership.
22251877Speter * The ASF licenses this file to You under the Apache License, Version 2.0
23251877Speter * (the "License"); you may not use this file except in compliance with
24251877Speter * the License.  You may obtain a copy of the License at
25251877Speter *
26251877Speter *     http://www.apache.org/licenses/LICENSE-2.0
27251877Speter *
28251877Speter * Unless required by applicable law or agreed to in writing, software
29251877Speter * distributed under the License is distributed on an "AS IS" BASIS,
30251877Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31251877Speter * See the License for the specific language governing permissions and
32251877Speter * limitations under the License.
33251877Speter *
34251877Speter * Originally developed by Aaron Bannert and Justin Erenkrantz, eBuilt.
35251877Speter */
36251877Speter
37251877Speter#include <apr_pools.h>
38251877Speter#include <apr_network_io.h>
39251877Speter#include <apr_portable.h>
40251877Speter#include <apr_strings.h>
41251877Speter#include <apr_base64.h>
42251877Speter#include <apr_version.h>
43251877Speter#include <apr_atomic.h>
44251877Speter
45251877Speter#include "serf.h"
46251877Speter#include "serf_private.h"
47251877Speter#include "serf_bucket_util.h"
48251877Speter
49251877Speter#include <openssl/bio.h>
50251877Speter#include <openssl/ssl.h>
51251877Speter#include <openssl/err.h>
52251877Speter#include <openssl/pkcs12.h>
53251877Speter#include <openssl/x509v3.h>
54251877Speter
55251877Speter#ifndef APR_VERSION_AT_LEAST /* Introduced in APR 1.3.0 */
56251877Speter#define APR_VERSION_AT_LEAST(major,minor,patch)                           \
57251877Speter    (((major) < APR_MAJOR_VERSION)                                        \
58251877Speter      || ((major) == APR_MAJOR_VERSION && (minor) < APR_MINOR_VERSION)    \
59251877Speter      || ((major) == APR_MAJOR_VERSION && (minor) == APR_MINOR_VERSION && \
60251877Speter               (patch) <= APR_PATCH_VERSION))
61251877Speter#endif /* APR_VERSION_AT_LEAST */
62251877Speter
63251877Speter#ifndef APR_ARRAY_PUSH
64251877Speter#define APR_ARRAY_PUSH(ary,type) (*((type *)apr_array_push(ary)))
65251877Speter#endif
66251877Speter
67251877Speter
68251877Speter/*
69251877Speter * Here's an overview of the SSL bucket's relationship to OpenSSL and serf.
70251877Speter *
71251877Speter * HTTP request:  SSLENCRYPT(REQUEST)
72251877Speter *   [context.c reads from SSLENCRYPT and writes out to the socket]
73251877Speter * HTTP response: RESPONSE(SSLDECRYPT(SOCKET))
74251877Speter *   [handler function reads from RESPONSE which in turn reads from SSLDECRYPT]
75251877Speter *
76251877Speter * HTTP request read call path:
77251877Speter *
78251877Speter * write_to_connection
79251877Speter *  |- serf_bucket_read on SSLENCRYPT
80251877Speter *    |- serf_ssl_read
81251877Speter *      |- serf_databuf_read
82251877Speter *        |- common_databuf_prep
83251877Speter *          |- ssl_encrypt
84251877Speter *            |- 1. Try to read pending encrypted data; If available, return.
85251877Speter *            |- 2. Try to read from ctx->stream [REQUEST bucket]
86251877Speter *            |- 3. Call SSL_write with read data
87251877Speter *              |- ...
88251877Speter *                |- bio_bucket_read can be called
89251877Speter *                |- bio_bucket_write with encrypted data
90251877Speter *                  |- store in sink
91251877Speter *            |- 4. If successful, read pending encrypted data and return.
92251877Speter *            |- 5. If fails, place read data back in ctx->stream
93251877Speter *
94251877Speter * HTTP response read call path:
95251877Speter *
96251877Speter * read_from_connection
97251877Speter *  |- acceptor
98251877Speter *  |- handler
99251877Speter *    |- ...
100251877Speter *      |- serf_bucket_read(SSLDECRYPT)
101251877Speter *        |- serf_ssl_read
102251877Speter *          |- serf_databuf_read
103251877Speter *            |- ssl_decrypt
104251877Speter *              |- 1. SSL_read() for pending decrypted data; if any, return.
105251877Speter *              |- 2. Try to read from ctx->stream [SOCKET bucket]
106251877Speter *              |- 3. Append data to ssl_ctx->source
107251877Speter *              |- 4. Call SSL_read()
108251877Speter *                |- ...
109251877Speter *                  |- bio_bucket_write can be called
110251877Speter *                  |- bio_bucket_read
111251877Speter *                    |- read data from ssl_ctx->source
112251877Speter *              |- If data read, return it.
113251877Speter *              |- If an error, set the STATUS value and return.
114251877Speter *
115251877Speter */
116251877Speter
117251877Spetertypedef struct bucket_list {
118251877Speter    serf_bucket_t *bucket;
119251877Speter    struct bucket_list *next;
120251877Speter} bucket_list_t;
121251877Speter
122251877Spetertypedef struct {
123251877Speter    /* Helper to read data. Wraps stream. */
124251877Speter    serf_databuf_t databuf;
125251877Speter
126251877Speter    /* Our source for more data. */
127251877Speter    serf_bucket_t *stream;
128251877Speter
129251877Speter    /* The next set of buckets */
130251877Speter    bucket_list_t *stream_next;
131251877Speter
132251877Speter    /* The status of the last thing we read. */
133251877Speter    apr_status_t status;
134251877Speter    apr_status_t exhausted;
135251877Speter    int exhausted_reset;
136251877Speter
137251877Speter    /* Data we've read but not processed. */
138251877Speter    serf_bucket_t *pending;
139251877Speter} serf_ssl_stream_t;
140251877Speter
141251877Speterstruct serf_ssl_context_t {
142251877Speter    /* How many open buckets refer to this context. */
143251877Speter    int refcount;
144251877Speter
145251877Speter    /* The pool that this context uses. */
146251877Speter    apr_pool_t *pool;
147251877Speter
148251877Speter    /* The allocator associated with the above pool. */
149251877Speter    serf_bucket_alloc_t *allocator;
150251877Speter
151251877Speter    /* Internal OpenSSL parameters */
152251877Speter    SSL_CTX *ctx;
153251877Speter    SSL *ssl;
154251877Speter    BIO *bio;
155251877Speter
156251877Speter    serf_ssl_stream_t encrypt;
157251877Speter    serf_ssl_stream_t decrypt;
158251877Speter
159251877Speter    /* Client cert callbacks */
160251877Speter    serf_ssl_need_client_cert_t cert_callback;
161251877Speter    void *cert_userdata;
162251877Speter    apr_pool_t *cert_cache_pool;
163251877Speter    const char *cert_file_success;
164251877Speter
165251877Speter    /* Client cert PW callbacks */
166251877Speter    serf_ssl_need_cert_password_t cert_pw_callback;
167251877Speter    void *cert_pw_userdata;
168251877Speter    apr_pool_t *cert_pw_cache_pool;
169251877Speter    const char *cert_pw_success;
170251877Speter
171251877Speter    /* Server cert callbacks */
172251877Speter    serf_ssl_need_server_cert_t server_cert_callback;
173251877Speter    serf_ssl_server_cert_chain_cb_t server_cert_chain_callback;
174251877Speter    void *server_cert_userdata;
175251877Speter
176251877Speter    const char *cert_path;
177251877Speter
178251877Speter    X509 *cached_cert;
179251877Speter    EVP_PKEY *cached_cert_pw;
180251877Speter
181251877Speter    apr_status_t pending_err;
182251877Speter
183251877Speter    /* Status of a fatal error, returned on subsequent encrypt or decrypt
184251877Speter       requests. */
185251877Speter    apr_status_t fatal_err;
186251877Speter};
187251877Speter
188251877Spetertypedef struct {
189251877Speter    /* The bucket-independent ssl context that this bucket is associated with */
190251877Speter    serf_ssl_context_t *ssl_ctx;
191251877Speter
192251877Speter    /* Pointer to the 'right' databuf. */
193251877Speter    serf_databuf_t *databuf;
194251877Speter
195251877Speter    /* Pointer to our stream, so we can find it later. */
196251877Speter    serf_bucket_t **our_stream;
197251877Speter} ssl_context_t;
198251877Speter
199251877Speterstruct serf_ssl_certificate_t {
200251877Speter    X509 *ssl_cert;
201251877Speter    int depth;
202251877Speter};
203251877Speter
204251877Speterstatic void disable_compression(serf_ssl_context_t *ssl_ctx);
205269847Speterstatic char *
206269847Speter    pstrdup_escape_nul_bytes(const char *buf, int len, apr_pool_t *pool);
207251877Speter
208251877Speter#if SSL_VERBOSE
209251877Speter/* Log all ssl alerts that we receive from the server. */
210251877Speterstatic void
211251877Speterapps_ssl_info_callback(const SSL *s, int where, int ret)
212251877Speter{
213251877Speter    const char *str;
214251877Speter    int w;
215251877Speter    w = where & ~SSL_ST_MASK;
216253895Speter
217251877Speter    if (w & SSL_ST_CONNECT)
218251877Speter        str = "SSL_connect";
219251877Speter    else if (w & SSL_ST_ACCEPT)
220251877Speter        str = "SSL_accept";
221251877Speter    else
222251877Speter        str = "undefined";
223253895Speter
224251877Speter    if (where & SSL_CB_LOOP) {
225251877Speter        serf__log(SSL_VERBOSE, __FILE__, "%s:%s\n", str,
226251877Speter                  SSL_state_string_long(s));
227251877Speter    }
228251877Speter    else if (where & SSL_CB_ALERT) {
229251877Speter        str = (where & SSL_CB_READ) ? "read" : "write";
230251877Speter        serf__log(SSL_VERBOSE, __FILE__, "SSL3 alert %s:%s:%s\n",
231251877Speter               str,
232251877Speter               SSL_alert_type_string_long(ret),
233251877Speter               SSL_alert_desc_string_long(ret));
234251877Speter    }
235251877Speter    else if (where & SSL_CB_EXIT) {
236251877Speter        if (ret == 0)
237251877Speter            serf__log(SSL_VERBOSE, __FILE__, "%s:failed in %s\n", str,
238251877Speter                      SSL_state_string_long(s));
239251877Speter        else if (ret < 0) {
240251877Speter            serf__log(SSL_VERBOSE, __FILE__, "%s:error in %s\n", str,
241251877Speter                      SSL_state_string_long(s));
242251877Speter        }
243251877Speter    }
244251877Speter}
245251877Speter#endif
246251877Speter
247251877Speter/* Returns the amount read. */
248251877Speterstatic int bio_bucket_read(BIO *bio, char *in, int inlen)
249251877Speter{
250251877Speter    serf_ssl_context_t *ctx = bio->ptr;
251251877Speter    const char *data;
252251877Speter    apr_status_t status;
253251877Speter    apr_size_t len;
254251877Speter
255251877Speter    serf__log(SSL_VERBOSE, __FILE__, "bio_bucket_read called for %d bytes\n",
256251877Speter              inlen);
257251877Speter
258251877Speter    if (ctx->encrypt.status == SERF_ERROR_WAIT_CONN
259251877Speter        && BIO_should_read(ctx->bio)) {
260253895Speter        serf__log(SSL_VERBOSE, __FILE__,
261253895Speter                  "bio_bucket_read waiting: (%d %d %d)\n",
262251877Speter           BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
263251877Speter           BIO_get_retry_flags(ctx->bio));
264251877Speter        /* Falling back... */
265251877Speter        ctx->encrypt.exhausted_reset = 1;
266251877Speter        BIO_clear_retry_flags(bio);
267251877Speter    }
268251877Speter
269251877Speter    status = serf_bucket_read(ctx->decrypt.pending, inlen, &data, &len);
270251877Speter
271251877Speter    ctx->decrypt.status = status;
272251877Speter
273251877Speter    serf__log(SSL_VERBOSE, __FILE__, "bio_bucket_read received %d bytes (%d)\n",
274251877Speter              len, status);
275251877Speter
276251877Speter    if (!SERF_BUCKET_READ_ERROR(status)) {
277251877Speter        /* Oh suck. */
278251877Speter        if (len) {
279251877Speter            memcpy(in, data, len);
280251877Speter            return len;
281251877Speter        }
282251877Speter        if (APR_STATUS_IS_EOF(status)) {
283251877Speter            BIO_set_retry_read(bio);
284251877Speter            return -1;
285251877Speter        }
286251877Speter    }
287251877Speter
288251877Speter    return -1;
289251877Speter}
290251877Speter
291251877Speter/* Returns the amount written. */
292251877Speterstatic int bio_bucket_write(BIO *bio, const char *in, int inl)
293251877Speter{
294251877Speter    serf_ssl_context_t *ctx = bio->ptr;
295251877Speter    serf_bucket_t *tmp;
296251877Speter
297251877Speter    serf__log(SSL_VERBOSE, __FILE__, "bio_bucket_write called for %d bytes\n",
298251877Speter              inl);
299251877Speter
300251877Speter    if (ctx->encrypt.status == SERF_ERROR_WAIT_CONN
301251877Speter        && !BIO_should_read(ctx->bio)) {
302253895Speter        serf__log(SSL_VERBOSE, __FILE__,
303253895Speter                  "bio_bucket_write waiting: (%d %d %d)\n",
304251877Speter           BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
305251877Speter           BIO_get_retry_flags(ctx->bio));
306251877Speter        /* Falling back... */
307251877Speter        ctx->encrypt.exhausted_reset = 1;
308251877Speter        BIO_clear_retry_flags(bio);
309251877Speter    }
310251877Speter
311251877Speter    tmp = serf_bucket_simple_copy_create(in, inl,
312251877Speter                                         ctx->encrypt.pending->allocator);
313251877Speter
314251877Speter    serf_bucket_aggregate_append(ctx->encrypt.pending, tmp);
315251877Speter
316251877Speter    return inl;
317251877Speter}
318251877Speter
319251877Speter/* Returns the amount read. */
320251877Speterstatic int bio_file_read(BIO *bio, char *in, int inlen)
321251877Speter{
322251877Speter    apr_file_t *file = bio->ptr;
323251877Speter    apr_status_t status;
324251877Speter    apr_size_t len;
325251877Speter
326251877Speter    BIO_clear_retry_flags(bio);
327251877Speter
328251877Speter    len = inlen;
329251877Speter    status = apr_file_read(file, in, &len);
330251877Speter
331251877Speter    if (!SERF_BUCKET_READ_ERROR(status)) {
332251877Speter        /* Oh suck. */
333251877Speter        if (APR_STATUS_IS_EOF(status)) {
334251877Speter            BIO_set_retry_read(bio);
335251877Speter            return -1;
336251877Speter        } else {
337251877Speter            return len;
338251877Speter        }
339251877Speter    }
340251877Speter
341251877Speter    return -1;
342251877Speter}
343251877Speter
344251877Speter/* Returns the amount written. */
345251877Speterstatic int bio_file_write(BIO *bio, const char *in, int inl)
346251877Speter{
347251877Speter    apr_file_t *file = bio->ptr;
348251877Speter    apr_size_t nbytes;
349251877Speter
350251877Speter    BIO_clear_retry_flags(bio);
351251877Speter
352251877Speter    nbytes = inl;
353251877Speter    apr_file_write(file, in, &nbytes);
354251877Speter
355251877Speter    return nbytes;
356251877Speter}
357251877Speter
358251877Speterstatic int bio_file_gets(BIO *bio, char *in, int inlen)
359251877Speter{
360251877Speter    return bio_file_read(bio, in, inlen);
361251877Speter}
362251877Speter
363251877Speterstatic int bio_bucket_create(BIO *bio)
364251877Speter{
365251877Speter    bio->shutdown = 1;
366251877Speter    bio->init = 1;
367251877Speter    bio->num = -1;
368251877Speter    bio->ptr = NULL;
369251877Speter
370251877Speter    return 1;
371251877Speter}
372251877Speter
373251877Speterstatic int bio_bucket_destroy(BIO *bio)
374251877Speter{
375251877Speter    /* Did we already free this? */
376251877Speter    if (bio == NULL) {
377251877Speter        return 0;
378251877Speter    }
379251877Speter
380251877Speter    return 1;
381251877Speter}
382251877Speter
383251877Speterstatic long bio_bucket_ctrl(BIO *bio, int cmd, long num, void *ptr)
384251877Speter{
385251877Speter    long ret = 1;
386251877Speter
387251877Speter    switch (cmd) {
388251877Speter    default:
389251877Speter        /* abort(); */
390251877Speter        break;
391251877Speter    case BIO_CTRL_FLUSH:
392251877Speter        /* At this point we can't force a flush. */
393251877Speter        break;
394251877Speter    case BIO_CTRL_PUSH:
395251877Speter    case BIO_CTRL_POP:
396251877Speter        ret = 0;
397251877Speter        break;
398251877Speter    }
399251877Speter    return ret;
400251877Speter}
401251877Speter
402251877Speterstatic BIO_METHOD bio_bucket_method = {
403251877Speter    BIO_TYPE_MEM,
404251877Speter    "Serf SSL encryption and decryption buckets",
405251877Speter    bio_bucket_write,
406251877Speter    bio_bucket_read,
407251877Speter    NULL,                        /* Is this called? */
408251877Speter    NULL,                        /* Is this called? */
409251877Speter    bio_bucket_ctrl,
410251877Speter    bio_bucket_create,
411251877Speter    bio_bucket_destroy,
412251877Speter#ifdef OPENSSL_VERSION_NUMBER
413251877Speter    NULL /* sslc does not have the callback_ctrl field */
414251877Speter#endif
415251877Speter};
416251877Speter
417251877Speterstatic BIO_METHOD bio_file_method = {
418251877Speter    BIO_TYPE_FILE,
419251877Speter    "Wrapper around APR file structures",
420251877Speter    bio_file_write,
421251877Speter    bio_file_read,
422251877Speter    NULL,                        /* Is this called? */
423251877Speter    bio_file_gets,               /* Is this called? */
424251877Speter    bio_bucket_ctrl,
425251877Speter    bio_bucket_create,
426251877Speter    bio_bucket_destroy,
427251877Speter#ifdef OPENSSL_VERSION_NUMBER
428251877Speter    NULL /* sslc does not have the callback_ctrl field */
429251877Speter#endif
430251877Speter};
431251877Speter
432269847Spetertypedef enum san_copy_t {
433269847Speter    EscapeNulAndCopy = 0,
434269847Speter    ErrorOnNul = 1,
435269847Speter} san_copy_t;
436269847Speter
437269847Speter
438269847Speterstatic apr_status_t
439269847Speterget_subject_alt_names(apr_array_header_t **san_arr, X509 *ssl_cert,
440269847Speter                      san_copy_t copy_action, apr_pool_t *pool)
441269847Speter{
442269847Speter    STACK_OF(GENERAL_NAME) *names;
443269847Speter
444269847Speter    /* assert: copy_action == ErrorOnNul || (san_arr && pool) */
445269847Speter
446269847Speter    if (san_arr) {
447269847Speter        *san_arr = NULL;
448269847Speter    }
449269847Speter
450269847Speter    /* Get subjectAltNames */
451269847Speter    names = X509_get_ext_d2i(ssl_cert, NID_subject_alt_name, NULL, NULL);
452269847Speter    if (names) {
453269847Speter        int names_count = sk_GENERAL_NAME_num(names);
454269847Speter        int name_idx;
455269847Speter
456269847Speter        if (san_arr)
457269847Speter            *san_arr = apr_array_make(pool, names_count, sizeof(char*));
458269847Speter        for (name_idx = 0; name_idx < names_count; name_idx++) {
459269847Speter            char *p = NULL;
460269847Speter            GENERAL_NAME *nm = sk_GENERAL_NAME_value(names, name_idx);
461269847Speter
462269847Speter            switch (nm->type) {
463269847Speter                case GEN_DNS:
464269847Speter                    if (copy_action == ErrorOnNul &&
465269847Speter                        strlen(nm->d.ia5->data) != nm->d.ia5->length)
466269847Speter                        return SERF_ERROR_SSL_CERT_FAILED;
467269847Speter                    if (san_arr && *san_arr)
468269847Speter                        p = pstrdup_escape_nul_bytes((const char *)nm->d.ia5->data,
469269847Speter                                                     nm->d.ia5->length,
470269847Speter                                                     pool);
471269847Speter                    break;
472269847Speter                default:
473269847Speter                    /* Don't know what to do - skip. */
474269847Speter                    break;
475269847Speter            }
476269847Speter
477269847Speter            if (p) {
478269847Speter                APR_ARRAY_PUSH(*san_arr, char*) = p;
479269847Speter            }
480269847Speter        }
481269847Speter        sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
482269847Speter    }
483269847Speter
484269847Speter    return APR_SUCCESS;
485269847Speter}
486269847Speter
487269847Speterstatic apr_status_t validate_cert_hostname(X509 *server_cert, apr_pool_t *pool)
488269847Speter{
489269847Speter    char buf[1024];
490269847Speter    int length;
491269847Speter    apr_status_t ret;
492269847Speter
493269847Speter    ret = get_subject_alt_names(NULL, server_cert, ErrorOnNul, NULL);
494269847Speter    if (ret) {
495269847Speter      return ret;
496269847Speter    } else {
497269847Speter        /* Fail if the subject's CN field contains \0 characters. */
498269847Speter        X509_NAME *subject = X509_get_subject_name(server_cert);
499269847Speter        if (!subject)
500269847Speter            return SERF_ERROR_SSL_CERT_FAILED;
501269847Speter
502269847Speter        length = X509_NAME_get_text_by_NID(subject, NID_commonName, buf, 1024);
503269847Speter        if (length != -1)
504269847Speter            if (strlen(buf) != length)
505269847Speter                return SERF_ERROR_SSL_CERT_FAILED;
506269847Speter    }
507269847Speter
508269847Speter    return APR_SUCCESS;
509269847Speter}
510269847Speter
511251877Speterstatic int
512251877Spetervalidate_server_certificate(int cert_valid, X509_STORE_CTX *store_ctx)
513251877Speter{
514251877Speter    SSL *ssl;
515251877Speter    serf_ssl_context_t *ctx;
516251877Speter    X509 *server_cert;
517251877Speter    int err, depth;
518251877Speter    int failures = 0;
519269847Speter    apr_status_t status;
520251877Speter
521251877Speter    ssl = X509_STORE_CTX_get_ex_data(store_ctx,
522251877Speter                                     SSL_get_ex_data_X509_STORE_CTX_idx());
523251877Speter    ctx = SSL_get_app_data(ssl);
524251877Speter
525251877Speter    server_cert = X509_STORE_CTX_get_current_cert(store_ctx);
526251877Speter    depth = X509_STORE_CTX_get_error_depth(store_ctx);
527251877Speter
528251877Speter    /* If the certification was found invalid, get the error and convert it to
529251877Speter       something our caller will understand. */
530251877Speter    if (! cert_valid) {
531251877Speter        err = X509_STORE_CTX_get_error(store_ctx);
532251877Speter
533251877Speter        switch(err) {
534251877Speter            case X509_V_ERR_CERT_NOT_YET_VALID:
535251877Speter                    failures |= SERF_SSL_CERT_NOTYETVALID;
536251877Speter                    break;
537251877Speter            case X509_V_ERR_CERT_HAS_EXPIRED:
538251877Speter                    failures |= SERF_SSL_CERT_EXPIRED;
539251877Speter                    break;
540251877Speter            case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
541251877Speter            case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
542251877Speter                    failures |= SERF_SSL_CERT_SELF_SIGNED;
543251877Speter                    break;
544251877Speter            case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
545251877Speter            case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
546251877Speter            case X509_V_ERR_CERT_UNTRUSTED:
547251877Speter            case X509_V_ERR_INVALID_CA:
548262339Speter            case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
549251877Speter                    failures |= SERF_SSL_CERT_UNKNOWNCA;
550251877Speter                    break;
551251877Speter            case X509_V_ERR_CERT_REVOKED:
552251877Speter                    failures |= SERF_SSL_CERT_REVOKED;
553251877Speter                    break;
554251877Speter            default:
555251877Speter                    failures |= SERF_SSL_CERT_UNKNOWN_FAILURE;
556251877Speter                    break;
557251877Speter        }
558251877Speter    }
559251877Speter
560269847Speter    /* Validate hostname */
561269847Speter    status = validate_cert_hostname(server_cert, ctx->pool);
562269847Speter    if (status)
563269847Speter        failures |= SERF_SSL_CERT_UNKNOWN_FAILURE;
564269847Speter
565251877Speter    /* Check certificate expiry dates. */
566251877Speter    if (X509_cmp_current_time(X509_get_notBefore(server_cert)) >= 0) {
567251877Speter        failures |= SERF_SSL_CERT_NOTYETVALID;
568251877Speter    }
569251877Speter    else if (X509_cmp_current_time(X509_get_notAfter(server_cert)) <= 0) {
570251877Speter        failures |= SERF_SSL_CERT_EXPIRED;
571251877Speter    }
572251877Speter
573251877Speter    if (ctx->server_cert_callback &&
574251877Speter        (depth == 0 || failures)) {
575251877Speter        serf_ssl_certificate_t *cert;
576251877Speter        apr_pool_t *subpool;
577251877Speter
578251877Speter        apr_pool_create(&subpool, ctx->pool);
579251877Speter
580251877Speter        cert = apr_palloc(subpool, sizeof(serf_ssl_certificate_t));
581251877Speter        cert->ssl_cert = server_cert;
582251877Speter        cert->depth = depth;
583251877Speter
584251877Speter        /* Callback for further verification. */
585251877Speter        status = ctx->server_cert_callback(ctx->server_cert_userdata,
586251877Speter                                           failures, cert);
587251877Speter        if (status == APR_SUCCESS)
588251877Speter            cert_valid = 1;
589251877Speter        else {
590251877Speter            /* Even if openssl found the certificate valid, the application
591251877Speter               told us to reject it. */
592251877Speter            cert_valid = 0;
593251877Speter            /* Pass the error back to the caller through the context-run. */
594251877Speter            ctx->pending_err = status;
595251877Speter        }
596251877Speter        apr_pool_destroy(subpool);
597251877Speter    }
598251877Speter
599251877Speter    if (ctx->server_cert_chain_callback
600251877Speter        && (depth == 0 || failures)) {
601251877Speter        STACK_OF(X509) *chain;
602251877Speter        const serf_ssl_certificate_t **certs;
603251877Speter        int certs_len;
604251877Speter        apr_pool_t *subpool;
605251877Speter
606251877Speter        apr_pool_create(&subpool, ctx->pool);
607251877Speter
608251877Speter        /* Borrow the chain to pass to the callback. */
609251877Speter        chain = X509_STORE_CTX_get_chain(store_ctx);
610251877Speter
611251877Speter        /* If the chain can't be retrieved, just pass the current
612251877Speter           certificate. */
613251877Speter        /* ### can this actually happen with _get_chain() ?  */
614251877Speter        if (!chain) {
615251877Speter            serf_ssl_certificate_t *cert = apr_palloc(subpool, sizeof(*cert));
616251877Speter
617251877Speter            cert->ssl_cert = server_cert;
618251877Speter            cert->depth = depth;
619251877Speter
620251877Speter            /* Room for the server_cert and a trailing NULL.  */
621251877Speter            certs = apr_palloc(subpool, sizeof(*certs) * 2);
622251877Speter            certs[0] = cert;
623251877Speter
624251877Speter            certs_len = 1;
625251877Speter        } else {
626251877Speter            int i;
627251877Speter
628251877Speter            certs_len = sk_X509_num(chain);
629251877Speter
630251877Speter            /* Room for all the certs and a trailing NULL.  */
631251877Speter            certs = apr_palloc(subpool, sizeof(*certs) * (certs_len + 1));
632251877Speter            for (i = 0; i < certs_len; ++i) {
633251877Speter                serf_ssl_certificate_t *cert;
634251877Speter
635251877Speter                cert = apr_palloc(subpool, sizeof(*cert));
636251877Speter                cert->ssl_cert = sk_X509_value(chain, i);
637251877Speter                cert->depth = i;
638251877Speter
639251877Speter                certs[i] = cert;
640251877Speter            }
641251877Speter        }
642251877Speter        certs[certs_len] = NULL;
643251877Speter
644251877Speter        /* Callback for further verification. */
645251877Speter        status = ctx->server_cert_chain_callback(ctx->server_cert_userdata,
646251877Speter                                                 failures, depth,
647251877Speter                                                 certs, certs_len);
648251877Speter        if (status == APR_SUCCESS) {
649251877Speter            cert_valid = 1;
650251877Speter        } else {
651251877Speter            /* Even if openssl found the certificate valid, the application
652251877Speter               told us to reject it. */
653251877Speter            cert_valid = 0;
654251877Speter            /* Pass the error back to the caller through the context-run. */
655251877Speter            ctx->pending_err = status;
656251877Speter        }
657251877Speter
658251877Speter        apr_pool_destroy(subpool);
659251877Speter    }
660251877Speter
661253895Speter    /* Return a specific error if the server certificate is not accepted by
662253895Speter       OpenSSL and the application has not set callbacks to override this. */
663253895Speter    if (!cert_valid &&
664253895Speter        !ctx->server_cert_chain_callback &&
665253895Speter        !ctx->server_cert_callback)
666253895Speter    {
667253895Speter        ctx->pending_err = SERF_ERROR_SSL_CERT_FAILED;
668253895Speter    }
669253895Speter
670251877Speter    return cert_valid;
671251877Speter}
672251877Speter
673251877Speter/* This function reads an encrypted stream and returns the decrypted stream. */
674251877Speterstatic apr_status_t ssl_decrypt(void *baton, apr_size_t bufsize,
675251877Speter                                char *buf, apr_size_t *len)
676251877Speter{
677251877Speter    serf_ssl_context_t *ctx = baton;
678251877Speter    apr_size_t priv_len;
679251877Speter    apr_status_t status;
680251877Speter    const char *data;
681251877Speter    int ssl_len;
682251877Speter
683251877Speter    if (ctx->fatal_err)
684251877Speter        return ctx->fatal_err;
685251877Speter
686251877Speter    serf__log(SSL_VERBOSE, __FILE__, "ssl_decrypt: begin %d\n", bufsize);
687251877Speter
688251877Speter    /* Is there some data waiting to be read? */
689251877Speter    ssl_len = SSL_read(ctx->ssl, buf, bufsize);
690251877Speter    if (ssl_len > 0) {
691251877Speter        serf__log(SSL_VERBOSE, __FILE__,
692251877Speter                  "ssl_decrypt: %d bytes (%d); status: %d; flags: %d\n",
693251877Speter                  ssl_len, bufsize, ctx->decrypt.status,
694251877Speter                  BIO_get_retry_flags(ctx->bio));
695251877Speter        *len = ssl_len;
696251877Speter        return APR_SUCCESS;
697251877Speter    }
698251877Speter
699251877Speter    status = serf_bucket_read(ctx->decrypt.stream, bufsize, &data, &priv_len);
700251877Speter
701251877Speter    if (!SERF_BUCKET_READ_ERROR(status) && priv_len) {
702251877Speter        serf_bucket_t *tmp;
703251877Speter
704251877Speter        serf__log(SSL_VERBOSE, __FILE__,
705251877Speter                  "ssl_decrypt: read %d bytes (%d); status: %d\n",
706251877Speter                  priv_len, bufsize, status);
707251877Speter
708251877Speter        tmp = serf_bucket_simple_copy_create(data, priv_len,
709251877Speter                                             ctx->decrypt.pending->allocator);
710251877Speter
711251877Speter        serf_bucket_aggregate_append(ctx->decrypt.pending, tmp);
712251877Speter
713251877Speter        ssl_len = SSL_read(ctx->ssl, buf, bufsize);
714251877Speter        if (ssl_len < 0) {
715251877Speter            int ssl_err;
716251877Speter
717251877Speter            ssl_err = SSL_get_error(ctx->ssl, ssl_len);
718251877Speter            switch (ssl_err) {
719251877Speter            case SSL_ERROR_SYSCALL:
720251877Speter                *len = 0;
721253895Speter                /* Return the underlying network error that caused OpenSSL
722253895Speter                   to fail. ### This can be a crypt error! */
723251877Speter                status = ctx->decrypt.status;
724251877Speter                break;
725251877Speter            case SSL_ERROR_WANT_READ:
726253895Speter            case SSL_ERROR_WANT_WRITE:
727251877Speter                *len = 0;
728251877Speter                status = APR_EAGAIN;
729251877Speter                break;
730251877Speter            case SSL_ERROR_SSL:
731251877Speter                *len = 0;
732251877Speter                if (ctx->pending_err) {
733251877Speter                    status = ctx->pending_err;
734251877Speter                    ctx->pending_err = 0;
735251877Speter                } else {
736251877Speter                    ctx->fatal_err = status = SERF_ERROR_SSL_COMM_FAILED;
737251877Speter                }
738251877Speter                break;
739251877Speter            default:
740251877Speter                *len = 0;
741251877Speter                ctx->fatal_err = status = SERF_ERROR_SSL_COMM_FAILED;
742251877Speter                break;
743251877Speter            }
744251877Speter        } else if (ssl_len == 0) {
745251877Speter            /* The server shut down the connection. */
746251877Speter            int ssl_err, shutdown;
747251877Speter            *len = 0;
748251877Speter
749251877Speter            /* Check for SSL_RECEIVED_SHUTDOWN */
750251877Speter            shutdown = SSL_get_shutdown(ctx->ssl);
751251877Speter            /* Check for SSL_ERROR_ZERO_RETURN */
752251877Speter            ssl_err = SSL_get_error(ctx->ssl, ssl_len);
753251877Speter
754251877Speter            if (shutdown == SSL_RECEIVED_SHUTDOWN &&
755251877Speter                ssl_err == SSL_ERROR_ZERO_RETURN) {
756251877Speter                /* The server closed the SSL session. While this doesn't
757251877Speter                necessary mean the connection is closed, let's close
758251877Speter                it here anyway.
759251877Speter                We can optimize this later. */
760251877Speter                serf__log(SSL_VERBOSE, __FILE__,
761251877Speter                          "ssl_decrypt: SSL read error: server"
762251877Speter                          " shut down connection!\n");
763251877Speter                status = APR_EOF;
764251877Speter            } else {
765251877Speter                /* A fatal error occurred. */
766251877Speter                ctx->fatal_err = status = SERF_ERROR_SSL_COMM_FAILED;
767251877Speter            }
768251877Speter        } else {
769251877Speter            *len = ssl_len;
770251877Speter            serf__log(SSL_MSG_VERBOSE, __FILE__,
771251877Speter                      "---\n%.*s\n-(%d)-\n", *len, buf, *len);
772251877Speter        }
773251877Speter    }
774251877Speter    else {
775251877Speter        *len = 0;
776251877Speter    }
777251877Speter    serf__log(SSL_VERBOSE, __FILE__,
778251877Speter              "ssl_decrypt: %d %d %d\n", status, *len,
779251877Speter              BIO_get_retry_flags(ctx->bio));
780251877Speter
781251877Speter    return status;
782251877Speter}
783251877Speter
784251877Speter/* This function reads a decrypted stream and returns an encrypted stream. */
785251877Speterstatic apr_status_t ssl_encrypt(void *baton, apr_size_t bufsize,
786251877Speter                                char *buf, apr_size_t *len)
787251877Speter{
788251877Speter    const char *data;
789251877Speter    apr_size_t interim_bufsize;
790251877Speter    serf_ssl_context_t *ctx = baton;
791251877Speter    apr_status_t status;
792251877Speter
793251877Speter    if (ctx->fatal_err)
794251877Speter        return ctx->fatal_err;
795251877Speter
796251877Speter    serf__log(SSL_VERBOSE, __FILE__, "ssl_encrypt: begin %d\n", bufsize);
797251877Speter
798251877Speter    /* Try to read already encrypted but unread data first. */
799251877Speter    status = serf_bucket_read(ctx->encrypt.pending, bufsize, &data, len);
800251877Speter    if (SERF_BUCKET_READ_ERROR(status)) {
801251877Speter        return status;
802251877Speter    }
803251877Speter
804251877Speter    /* Aha, we read something.  Return that now. */
805251877Speter    if (*len) {
806251877Speter        memcpy(buf, data, *len);
807251877Speter        if (APR_STATUS_IS_EOF(status)) {
808251877Speter            status = APR_SUCCESS;
809251877Speter        }
810251877Speter
811251877Speter        serf__log(SSL_VERBOSE, __FILE__, "ssl_encrypt: %d %d %d (quick read)\n",
812251877Speter                  status, *len, BIO_get_retry_flags(ctx->bio));
813251877Speter
814251877Speter        return status;
815251877Speter    }
816251877Speter
817251877Speter    if (BIO_should_retry(ctx->bio) && BIO_should_write(ctx->bio)) {
818251877Speter        serf__log(SSL_VERBOSE, __FILE__,
819251877Speter                  "ssl_encrypt: %d %d %d (should write exit)\n",
820251877Speter                  status, *len, BIO_get_retry_flags(ctx->bio));
821251877Speter
822251877Speter        return APR_EAGAIN;
823251877Speter    }
824251877Speter
825251877Speter    /* If we were previously blocked, unblock ourselves now. */
826251877Speter    if (BIO_should_read(ctx->bio)) {
827251877Speter        serf__log(SSL_VERBOSE, __FILE__, "ssl_encrypt: reset %d %d (%d %d %d)\n",
828251877Speter                  status, ctx->encrypt.status,
829251877Speter                  BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
830251877Speter                  BIO_get_retry_flags(ctx->bio));
831251877Speter
832251877Speter        ctx->encrypt.status = APR_SUCCESS;
833251877Speter        ctx->encrypt.exhausted_reset = 0;
834251877Speter    }
835251877Speter
836251877Speter    /* Oh well, read from our stream now. */
837251877Speter    interim_bufsize = bufsize;
838251877Speter    do {
839251877Speter        apr_size_t interim_len;
840251877Speter
841251877Speter        if (!ctx->encrypt.status) {
842251877Speter            struct iovec vecs[64];
843251877Speter            int vecs_read;
844251877Speter
845251877Speter            status = serf_bucket_read_iovec(ctx->encrypt.stream,
846251877Speter                                            interim_bufsize, 64, vecs,
847251877Speter                                            &vecs_read);
848251877Speter
849251877Speter            if (!SERF_BUCKET_READ_ERROR(status) && vecs_read) {
850251877Speter                char *vecs_data;
851251877Speter                int i, cur, vecs_data_len;
852251877Speter                int ssl_len;
853251877Speter
854251877Speter                /* Combine the buffers of the iovec into one buffer, as
855251877Speter                   that is with SSL_write requires. */
856251877Speter                vecs_data_len = 0;
857251877Speter                for (i = 0; i < vecs_read; i++) {
858251877Speter                    vecs_data_len += vecs[i].iov_len;
859251877Speter                }
860251877Speter
861251877Speter                vecs_data = serf_bucket_mem_alloc(ctx->allocator,
862251877Speter                                                  vecs_data_len);
863251877Speter
864251877Speter                cur = 0;
865251877Speter                for (i = 0; i < vecs_read; i++) {
866251877Speter                    memcpy(vecs_data + cur, vecs[i].iov_base, vecs[i].iov_len);
867251877Speter                    cur += vecs[i].iov_len;
868251877Speter                }
869251877Speter
870251877Speter                interim_bufsize -= vecs_data_len;
871251877Speter                interim_len = vecs_data_len;
872251877Speter
873251877Speter                serf__log(SSL_VERBOSE, __FILE__,
874251877Speter                          "ssl_encrypt: bucket read %d bytes; "\
875251877Speter                          "status %d\n", interim_len, status);
876251877Speter                serf__log(SSL_MSG_VERBOSE, __FILE__, "---\n%.*s\n-(%d)-\n",
877251877Speter                          interim_len, vecs_data, interim_len);
878251877Speter
879251877Speter                /* Stash our status away. */
880251877Speter                ctx->encrypt.status = status;
881251877Speter
882251877Speter                ssl_len = SSL_write(ctx->ssl, vecs_data, interim_len);
883251877Speter
884251877Speter                serf__log(SSL_VERBOSE, __FILE__,
885251877Speter                          "ssl_encrypt: SSL write: %d\n", ssl_len);
886251877Speter
887251877Speter                /* If we failed to write... */
888251877Speter                if (ssl_len < 0) {
889251877Speter                    int ssl_err;
890251877Speter
891253895Speter                    /* Ah, bugger. We need to put that data back.
892253895Speter                       Note: use the copy here, we do not own the original iovec
893253895Speter                       data buffer so it will be freed on next read. */
894253895Speter                    serf_bucket_t *vecs_copy =
895253895Speter                        serf_bucket_simple_own_create(vecs_data,
896253895Speter                                                      vecs_data_len,
897253895Speter                                                      ctx->allocator);
898253895Speter                    serf_bucket_aggregate_prepend(ctx->encrypt.stream,
899253895Speter                                                  vecs_copy);
900251877Speter
901251877Speter                    ssl_err = SSL_get_error(ctx->ssl, ssl_len);
902251877Speter
903251877Speter                    serf__log(SSL_VERBOSE, __FILE__,
904251877Speter                              "ssl_encrypt: SSL write error: %d\n", ssl_err);
905251877Speter
906251877Speter                    if (ssl_err == SSL_ERROR_SYSCALL) {
907253895Speter                        /* Return the underlying network error that caused OpenSSL
908253895Speter                           to fail. ### This can be a decrypt error! */
909251877Speter                        status = ctx->encrypt.status;
910251877Speter                        if (SERF_BUCKET_READ_ERROR(status)) {
911251877Speter                            return status;
912251877Speter                        }
913251877Speter                    }
914251877Speter                    else {
915251877Speter                        /* Oh, no. */
916251877Speter                        if (ssl_err == SSL_ERROR_WANT_READ) {
917251877Speter                            status = SERF_ERROR_WAIT_CONN;
918251877Speter                        }
919251877Speter                        else {
920253895Speter                            ctx->fatal_err = status =
921253895Speter                                SERF_ERROR_SSL_COMM_FAILED;
922251877Speter                        }
923251877Speter                    }
924251877Speter
925251877Speter                    serf__log(SSL_VERBOSE, __FILE__,
926251877Speter                              "ssl_encrypt: SSL write error: %d %d\n",
927251877Speter                              status, *len);
928253895Speter                } else {
929253895Speter                    /* We're done with this data. */
930253895Speter                    serf_bucket_mem_free(ctx->allocator, vecs_data);
931251877Speter                }
932251877Speter            }
933251877Speter        }
934251877Speter        else {
935251877Speter            interim_len = 0;
936251877Speter            *len = 0;
937251877Speter            status = ctx->encrypt.status;
938251877Speter        }
939251877Speter
940251877Speter    } while (!status && interim_bufsize);
941251877Speter
942251877Speter    /* Okay, we exhausted our underlying stream. */
943251877Speter    if (!SERF_BUCKET_READ_ERROR(status)) {
944251877Speter        apr_status_t agg_status;
945251877Speter        struct iovec vecs[64];
946251877Speter        int vecs_read, i;
947251877Speter
948251877Speter        /* We read something! */
949251877Speter        agg_status = serf_bucket_read_iovec(ctx->encrypt.pending, bufsize,
950251877Speter                                            64, vecs, &vecs_read);
951251877Speter        *len = 0;
952251877Speter        for (i = 0; i < vecs_read; i++) {
953251877Speter            memcpy(buf + *len, vecs[i].iov_base, vecs[i].iov_len);
954251877Speter            *len += vecs[i].iov_len;
955251877Speter        }
956251877Speter
957251877Speter        serf__log(SSL_VERBOSE, __FILE__,
958251877Speter                  "ssl_encrypt read agg: %d %d %d %d\n", status, agg_status,
959251877Speter            ctx->encrypt.status, *len);
960251877Speter
961251877Speter        if (!agg_status) {
962251877Speter            status = agg_status;
963251877Speter        }
964251877Speter    }
965251877Speter
966251877Speter    if (status == SERF_ERROR_WAIT_CONN
967251877Speter        && BIO_should_retry(ctx->bio) && BIO_should_read(ctx->bio)) {
968251877Speter        ctx->encrypt.exhausted = ctx->encrypt.status;
969251877Speter        ctx->encrypt.status = SERF_ERROR_WAIT_CONN;
970251877Speter    }
971251877Speter
972251877Speter    serf__log(SSL_VERBOSE, __FILE__,
973251877Speter              "ssl_encrypt finished: %d %d (%d %d %d)\n", status, *len,
974251877Speter              BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
975251877Speter              BIO_get_retry_flags(ctx->bio));
976251877Speter
977251877Speter    return status;
978251877Speter}
979251877Speter
980251877Speter#if APR_HAS_THREADS
981251877Speterstatic apr_pool_t *ssl_pool;
982251877Speterstatic apr_thread_mutex_t **ssl_locks;
983251877Speter
984251877Spetertypedef struct CRYPTO_dynlock_value {
985251877Speter    apr_thread_mutex_t *lock;
986251877Speter} CRYPTO_dynlock_value;
987251877Speter
988251877Speterstatic CRYPTO_dynlock_value *ssl_dyn_create(const char* file, int line)
989251877Speter{
990251877Speter    CRYPTO_dynlock_value *l;
991251877Speter    apr_status_t rv;
992251877Speter
993251877Speter    l = apr_palloc(ssl_pool, sizeof(CRYPTO_dynlock_value));
994251877Speter    rv = apr_thread_mutex_create(&l->lock, APR_THREAD_MUTEX_DEFAULT, ssl_pool);
995251877Speter    if (rv != APR_SUCCESS) {
996251877Speter        /* FIXME: return error here */
997251877Speter    }
998251877Speter    return l;
999251877Speter}
1000251877Speter
1001251877Speterstatic void ssl_dyn_lock(int mode, CRYPTO_dynlock_value *l, const char *file,
1002251877Speter                         int line)
1003251877Speter{
1004251877Speter    if (mode & CRYPTO_LOCK) {
1005251877Speter        apr_thread_mutex_lock(l->lock);
1006251877Speter    }
1007251877Speter    else if (mode & CRYPTO_UNLOCK) {
1008251877Speter        apr_thread_mutex_unlock(l->lock);
1009251877Speter    }
1010251877Speter}
1011251877Speter
1012251877Speterstatic void ssl_dyn_destroy(CRYPTO_dynlock_value *l, const char *file,
1013251877Speter                            int line)
1014251877Speter{
1015251877Speter    apr_thread_mutex_destroy(l->lock);
1016251877Speter}
1017251877Speter
1018251877Speterstatic void ssl_lock(int mode, int n, const char *file, int line)
1019251877Speter{
1020251877Speter    if (mode & CRYPTO_LOCK) {
1021251877Speter        apr_thread_mutex_lock(ssl_locks[n]);
1022251877Speter    }
1023251877Speter    else if (mode & CRYPTO_UNLOCK) {
1024251877Speter        apr_thread_mutex_unlock(ssl_locks[n]);
1025251877Speter    }
1026251877Speter}
1027251877Speter
1028251877Speterstatic unsigned long ssl_id(void)
1029251877Speter{
1030251877Speter    /* FIXME: This is lame and not portable. -aaron */
1031251877Speter    return (unsigned long) apr_os_thread_current();
1032251877Speter}
1033251877Speter
1034251877Speterstatic apr_status_t cleanup_ssl(void *data)
1035251877Speter{
1036251877Speter    CRYPTO_set_locking_callback(NULL);
1037251877Speter    CRYPTO_set_id_callback(NULL);
1038251877Speter    CRYPTO_set_dynlock_create_callback(NULL);
1039251877Speter    CRYPTO_set_dynlock_lock_callback(NULL);
1040251877Speter    CRYPTO_set_dynlock_destroy_callback(NULL);
1041251877Speter
1042251877Speter    return APR_SUCCESS;
1043251877Speter}
1044251877Speter
1045251877Speter#endif
1046251877Speter
1047262339Speter#if !APR_VERSION_AT_LEAST(1,0,0)
1048262339Speter#define apr_atomic_cas32(mem, with, cmp) apr_atomic_cas(mem, with, cmp)
1049262339Speter#endif
1050251877Speter
1051262339Speterenum ssl_init_e
1052262339Speter{
1053262339Speter   INIT_UNINITIALIZED = 0,
1054262339Speter   INIT_BUSY = 1,
1055262339Speter   INIT_DONE = 2
1056262339Speter};
1057262339Speter
1058262339Speterstatic volatile apr_uint32_t have_init_ssl = INIT_UNINITIALIZED;
1059262339Speter
1060251877Speterstatic void init_ssl_libraries(void)
1061251877Speter{
1062251877Speter    apr_uint32_t val;
1063251877Speter
1064262339Speter    val = apr_atomic_cas32(&have_init_ssl, INIT_BUSY, INIT_UNINITIALIZED);
1065262339Speter
1066251877Speter    if (!val) {
1067251877Speter#if APR_HAS_THREADS
1068251877Speter        int i, numlocks;
1069251877Speter#endif
1070251877Speter
1071251877Speter#ifdef SSL_VERBOSE
1072251877Speter        /* Warn when compile-time and run-time version of OpenSSL differ in
1073251877Speter           major/minor version number. */
1074251877Speter        long libver = SSLeay();
1075251877Speter
1076251877Speter        if ((libver ^ OPENSSL_VERSION_NUMBER) & 0xFFF00000) {
1077251877Speter            serf__log(SSL_VERBOSE, __FILE__,
1078251877Speter                      "Warning: OpenSSL library version mismatch, compile-time "
1079251877Speter                      "was %lx, runtime is %lx.\n",
1080251877Speter                      OPENSSL_VERSION_NUMBER, libver);
1081251877Speter        }
1082251877Speter#endif
1083251877Speter
1084251877Speter        CRYPTO_malloc_init();
1085251877Speter        ERR_load_crypto_strings();
1086251877Speter        SSL_load_error_strings();
1087251877Speter        SSL_library_init();
1088251877Speter        OpenSSL_add_all_algorithms();
1089251877Speter
1090251877Speter#if APR_HAS_THREADS
1091251877Speter        numlocks = CRYPTO_num_locks();
1092251877Speter        apr_pool_create(&ssl_pool, NULL);
1093251877Speter        ssl_locks = apr_palloc(ssl_pool, sizeof(apr_thread_mutex_t*)*numlocks);
1094251877Speter        for (i = 0; i < numlocks; i++) {
1095251877Speter            apr_status_t rv;
1096251877Speter
1097251877Speter            /* Intraprocess locks don't /need/ a filename... */
1098251877Speter            rv = apr_thread_mutex_create(&ssl_locks[i],
1099251877Speter                                         APR_THREAD_MUTEX_DEFAULT, ssl_pool);
1100251877Speter            if (rv != APR_SUCCESS) {
1101251877Speter                /* FIXME: error out here */
1102251877Speter            }
1103251877Speter        }
1104251877Speter        CRYPTO_set_locking_callback(ssl_lock);
1105251877Speter        CRYPTO_set_id_callback(ssl_id);
1106251877Speter        CRYPTO_set_dynlock_create_callback(ssl_dyn_create);
1107251877Speter        CRYPTO_set_dynlock_lock_callback(ssl_dyn_lock);
1108251877Speter        CRYPTO_set_dynlock_destroy_callback(ssl_dyn_destroy);
1109251877Speter
1110251877Speter        apr_pool_cleanup_register(ssl_pool, NULL, cleanup_ssl, cleanup_ssl);
1111251877Speter#endif
1112262339Speter        apr_atomic_cas32(&have_init_ssl, INIT_DONE, INIT_BUSY);
1113251877Speter    }
1114262339Speter  else
1115262339Speter    {
1116262339Speter        /* Make sure we don't continue before the initialization in another
1117262339Speter           thread has completed */
1118262339Speter        while (val != INIT_DONE) {
1119262339Speter            apr_sleep(APR_USEC_PER_SEC / 1000);
1120262339Speter
1121262339Speter            val = apr_atomic_cas32(&have_init_ssl,
1122262339Speter                                   INIT_UNINITIALIZED,
1123262339Speter                                   INIT_UNINITIALIZED);
1124262339Speter        }
1125262339Speter    }
1126251877Speter}
1127251877Speter
1128251877Speterstatic int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey)
1129251877Speter{
1130251877Speter    serf_ssl_context_t *ctx = SSL_get_app_data(ssl);
1131251877Speter    apr_status_t status;
1132251877Speter
1133251877Speter    if (ctx->cached_cert) {
1134251877Speter        *cert = ctx->cached_cert;
1135251877Speter        *pkey = ctx->cached_cert_pw;
1136251877Speter        return 1;
1137251877Speter    }
1138251877Speter
1139251877Speter    while (ctx->cert_callback) {
1140251877Speter        const char *cert_path;
1141251877Speter        apr_file_t *cert_file;
1142251877Speter        BIO *bio;
1143251877Speter        PKCS12 *p12;
1144251877Speter        int i;
1145251877Speter        int retrying_success = 0;
1146251877Speter
1147251877Speter        if (ctx->cert_file_success) {
1148251877Speter            status = APR_SUCCESS;
1149251877Speter            cert_path = ctx->cert_file_success;
1150251877Speter            ctx->cert_file_success = NULL;
1151251877Speter            retrying_success = 1;
1152251877Speter        } else {
1153251877Speter            status = ctx->cert_callback(ctx->cert_userdata, &cert_path);
1154251877Speter        }
1155251877Speter
1156251877Speter        if (status || !cert_path) {
1157253895Speter            break;
1158251877Speter        }
1159251877Speter
1160251877Speter        /* Load the x.509 cert file stored in PKCS12 */
1161251877Speter        status = apr_file_open(&cert_file, cert_path, APR_READ, APR_OS_DEFAULT,
1162251877Speter                               ctx->pool);
1163251877Speter
1164251877Speter        if (status) {
1165251877Speter            continue;
1166251877Speter        }
1167251877Speter
1168251877Speter        bio = BIO_new(&bio_file_method);
1169251877Speter        bio->ptr = cert_file;
1170251877Speter
1171251877Speter        ctx->cert_path = cert_path;
1172251877Speter        p12 = d2i_PKCS12_bio(bio, NULL);
1173251877Speter        apr_file_close(cert_file);
1174251877Speter
1175251877Speter        i = PKCS12_parse(p12, NULL, pkey, cert, NULL);
1176251877Speter
1177251877Speter        if (i == 1) {
1178251877Speter            PKCS12_free(p12);
1179251877Speter            ctx->cached_cert = *cert;
1180251877Speter            ctx->cached_cert_pw = *pkey;
1181251877Speter            if (!retrying_success && ctx->cert_cache_pool) {
1182251877Speter                const char *c;
1183251877Speter
1184251877Speter                c = apr_pstrdup(ctx->cert_cache_pool, ctx->cert_path);
1185251877Speter
1186251877Speter                apr_pool_userdata_setn(c, "serf:ssl:cert",
1187251877Speter                                       apr_pool_cleanup_null,
1188251877Speter                                       ctx->cert_cache_pool);
1189251877Speter            }
1190251877Speter            return 1;
1191251877Speter        }
1192251877Speter        else {
1193251877Speter            int err = ERR_get_error();
1194251877Speter            ERR_clear_error();
1195251877Speter            if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
1196251877Speter                ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
1197251877Speter                if (ctx->cert_pw_callback) {
1198251877Speter                    const char *password;
1199251877Speter
1200251877Speter                    if (ctx->cert_pw_success) {
1201251877Speter                        status = APR_SUCCESS;
1202251877Speter                        password = ctx->cert_pw_success;
1203251877Speter                        ctx->cert_pw_success = NULL;
1204251877Speter                    } else {
1205251877Speter                        status = ctx->cert_pw_callback(ctx->cert_pw_userdata,
1206251877Speter                                                       ctx->cert_path,
1207251877Speter                                                       &password);
1208251877Speter                    }
1209251877Speter
1210251877Speter                    if (!status && password) {
1211251877Speter                        i = PKCS12_parse(p12, password, pkey, cert, NULL);
1212251877Speter                        if (i == 1) {
1213251877Speter                            PKCS12_free(p12);
1214251877Speter                            ctx->cached_cert = *cert;
1215251877Speter                            ctx->cached_cert_pw = *pkey;
1216251877Speter                            if (!retrying_success && ctx->cert_cache_pool) {
1217251877Speter                                const char *c;
1218251877Speter
1219251877Speter                                c = apr_pstrdup(ctx->cert_cache_pool,
1220251877Speter                                                ctx->cert_path);
1221251877Speter
1222251877Speter                                apr_pool_userdata_setn(c, "serf:ssl:cert",
1223251877Speter                                                       apr_pool_cleanup_null,
1224251877Speter                                                       ctx->cert_cache_pool);
1225251877Speter                            }
1226251877Speter                            if (!retrying_success && ctx->cert_pw_cache_pool) {
1227251877Speter                                const char *c;
1228251877Speter
1229251877Speter                                c = apr_pstrdup(ctx->cert_pw_cache_pool,
1230251877Speter                                                password);
1231251877Speter
1232251877Speter                                apr_pool_userdata_setn(c, "serf:ssl:certpw",
1233251877Speter                                                       apr_pool_cleanup_null,
1234251877Speter                                                       ctx->cert_pw_cache_pool);
1235251877Speter                            }
1236251877Speter                            return 1;
1237251877Speter                        }
1238251877Speter                    }
1239251877Speter                }
1240251877Speter                PKCS12_free(p12);
1241251877Speter                return 0;
1242251877Speter            }
1243251877Speter            else {
1244251877Speter                printf("OpenSSL cert error: %d %d %d\n", ERR_GET_LIB(err),
1245251877Speter                       ERR_GET_FUNC(err),
1246251877Speter                       ERR_GET_REASON(err));
1247251877Speter                PKCS12_free(p12);
1248251877Speter            }
1249251877Speter        }
1250251877Speter    }
1251251877Speter
1252251877Speter    return 0;
1253251877Speter}
1254251877Speter
1255251877Speter
1256251877Spetervoid serf_ssl_client_cert_provider_set(
1257251877Speter    serf_ssl_context_t *context,
1258251877Speter    serf_ssl_need_client_cert_t callback,
1259251877Speter    void *data,
1260251877Speter    void *cache_pool)
1261251877Speter{
1262251877Speter    context->cert_callback = callback;
1263251877Speter    context->cert_userdata = data;
1264251877Speter    context->cert_cache_pool = cache_pool;
1265251877Speter    if (context->cert_cache_pool) {
1266251877Speter        apr_pool_userdata_get((void**)&context->cert_file_success,
1267251877Speter                              "serf:ssl:cert", cache_pool);
1268251877Speter    }
1269251877Speter}
1270251877Speter
1271251877Speter
1272251877Spetervoid serf_ssl_client_cert_password_set(
1273251877Speter    serf_ssl_context_t *context,
1274251877Speter    serf_ssl_need_cert_password_t callback,
1275251877Speter    void *data,
1276251877Speter    void *cache_pool)
1277251877Speter{
1278251877Speter    context->cert_pw_callback = callback;
1279251877Speter    context->cert_pw_userdata = data;
1280251877Speter    context->cert_pw_cache_pool = cache_pool;
1281251877Speter    if (context->cert_pw_cache_pool) {
1282251877Speter        apr_pool_userdata_get((void**)&context->cert_pw_success,
1283251877Speter                              "serf:ssl:certpw", cache_pool);
1284251877Speter    }
1285251877Speter}
1286251877Speter
1287251877Speter
1288251877Spetervoid serf_ssl_server_cert_callback_set(
1289251877Speter    serf_ssl_context_t *context,
1290251877Speter    serf_ssl_need_server_cert_t callback,
1291251877Speter    void *data)
1292251877Speter{
1293251877Speter    context->server_cert_callback = callback;
1294251877Speter    context->server_cert_userdata = data;
1295251877Speter}
1296251877Speter
1297251877Spetervoid serf_ssl_server_cert_chain_callback_set(
1298251877Speter    serf_ssl_context_t *context,
1299251877Speter    serf_ssl_need_server_cert_t cert_callback,
1300251877Speter    serf_ssl_server_cert_chain_cb_t cert_chain_callback,
1301251877Speter    void *data)
1302251877Speter{
1303251877Speter    context->server_cert_callback = cert_callback;
1304251877Speter    context->server_cert_chain_callback = cert_chain_callback;
1305251877Speter    context->server_cert_userdata = data;
1306251877Speter}
1307251877Speter
1308262339Speterstatic serf_ssl_context_t *ssl_init_context(serf_bucket_alloc_t *allocator)
1309251877Speter{
1310251877Speter    serf_ssl_context_t *ssl_ctx;
1311251877Speter
1312251877Speter    init_ssl_libraries();
1313251877Speter
1314251877Speter    ssl_ctx = serf_bucket_mem_alloc(allocator, sizeof(*ssl_ctx));
1315251877Speter
1316251877Speter    ssl_ctx->refcount = 0;
1317262339Speter    ssl_ctx->pool = serf_bucket_allocator_get_pool(allocator);
1318251877Speter    ssl_ctx->allocator = allocator;
1319251877Speter
1320251877Speter    ssl_ctx->ctx = SSL_CTX_new(SSLv23_client_method());
1321251877Speter
1322251877Speter    SSL_CTX_set_client_cert_cb(ssl_ctx->ctx, ssl_need_client_cert);
1323251877Speter    ssl_ctx->cached_cert = 0;
1324251877Speter    ssl_ctx->cached_cert_pw = 0;
1325251877Speter    ssl_ctx->pending_err = APR_SUCCESS;
1326251877Speter    ssl_ctx->fatal_err = APR_SUCCESS;
1327251877Speter
1328251877Speter    ssl_ctx->cert_callback = NULL;
1329251877Speter    ssl_ctx->cert_pw_callback = NULL;
1330251877Speter    ssl_ctx->server_cert_callback = NULL;
1331251877Speter    ssl_ctx->server_cert_chain_callback = NULL;
1332251877Speter
1333251877Speter    SSL_CTX_set_verify(ssl_ctx->ctx, SSL_VERIFY_PEER,
1334251877Speter                       validate_server_certificate);
1335251877Speter    SSL_CTX_set_options(ssl_ctx->ctx, SSL_OP_ALL);
1336251877Speter    /* Disable SSL compression by default. */
1337251877Speter    disable_compression(ssl_ctx);
1338251877Speter
1339251877Speter    ssl_ctx->ssl = SSL_new(ssl_ctx->ctx);
1340251877Speter    ssl_ctx->bio = BIO_new(&bio_bucket_method);
1341251877Speter    ssl_ctx->bio->ptr = ssl_ctx;
1342251877Speter
1343251877Speter    SSL_set_bio(ssl_ctx->ssl, ssl_ctx->bio, ssl_ctx->bio);
1344251877Speter
1345251877Speter    SSL_set_connect_state(ssl_ctx->ssl);
1346251877Speter
1347251877Speter    SSL_set_app_data(ssl_ctx->ssl, ssl_ctx);
1348251877Speter
1349251877Speter#if SSL_VERBOSE
1350251877Speter    SSL_CTX_set_info_callback(ssl_ctx->ctx, apps_ssl_info_callback);
1351251877Speter#endif
1352251877Speter
1353251877Speter    ssl_ctx->encrypt.stream = NULL;
1354251877Speter    ssl_ctx->encrypt.stream_next = NULL;
1355251877Speter    ssl_ctx->encrypt.pending = serf_bucket_aggregate_create(allocator);
1356251877Speter    ssl_ctx->encrypt.status = APR_SUCCESS;
1357251877Speter    serf_databuf_init(&ssl_ctx->encrypt.databuf);
1358251877Speter    ssl_ctx->encrypt.databuf.read = ssl_encrypt;
1359251877Speter    ssl_ctx->encrypt.databuf.read_baton = ssl_ctx;
1360251877Speter
1361251877Speter    ssl_ctx->decrypt.stream = NULL;
1362251877Speter    ssl_ctx->decrypt.pending = serf_bucket_aggregate_create(allocator);
1363251877Speter    ssl_ctx->decrypt.status = APR_SUCCESS;
1364251877Speter    serf_databuf_init(&ssl_ctx->decrypt.databuf);
1365251877Speter    ssl_ctx->decrypt.databuf.read = ssl_decrypt;
1366251877Speter    ssl_ctx->decrypt.databuf.read_baton = ssl_ctx;
1367251877Speter
1368251877Speter    return ssl_ctx;
1369251877Speter}
1370251877Speter
1371251877Speterstatic apr_status_t ssl_free_context(
1372251877Speter    serf_ssl_context_t *ssl_ctx)
1373251877Speter{
1374251877Speter    /* If never had the pending buckets, don't try to free them. */
1375251877Speter    if (ssl_ctx->decrypt.pending != NULL) {
1376251877Speter        serf_bucket_destroy(ssl_ctx->decrypt.pending);
1377251877Speter    }
1378251877Speter    if (ssl_ctx->encrypt.pending != NULL) {
1379251877Speter        serf_bucket_destroy(ssl_ctx->encrypt.pending);
1380251877Speter    }
1381251877Speter
1382251877Speter    /* SSL_free implicitly frees the underlying BIO. */
1383251877Speter    SSL_free(ssl_ctx->ssl);
1384251877Speter    SSL_CTX_free(ssl_ctx->ctx);
1385251877Speter
1386251877Speter    serf_bucket_mem_free(ssl_ctx->allocator, ssl_ctx);
1387251877Speter
1388251877Speter    return APR_SUCCESS;
1389251877Speter}
1390251877Speter
1391251877Speterstatic serf_bucket_t * serf_bucket_ssl_create(
1392251877Speter    serf_ssl_context_t *ssl_ctx,
1393251877Speter    serf_bucket_alloc_t *allocator,
1394251877Speter    const serf_bucket_type_t *type)
1395251877Speter{
1396251877Speter    ssl_context_t *ctx;
1397251877Speter
1398251877Speter    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
1399251877Speter    if (!ssl_ctx) {
1400262339Speter        ctx->ssl_ctx = ssl_init_context(allocator);
1401251877Speter    }
1402251877Speter    else {
1403251877Speter        ctx->ssl_ctx = ssl_ctx;
1404251877Speter    }
1405251877Speter    ctx->ssl_ctx->refcount++;
1406251877Speter
1407251877Speter    return serf_bucket_create(type, allocator, ctx);
1408251877Speter}
1409251877Speter
1410251877Speterapr_status_t serf_ssl_set_hostname(serf_ssl_context_t *context,
1411251877Speter                                   const char * hostname)
1412251877Speter{
1413251877Speter#ifdef SSL_set_tlsext_host_name
1414251877Speter    if (SSL_set_tlsext_host_name(context->ssl, hostname) != 1) {
1415251877Speter        ERR_clear_error();
1416251877Speter    }
1417251877Speter#endif
1418251877Speter    return APR_SUCCESS;
1419251877Speter}
1420251877Speter
1421251877Speterapr_status_t serf_ssl_use_default_certificates(serf_ssl_context_t *ssl_ctx)
1422251877Speter{
1423251877Speter    X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx->ctx);
1424251877Speter
1425251877Speter    int result = X509_STORE_set_default_paths(store);
1426251877Speter
1427251877Speter    return result ? APR_SUCCESS : SERF_ERROR_SSL_CERT_FAILED;
1428251877Speter}
1429251877Speter
1430251877Speterapr_status_t serf_ssl_load_cert_file(
1431251877Speter    serf_ssl_certificate_t **cert,
1432251877Speter    const char *file_path,
1433251877Speter    apr_pool_t *pool)
1434251877Speter{
1435251877Speter    FILE *fp = fopen(file_path, "r");
1436253895Speter
1437251877Speter    if (fp) {
1438251877Speter        X509 *ssl_cert = PEM_read_X509(fp, NULL, NULL, NULL);
1439251877Speter        fclose(fp);
1440251877Speter
1441251877Speter        if (ssl_cert) {
1442251877Speter            *cert = apr_palloc(pool, sizeof(serf_ssl_certificate_t));
1443251877Speter            (*cert)->ssl_cert = ssl_cert;
1444251877Speter
1445251877Speter            return APR_SUCCESS;
1446251877Speter        }
1447251877Speter    }
1448251877Speter
1449251877Speter    return SERF_ERROR_SSL_CERT_FAILED;
1450251877Speter}
1451251877Speter
1452251877Speter
1453251877Speterapr_status_t serf_ssl_trust_cert(
1454251877Speter    serf_ssl_context_t *ssl_ctx,
1455251877Speter    serf_ssl_certificate_t *cert)
1456251877Speter{
1457251877Speter    X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx->ctx);
1458251877Speter
1459251877Speter    int result = X509_STORE_add_cert(store, cert->ssl_cert);
1460251877Speter
1461251877Speter    return result ? APR_SUCCESS : SERF_ERROR_SSL_CERT_FAILED;
1462251877Speter}
1463251877Speter
1464251877Speter
1465251877Speterserf_bucket_t *serf_bucket_ssl_decrypt_create(
1466251877Speter    serf_bucket_t *stream,
1467251877Speter    serf_ssl_context_t *ssl_ctx,
1468251877Speter    serf_bucket_alloc_t *allocator)
1469251877Speter{
1470251877Speter    serf_bucket_t *bkt;
1471251877Speter    ssl_context_t *ctx;
1472251877Speter
1473251877Speter    bkt = serf_bucket_ssl_create(ssl_ctx, allocator,
1474251877Speter                                 &serf_bucket_type_ssl_decrypt);
1475251877Speter
1476251877Speter    ctx = bkt->data;
1477251877Speter
1478251877Speter    ctx->databuf = &ctx->ssl_ctx->decrypt.databuf;
1479251877Speter    if (ctx->ssl_ctx->decrypt.stream != NULL) {
1480251877Speter        return NULL;
1481251877Speter    }
1482251877Speter    ctx->ssl_ctx->decrypt.stream = stream;
1483251877Speter    ctx->our_stream = &ctx->ssl_ctx->decrypt.stream;
1484251877Speter
1485251877Speter    return bkt;
1486251877Speter}
1487251877Speter
1488251877Speter
1489251877Speterserf_ssl_context_t *serf_bucket_ssl_decrypt_context_get(
1490251877Speter     serf_bucket_t *bucket)
1491251877Speter{
1492251877Speter    ssl_context_t *ctx = bucket->data;
1493251877Speter    return ctx->ssl_ctx;
1494251877Speter}
1495251877Speter
1496251877Speter
1497251877Speterserf_bucket_t *serf_bucket_ssl_encrypt_create(
1498251877Speter    serf_bucket_t *stream,
1499251877Speter    serf_ssl_context_t *ssl_ctx,
1500251877Speter    serf_bucket_alloc_t *allocator)
1501251877Speter{
1502251877Speter    serf_bucket_t *bkt;
1503251877Speter    ssl_context_t *ctx;
1504251877Speter
1505251877Speter    bkt = serf_bucket_ssl_create(ssl_ctx, allocator,
1506251877Speter                                 &serf_bucket_type_ssl_encrypt);
1507251877Speter
1508251877Speter    ctx = bkt->data;
1509251877Speter
1510251877Speter    ctx->databuf = &ctx->ssl_ctx->encrypt.databuf;
1511251877Speter    ctx->our_stream = &ctx->ssl_ctx->encrypt.stream;
1512251877Speter    if (ctx->ssl_ctx->encrypt.stream == NULL) {
1513251877Speter        serf_bucket_t *tmp = serf_bucket_aggregate_create(stream->allocator);
1514251877Speter        serf_bucket_aggregate_append(tmp, stream);
1515251877Speter        ctx->ssl_ctx->encrypt.stream = tmp;
1516251877Speter    }
1517251877Speter    else {
1518251877Speter        bucket_list_t *new_list;
1519251877Speter
1520251877Speter        new_list = serf_bucket_mem_alloc(ctx->ssl_ctx->allocator,
1521251877Speter                                         sizeof(*new_list));
1522251877Speter        new_list->bucket = stream;
1523251877Speter        new_list->next = NULL;
1524251877Speter        if (ctx->ssl_ctx->encrypt.stream_next == NULL) {
1525251877Speter            ctx->ssl_ctx->encrypt.stream_next = new_list;
1526251877Speter        }
1527251877Speter        else {
1528251877Speter            bucket_list_t *scan = ctx->ssl_ctx->encrypt.stream_next;
1529251877Speter
1530251877Speter            while (scan->next != NULL)
1531251877Speter                scan = scan->next;
1532251877Speter            scan->next = new_list;
1533251877Speter        }
1534251877Speter    }
1535251877Speter
1536251877Speter    return bkt;
1537251877Speter}
1538251877Speter
1539251877Speter
1540251877Speterserf_ssl_context_t *serf_bucket_ssl_encrypt_context_get(
1541251877Speter     serf_bucket_t *bucket)
1542251877Speter{
1543251877Speter    ssl_context_t *ctx = bucket->data;
1544251877Speter    return ctx->ssl_ctx;
1545251877Speter}
1546251877Speter
1547251877Speter/* Functions to read a serf_ssl_certificate structure. */
1548251877Speter
1549269847Speter/* Takes a counted length string and escapes any NUL bytes so that
1550269847Speter * it can be used as a C string.  NUL bytes are escaped as 3 characters
1551269847Speter * "\00" (that's a literal backslash).
1552269847Speter * The returned string is allocated in POOL.
1553269847Speter */
1554269847Speterstatic char *
1555269847Speterpstrdup_escape_nul_bytes(const char *buf, int len, apr_pool_t *pool)
1556269847Speter{
1557269847Speter    int i, nul_count = 0;
1558269847Speter    char *ret;
1559269847Speter
1560269847Speter    /* First determine if there are any nul bytes in the string. */
1561269847Speter    for (i = 0; i < len; i++) {
1562269847Speter        if (buf[i] == '\0')
1563269847Speter            nul_count++;
1564269847Speter    }
1565269847Speter
1566269847Speter    if (nul_count == 0) {
1567269847Speter        /* There aren't so easy case to just copy the string */
1568269847Speter        ret = apr_pstrdup(pool, buf);
1569269847Speter    } else {
1570269847Speter        /* There are so we have to replace nul bytes with escape codes
1571269847Speter         * Proper length is the length of the original string, plus
1572269847Speter         * 2 times the number of nulls (for two digit hex code for
1573269847Speter         * the value) + the trailing null. */
1574269847Speter        char *pos;
1575269847Speter        ret = pos = apr_palloc(pool, len + 2 * nul_count + 1);
1576269847Speter        for (i = 0; i < len; i++) {
1577269847Speter            if (buf[i] != '\0') {
1578269847Speter                *(pos++) = buf[i];
1579269847Speter            } else {
1580269847Speter                *(pos++) = '\\';
1581269847Speter                *(pos++) = '0';
1582269847Speter                *(pos++) = '0';
1583269847Speter            }
1584269847Speter        }
1585269847Speter        *pos = '\0';
1586269847Speter    }
1587269847Speter
1588269847Speter    return ret;
1589269847Speter}
1590269847Speter
1591269847Speter/* Creates a hash_table with keys (E, CN, OU, O, L, ST and C). Any NUL bytes in
1592269847Speter   these fields in the certificate will be escaped as \00. */
1593251877Speterstatic apr_hash_t *
1594251877Speterconvert_X509_NAME_to_table(X509_NAME *org, apr_pool_t *pool)
1595251877Speter{
1596251877Speter    char buf[1024];
1597251877Speter    int ret;
1598251877Speter
1599251877Speter    apr_hash_t *tgt = apr_hash_make(pool);
1600251877Speter
1601251877Speter    ret = X509_NAME_get_text_by_NID(org,
1602251877Speter                                    NID_commonName,
1603251877Speter                                    buf, 1024);
1604251877Speter    if (ret != -1)
1605269847Speter        apr_hash_set(tgt, "CN", APR_HASH_KEY_STRING,
1606269847Speter                     pstrdup_escape_nul_bytes(buf, ret, pool));
1607251877Speter    ret = X509_NAME_get_text_by_NID(org,
1608251877Speter                                    NID_pkcs9_emailAddress,
1609251877Speter                                    buf, 1024);
1610251877Speter    if (ret != -1)
1611269847Speter        apr_hash_set(tgt, "E", APR_HASH_KEY_STRING,
1612269847Speter                     pstrdup_escape_nul_bytes(buf, ret, pool));
1613251877Speter    ret = X509_NAME_get_text_by_NID(org,
1614251877Speter                                    NID_organizationalUnitName,
1615251877Speter                                    buf, 1024);
1616251877Speter    if (ret != -1)
1617269847Speter        apr_hash_set(tgt, "OU", APR_HASH_KEY_STRING,
1618269847Speter                     pstrdup_escape_nul_bytes(buf, ret, pool));
1619251877Speter    ret = X509_NAME_get_text_by_NID(org,
1620251877Speter                                    NID_organizationName,
1621251877Speter                                    buf, 1024);
1622251877Speter    if (ret != -1)
1623269847Speter        apr_hash_set(tgt, "O", APR_HASH_KEY_STRING,
1624269847Speter                     pstrdup_escape_nul_bytes(buf, ret, pool));
1625251877Speter    ret = X509_NAME_get_text_by_NID(org,
1626251877Speter                                    NID_localityName,
1627251877Speter                                    buf, 1024);
1628251877Speter    if (ret != -1)
1629269847Speter        apr_hash_set(tgt, "L", APR_HASH_KEY_STRING,
1630269847Speter                     pstrdup_escape_nul_bytes(buf, ret, pool));
1631251877Speter    ret = X509_NAME_get_text_by_NID(org,
1632251877Speter                                    NID_stateOrProvinceName,
1633251877Speter                                    buf, 1024);
1634251877Speter    if (ret != -1)
1635269847Speter        apr_hash_set(tgt, "ST", APR_HASH_KEY_STRING,
1636269847Speter                     pstrdup_escape_nul_bytes(buf, ret, pool));
1637251877Speter    ret = X509_NAME_get_text_by_NID(org,
1638251877Speter                                    NID_countryName,
1639251877Speter                                    buf, 1024);
1640251877Speter    if (ret != -1)
1641269847Speter        apr_hash_set(tgt, "C", APR_HASH_KEY_STRING,
1642269847Speter                     pstrdup_escape_nul_bytes(buf, ret, pool));
1643251877Speter
1644251877Speter    return tgt;
1645251877Speter}
1646251877Speter
1647251877Speter
1648251877Speterint serf_ssl_cert_depth(const serf_ssl_certificate_t *cert)
1649251877Speter{
1650251877Speter    return cert->depth;
1651251877Speter}
1652251877Speter
1653251877Speter
1654251877Speterapr_hash_t *serf_ssl_cert_issuer(
1655251877Speter    const serf_ssl_certificate_t *cert,
1656251877Speter    apr_pool_t *pool)
1657251877Speter{
1658251877Speter    X509_NAME *issuer = X509_get_issuer_name(cert->ssl_cert);
1659251877Speter
1660251877Speter    if (!issuer)
1661251877Speter        return NULL;
1662251877Speter
1663251877Speter    return convert_X509_NAME_to_table(issuer, pool);
1664251877Speter}
1665251877Speter
1666251877Speter
1667251877Speterapr_hash_t *serf_ssl_cert_subject(
1668251877Speter    const serf_ssl_certificate_t *cert,
1669251877Speter    apr_pool_t *pool)
1670251877Speter{
1671251877Speter    X509_NAME *subject = X509_get_subject_name(cert->ssl_cert);
1672251877Speter
1673251877Speter    if (!subject)
1674251877Speter        return NULL;
1675251877Speter
1676251877Speter    return convert_X509_NAME_to_table(subject, pool);
1677251877Speter}
1678251877Speter
1679251877Speter
1680251877Speterapr_hash_t *serf_ssl_cert_certificate(
1681251877Speter    const serf_ssl_certificate_t *cert,
1682251877Speter    apr_pool_t *pool)
1683251877Speter{
1684251877Speter    apr_hash_t *tgt = apr_hash_make(pool);
1685251877Speter    unsigned int md_size, i;
1686251877Speter    unsigned char md[EVP_MAX_MD_SIZE];
1687251877Speter    BIO *bio;
1688269847Speter    apr_array_header_t *san_arr;
1689251877Speter
1690251877Speter    /* sha1 fingerprint */
1691251877Speter    if (X509_digest(cert->ssl_cert, EVP_sha1(), md, &md_size)) {
1692251877Speter        const char hex[] = "0123456789ABCDEF";
1693251877Speter        char fingerprint[EVP_MAX_MD_SIZE * 3];
1694251877Speter
1695251877Speter        for (i=0; i<md_size; i++) {
1696251877Speter            fingerprint[3*i] = hex[(md[i] & 0xf0) >> 4];
1697251877Speter            fingerprint[(3*i)+1] = hex[(md[i] & 0x0f)];
1698251877Speter            fingerprint[(3*i)+2] = ':';
1699251877Speter        }
1700251877Speter        if (md_size > 0)
1701251877Speter            fingerprint[(3*(md_size-1))+2] = '\0';
1702251877Speter        else
1703251877Speter            fingerprint[0] = '\0';
1704251877Speter
1705251877Speter        apr_hash_set(tgt, "sha1", APR_HASH_KEY_STRING,
1706251877Speter                     apr_pstrdup(pool, fingerprint));
1707251877Speter    }
1708251877Speter
1709251877Speter    /* set expiry dates */
1710251877Speter    bio = BIO_new(BIO_s_mem());
1711251877Speter    if (bio) {
1712251877Speter        ASN1_TIME *notBefore, *notAfter;
1713251877Speter        char buf[256];
1714251877Speter
1715251877Speter        memset (buf, 0, sizeof (buf));
1716251877Speter        notBefore = X509_get_notBefore(cert->ssl_cert);
1717251877Speter        if (ASN1_TIME_print(bio, notBefore)) {
1718251877Speter            BIO_read(bio, buf, 255);
1719251877Speter            apr_hash_set(tgt, "notBefore", APR_HASH_KEY_STRING,
1720251877Speter                         apr_pstrdup(pool, buf));
1721251877Speter        }
1722251877Speter        memset (buf, 0, sizeof (buf));
1723251877Speter        notAfter = X509_get_notAfter(cert->ssl_cert);
1724251877Speter        if (ASN1_TIME_print(bio, notAfter)) {
1725251877Speter            BIO_read(bio, buf, 255);
1726251877Speter            apr_hash_set(tgt, "notAfter", APR_HASH_KEY_STRING,
1727251877Speter                         apr_pstrdup(pool, buf));
1728251877Speter        }
1729251877Speter    }
1730251877Speter    BIO_free(bio);
1731251877Speter
1732251877Speter    /* Get subjectAltNames */
1733269847Speter    if (!get_subject_alt_names(&san_arr, cert->ssl_cert, EscapeNulAndCopy, pool))
1734251877Speter        apr_hash_set(tgt, "subjectAltName", APR_HASH_KEY_STRING, san_arr);
1735251877Speter
1736251877Speter    return tgt;
1737251877Speter}
1738251877Speter
1739251877Speter
1740251877Speterconst char *serf_ssl_cert_export(
1741251877Speter    const serf_ssl_certificate_t *cert,
1742251877Speter    apr_pool_t *pool)
1743251877Speter{
1744251877Speter    char *binary_cert;
1745251877Speter    char *encoded_cert;
1746251877Speter    int len;
1747251877Speter    unsigned char *unused;
1748251877Speter
1749251877Speter    /* find the length of the DER encoding. */
1750251877Speter    len = i2d_X509(cert->ssl_cert, NULL);
1751251877Speter    if (len < 0) {
1752251877Speter        return NULL;
1753251877Speter    }
1754251877Speter
1755251877Speter    binary_cert = apr_palloc(pool, len);
1756251877Speter    unused = (unsigned char *)binary_cert;
1757251877Speter    len = i2d_X509(cert->ssl_cert, &unused);  /* unused is incremented  */
1758251877Speter    if (len < 0) {
1759251877Speter        return NULL;
1760251877Speter    }
1761251877Speter
1762251877Speter    encoded_cert = apr_palloc(pool, apr_base64_encode_len(len));
1763251877Speter    apr_base64_encode(encoded_cert, binary_cert, len);
1764251877Speter
1765251877Speter    return encoded_cert;
1766251877Speter}
1767251877Speter
1768251877Speter/* Disables compression for all SSL sessions. */
1769251877Speterstatic void disable_compression(serf_ssl_context_t *ssl_ctx)
1770251877Speter{
1771251877Speter#ifdef SSL_OP_NO_COMPRESSION
1772251877Speter    SSL_CTX_set_options(ssl_ctx->ctx, SSL_OP_NO_COMPRESSION);
1773251877Speter#endif
1774251877Speter}
1775251877Speter
1776251877Speterapr_status_t serf_ssl_use_compression(serf_ssl_context_t *ssl_ctx, int enabled)
1777251877Speter{
1778251877Speter    if (enabled) {
1779251877Speter#ifdef SSL_OP_NO_COMPRESSION
1780251877Speter        SSL_clear_options(ssl_ctx->ssl, SSL_OP_NO_COMPRESSION);
1781251877Speter        return APR_SUCCESS;
1782251877Speter#endif
1783251877Speter    } else {
1784251877Speter#ifdef SSL_OP_NO_COMPRESSION
1785251877Speter        SSL_set_options(ssl_ctx->ssl, SSL_OP_NO_COMPRESSION);
1786251877Speter        return APR_SUCCESS;
1787251877Speter#endif
1788251877Speter    }
1789251877Speter
1790251877Speter    return APR_EGENERAL;
1791251877Speter}
1792251877Speter
1793251877Speterstatic void serf_ssl_destroy_and_data(serf_bucket_t *bucket)
1794251877Speter{
1795251877Speter    ssl_context_t *ctx = bucket->data;
1796251877Speter
1797251877Speter    if (!--ctx->ssl_ctx->refcount) {
1798251877Speter        ssl_free_context(ctx->ssl_ctx);
1799251877Speter    }
1800251877Speter
1801251877Speter    serf_default_destroy_and_data(bucket);
1802251877Speter}
1803251877Speter
1804251877Speterstatic void serf_ssl_decrypt_destroy_and_data(serf_bucket_t *bucket)
1805251877Speter{
1806251877Speter    ssl_context_t *ctx = bucket->data;
1807251877Speter
1808251877Speter    serf_bucket_destroy(*ctx->our_stream);
1809251877Speter
1810251877Speter    serf_ssl_destroy_and_data(bucket);
1811251877Speter}
1812251877Speter
1813251877Speterstatic void serf_ssl_encrypt_destroy_and_data(serf_bucket_t *bucket)
1814251877Speter{
1815251877Speter    ssl_context_t *ctx = bucket->data;
1816251877Speter    serf_ssl_context_t *ssl_ctx = ctx->ssl_ctx;
1817251877Speter
1818251877Speter    if (ssl_ctx->encrypt.stream == *ctx->our_stream) {
1819251877Speter        serf_bucket_destroy(*ctx->our_stream);
1820251877Speter        serf_bucket_destroy(ssl_ctx->encrypt.pending);
1821251877Speter
1822251877Speter        /* Reset our encrypted status and databuf. */
1823251877Speter        ssl_ctx->encrypt.status = APR_SUCCESS;
1824251877Speter        ssl_ctx->encrypt.databuf.status = APR_SUCCESS;
1825251877Speter
1826251877Speter        /* Advance to the next stream - if we have one. */
1827251877Speter        if (ssl_ctx->encrypt.stream_next == NULL) {
1828251877Speter            ssl_ctx->encrypt.stream = NULL;
1829251877Speter            ssl_ctx->encrypt.pending = NULL;
1830251877Speter        }
1831251877Speter        else {
1832251877Speter            bucket_list_t *cur;
1833251877Speter
1834251877Speter            cur = ssl_ctx->encrypt.stream_next;
1835251877Speter            ssl_ctx->encrypt.stream = cur->bucket;
1836251877Speter            ssl_ctx->encrypt.pending =
1837251877Speter                serf_bucket_aggregate_create(cur->bucket->allocator);
1838251877Speter            ssl_ctx->encrypt.stream_next = cur->next;
1839251877Speter            serf_bucket_mem_free(ssl_ctx->allocator, cur);
1840251877Speter        }
1841251877Speter    }
1842251877Speter    else {
1843251877Speter        /* Ah, darn.  We haven't sent this one along yet. */
1844251877Speter        return;
1845251877Speter    }
1846251877Speter    serf_ssl_destroy_and_data(bucket);
1847251877Speter}
1848251877Speter
1849251877Speterstatic apr_status_t serf_ssl_read(serf_bucket_t *bucket,
1850251877Speter                                  apr_size_t requested,
1851251877Speter                                  const char **data, apr_size_t *len)
1852251877Speter{
1853251877Speter    ssl_context_t *ctx = bucket->data;
1854251877Speter
1855251877Speter    return serf_databuf_read(ctx->databuf, requested, data, len);
1856251877Speter}
1857251877Speter
1858251877Speterstatic apr_status_t serf_ssl_readline(serf_bucket_t *bucket,
1859251877Speter                                      int acceptable, int *found,
1860251877Speter                                      const char **data,
1861251877Speter                                      apr_size_t *len)
1862251877Speter{
1863251877Speter    ssl_context_t *ctx = bucket->data;
1864251877Speter
1865251877Speter    return serf_databuf_readline(ctx->databuf, acceptable, found, data, len);
1866251877Speter}
1867251877Speter
1868251877Speterstatic apr_status_t serf_ssl_peek(serf_bucket_t *bucket,
1869251877Speter                                  const char **data,
1870251877Speter                                  apr_size_t *len)
1871251877Speter{
1872251877Speter    ssl_context_t *ctx = bucket->data;
1873251877Speter
1874251877Speter    return serf_databuf_peek(ctx->databuf, data, len);
1875251877Speter}
1876251877Speter
1877251877Speter
1878251877Speterconst serf_bucket_type_t serf_bucket_type_ssl_encrypt = {
1879251877Speter    "SSLENCRYPT",
1880251877Speter    serf_ssl_read,
1881251877Speter    serf_ssl_readline,
1882251877Speter    serf_default_read_iovec,
1883251877Speter    serf_default_read_for_sendfile,
1884251877Speter    serf_default_read_bucket,
1885251877Speter    serf_ssl_peek,
1886251877Speter    serf_ssl_encrypt_destroy_and_data,
1887251877Speter};
1888251877Speter
1889251877Speterconst serf_bucket_type_t serf_bucket_type_ssl_decrypt = {
1890251877Speter    "SSLDECRYPT",
1891251877Speter    serf_ssl_read,
1892251877Speter    serf_ssl_readline,
1893251877Speter    serf_default_read_iovec,
1894251877Speter    serf_default_read_for_sendfile,
1895251877Speter    serf_default_read_bucket,
1896251877Speter    serf_ssl_peek,
1897251877Speter    serf_ssl_decrypt_destroy_and_data,
1898251877Speter};
1899