Search
j0ke.net Open Build Service
>
Projects
>
home:jg
:
http-testing
>
nginx
> nginx-1.3.12-polarssl-20130217.diff
Sign Up
|
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File nginx-1.3.12-polarssl-20130217.diff of Package nginx (Revision 145)
Currently displaying revision
145
,
show latest
diff -uNr nginx-1.3.12/auto/lib/conf nginx-1.3.12-polarssl/auto/lib/conf --- nginx-1.3.12/auto/lib/conf 2012-01-18 07:07:43.000000000 -0800 +++ nginx-1.3.12-polarssl/auto/lib/conf 2013-02-17 00:29:25.000000000 -0800 @@ -20,9 +20,21 @@ fi fi +if [ $USE_SSL = YES ]; then + if [ $USE_OPENSSL = YES -o $OPENSSL != NONE ]; then + . auto/lib/openssl/conf + elif [ $USE_POLARSSL = YES -o $POLARSSL != NONE ]; then + . auto/lib/polarssl/conf + else + cat << END + +$0: error: Some modules requires a SSL library. +You can either disable the modules or you have to enable a SSL +implementation. -if [ $USE_OPENSSL = YES ]; then - . auto/lib/openssl/conf +END + exit 1 + fi fi if [ $USE_MD5 = YES ]; then diff -uNr nginx-1.3.12/auto/lib/make nginx-1.3.12-polarssl/auto/lib/make --- nginx-1.3.12/auto/lib/make 2012-01-18 07:07:43.000000000 -0800 +++ nginx-1.3.12-polarssl/auto/lib/make 2013-02-17 04:49:55.000000000 -0800 @@ -19,6 +19,10 @@ . auto/lib/openssl/make fi +if [ $POLARSSL != NONE -a $POLARSSL != NO -a $POLARSSL != YES ]; then + . auto/lib/polarssl/make +fi + if [ $ZLIB != NONE -a $ZLIB != NO -a $ZLIB != YES ]; then . auto/lib/zlib/make fi diff -uNr nginx-1.3.12/auto/lib/polarssl/conf nginx-1.3.12-polarssl/auto/lib/polarssl/conf --- nginx-1.3.12/auto/lib/polarssl/conf 1969-12-31 16:00:00.000000000 -0800 +++ nginx-1.3.12-polarssl/auto/lib/polarssl/conf 2013-02-17 00:37:06.000000000 -0800 @@ -0,0 +1,70 @@ + +# Copyright (C) Igor Sysoev +# Copyright (C) Nginx, Inc. + + +if [ $POLARSSL != NONE ]; then + + case "$CC" in + + cl | bcc32) + # Someone that cares should support windows. + +cat << END + +$0: error: Ngnix's PolarSSL support requires a non-cl/bcc32 compiler. +The build infrastructure for PolarSSL support has not been written for cl or +bcc32. You can either use GCC or try using OpenSSL instead. + +END + exit 1 + ;; + + *) + have=NGX_POLARSSL . auto/have + have=NGX_SSL . auto/have + + CORE_INCS="$CORE_INCS $POLARSSL/.polarssl/include" + CORE_DEPS="$CORE_DEPS $POLARSSL/.polarssl/include/polarssl/config.h" + CORE_LIBS="$CORE_LIBS $POLARSSL/.polarssl/lib/libpolarssl.a" + CORE_LIBS="$CORE_LIBS $NGX_LIBDL" + ;; + esac + +else + + if [ "$NGX_PLATFORM" != win32 ]; then + + POLARSSL=NO + + ngx_feature="PolarSSL library" + ngx_feature_name="NGX_POLARSSL" + ngx_feature_run=no + ngx_feature_incs="#include <polarssl/config.h> + #include <polarssl/ssl.h>" + ngx_feature_path= + ngx_feature_libs="-lpolarssl" + ngx_feature_test="ssl_context c; ssl_init(&c);" + . auto/feature + + if [ $ngx_found = yes ]; then + have=NGX_SSL . auto/have + CORE_LIBS="$CORE_LIBS $ngx_feature_libs $NGX_LIBDL" + POLARSSL=YES + fi + fi + + if [ $POLARSSL != YES ]; then + +cat << END + +$0: error: SSL modules require the PolarSSL library. +You can either do not enable the modules, or install the PolarSSL library +into the system, or build the PolarSSL library statically from the source +with nginx by using --with-polarssl=<path> option. + +END + exit 1 + fi + +fi diff -uNr nginx-1.3.12/auto/lib/polarssl/make nginx-1.3.12-polarssl/auto/lib/polarssl/make --- nginx-1.3.12/auto/lib/polarssl/make 1969-12-31 16:00:00.000000000 -0800 +++ nginx-1.3.12-polarssl/auto/lib/polarssl/make 2013-02-17 00:11:52.000000000 -0800 @@ -0,0 +1,31 @@ + +# Copyright (C) Igor Sysoev +# Copyright (C) Nginx, Inc. + + +case "$CC" in + + # TODO: Someone that cares should write this for cl/BCC. + + cl) + exit 1 + ;; + + bcc32) + exit 1 + ;; + + *) + cat << END >> $NGX_MAKEFILE + +$POLARSSL/.polarssl/include/polarssl/config.h: $NGX_MAKEFILE + cd $POLARSSL \\ + && \$(MAKE) clean \\ + && \$(MAKE) no_test \\ + && \$(MAKE) install DESTDIR=.polarssl + +END + + ;; + +esac diff -uNr nginx-1.3.12/auto/modules nginx-1.3.12-polarssl/auto/modules --- nginx-1.3.12/auto/modules 2012-09-10 09:52:47.000000000 -0700 +++ nginx-1.3.12-polarssl/auto/modules 2013-02-17 04:52:21.000000000 -0800 @@ -275,7 +275,7 @@ fi if [ $HTTP_SSL = YES ]; then - USE_OPENSSL=YES + USE_SSL=YES have=NGX_HTTP_SSL . auto/have HTTP_MODULES="$HTTP_MODULES $HTTP_SSL_MODULE" HTTP_DEPS="$HTTP_DEPS $HTTP_SSL_DEPS" @@ -399,17 +399,24 @@ if [ $MAIL_SSL = YES ]; then have=NGX_MAIL_SSL . auto/have - USE_OPENSSL=YES + USE_SSL=YES fi modules="$CORE_MODULES $EVENT_MODULES" +if [ $USE_SSL = YES ]; then + if [ $OPENSSL != NONE -o $USE_OPENSSL = YES ]; then + modules="$modules $OPENSSL_MODULE" + CORE_DEPS="$CORE_DEPS $OPENSSL_DEPS" + CORE_SRCS="$CORE_SRCS $OPENSSL_SRCS" + fi -if [ $USE_OPENSSL = YES ]; then - modules="$modules $OPENSSL_MODULE" - CORE_DEPS="$CORE_DEPS $OPENSSL_DEPS" - CORE_SRCS="$CORE_SRCS $OPENSSL_SRCS" + if [ $POLARSSL != NONE -o $USE_POLARSSL = YES ]; then + modules="$modules $POLARSSL_MODULE" + CORE_DEPS="$CORE_DEPS $POLARSSL_DEPS" + CORE_SRCS="$CORE_SRCS $POLARSSL_SRCS" + fi fi if [ $USE_PCRE = YES ]; then diff -uNr nginx-1.3.12/auto/options nginx-1.3.12-polarssl/auto/options --- nginx-1.3.12/auto/options 2012-09-26 09:39:38.000000000 -0700 +++ nginx-1.3.12-polarssl/auto/options 2013-02-17 04:55:03.000000000 -0800 @@ -117,9 +117,14 @@ PCRE_CONF_OPT= PCRE_JIT=NO +USE_SSL=NO + USE_OPENSSL=NO OPENSSL=NONE +USE_POLARSSL=NO +POLARSSL=NONE + USE_MD5=NO MD5=NONE MD5_OPT= @@ -284,9 +289,14 @@ --with-pcre-opt=*) PCRE_OPT="$value" ;; --with-pcre-jit) PCRE_JIT=YES ;; + --with-openssl) USE_OPENSSL=YES ;; --with-openssl=*) OPENSSL="$value" ;; --with-openssl-opt=*) OPENSSL_OPT="$value" ;; + --with-polarssl) USE_POLARSSL=YES ;; + --with-polarssl=*) POLARSSL="$value" ;; + --with-polarssl-opt=*) POLARSSL_OPT="$value" ;; + --with-md5=*) MD5="$value" ;; --with-md5-opt=*) MD5_OPT="$value" ;; --with-md5-asm) MD5_ASM=YES ;; @@ -454,9 +464,14 @@ --with-libatomic force libatomic_ops library usage --with-libatomic=DIR set path to libatomic_ops library sources + --with-openssl force OpenSSL library usage --with-openssl=DIR set path to OpenSSL library sources --with-openssl-opt=OPTIONS set additional build options for OpenSSL + --with-polarssl force PolarSSL library usage + --with-polarssl=DIR set path to PolarSSL library sources + --with-polarssl-opt=OPTIONS set additional build options for PolarSSL + --with-debug enable debug logging END diff -uNr nginx-1.3.12/auto/sources nginx-1.3.12-polarssl/auto/sources --- nginx-1.3.12/auto/sources 2012-10-01 05:41:08.000000000 -0700 +++ nginx-1.3.12-polarssl/auto/sources 2013-02-14 02:29:11.000000000 -0800 @@ -80,6 +80,10 @@ OPENSSL_SRCS="src/event/ngx_event_openssl.c \ src/event/ngx_event_openssl_stapling.c" +POLARSSL_MODULE=ngx_polarssl_module +POLARSSL_DEPS=src/event/ngx_event_polarssl.h +POLARSSL_SRCS="src/event/ngx_event_polarssl.c" + EVENT_MODULES="ngx_events_module ngx_event_core_module" diff -uNr nginx-1.3.12/auto/summary nginx-1.3.12-polarssl/auto/summary --- nginx-1.3.12/auto/summary 2012-01-18 07:07:43.000000000 -0800 +++ nginx-1.3.12-polarssl/auto/summary 2013-02-14 02:49:07.000000000 -0800 @@ -49,6 +49,12 @@ *) echo " + using OpenSSL library: $OPENSSL" ;; esac +case $POLARSSL in + YES) echo " + using system PolarSSL library" ;; + NONE) echo " + PolarSSL library is not used" ;; + *) echo " + using PolarSSL library: $POLARSSL" ;; +esac + case $MD5 in YES) echo " + md5: using $MD5_LIB library" ;; NONE) echo " + md5 library is not used" ;; diff -uNr nginx-1.3.12/src/core/nginx.c nginx-1.3.12-polarssl/src/core/nginx.c --- nginx-1.3.12/src/core/nginx.c 2012-10-23 02:08:41.000000000 -0700 +++ nginx-1.3.12-polarssl/src/core/nginx.c 2013-02-14 05:51:17.000000000 -0800 @@ -283,7 +283,7 @@ } /* STUB */ -#if (NGX_OPENSSL) +#if (NGX_OPENSSL) || (NGX_POLARSSL) ngx_ssl_init(log); #endif diff -uNr nginx-1.3.12/src/core/ngx_core.h nginx-1.3.12-polarssl/src/core/ngx_core.h --- nginx-1.3.12/src/core/ngx_core.h 2012-10-01 05:47:55.000000000 -0700 +++ nginx-1.3.12-polarssl/src/core/ngx_core.h 2013-02-14 03:00:07.000000000 -0800 @@ -73,6 +73,9 @@ #if (NGX_OPENSSL) #include <ngx_event_openssl.h> #endif +#if (NGX_POLARSSL) +#include <ngx_event_polarssl.h> +#endif #include <ngx_process_cycle.h> #include <ngx_conf_file.h> #include <ngx_open_file_cache.h> diff -uNr nginx-1.3.12/src/event/ngx_event_polarssl.c nginx-1.3.12-polarssl/src/event/ngx_event_polarssl.c --- nginx-1.3.12/src/event/ngx_event_polarssl.c 1969-12-31 16:00:00.000000000 -0800 +++ nginx-1.3.12-polarssl/src/event/ngx_event_polarssl.c 2013-02-17 04:48:16.000000000 -0800 @@ -0,0 +1,2044 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + * Copyright (C) Yawning Angel <yawning at schwanenlied dot me> + */ + +/* + * TODO: (In roughly decreasing order of importance) + * * Make ngx_http_upstream_round_robin's session reuse work with PolarSSL. + * * Check polarssl/config.h to ensure that everything needed is compiled + * into the library. + * * PolarSSL supports SNI but predictably ngx_http_ssl_module's implementation + * is very OpenSSL specific. The path of least resistance is probably to + * just use the NGX_POLARSSL ifdef. + * * It's possible to remove the mutex around ctr_drbg if an instance is + * allocated per thread. Probably not worth it as the mutex should not be + * hotly contested but it's worth investigating. + */ + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +#define POLARSSL_DN_MAX_LENGTH 256 +#define POLARSSL_SSL_CIPHER_MAX_LENGTH 64 + + +static void ngx_ssl_handshake_handler(ngx_event_t *ev); +static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n); +static void ngx_ssl_write_handler(ngx_event_t *wev); +static void ngx_ssl_read_handler(ngx_event_t *rev); +static void ngx_ssl_shutdown_handler(ngx_event_t *ev); +static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, + ngx_slab_pool_t *shpool, ngx_uint_t n); +static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +static int ngx_polarssl_get_cache(void *ctx, ssl_session *session); +static int ngx_polarssl_set_cache(void *ctx, const ssl_session *session); +static void ngx_cdecl ngx_polarssl_error(ngx_uint_t level, ngx_log_t *log, + ngx_err_t err, int sslerr, char *fmt, ...); +static int ngx_polarssl_cipher_in_list(const int id, const int *ciphersuites); +static int ngx_polarssl_rng(void *data, unsigned char *output, size_t output_len); +static void ngx_polarssl_exit(ngx_cycle_t *cycle); + + +static ctr_drbg_context ngx_ctr_drbg; +#if (NGX_THREADS) +static ngx_mutex *ngx_ctr_drbg_mutex; +#endif + +static ngx_command_t ngx_polarssl_commands[] = { + ngx_null_command +}; + +static ngx_core_module_t ngx_polarssl_module_ctx = { + ngx_string("polarssl"), + NULL, + NULL +}; + +ngx_module_t ngx_polarssl_module = { + NGX_MODULE_V1, + &ngx_polarssl_module_ctx, /* module context */ + ngx_polarssl_commands, /* module directives */ + NGX_CORE_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + ngx_polarssl_exit, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +ngx_int_t +ngx_ssl_init(ngx_log_t *log) +{ + static unsigned char ctr_drbg_custom[] = "nginx-polarssl"; + entropy_context entropy; + int sslerr; + + /* Initialize the PRNG */ + + entropy_init(&entropy); + sslerr = ctr_drbg_init(&ngx_ctr_drbg, entropy_func, &entropy, + ctr_drbg_custom, ngx_strlen(ctr_drbg_custom)); + if (sslerr != 0) { + ngx_polarssl_error(NGX_LOG_EMERG, log, 0, sslerr, + "ctr_drbg_init() failed"); + return NGX_ERROR; + } + +#if (NGX_THREADS) + ngx_ctr_drbg_mutex = ngx_mutex_init(log, 0); + if (ngx_ctr_drbg_mutex == NULL) { + return NGX_ERROR; + } +#endif + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) +{ + int minor_min = 99; + int minor_max = -99; + + ssl->data = data; + ssl->builtin_session_cache = NGX_SSL_NO_SCACHE; + ssl->cache_shm_zone = NULL; + + /* + * PolarSSL only allows the user to specify the minimum and* maximum + * versions of SSL/TLS to support. + */ + + if (protocols & NGX_SSL_SSLv3) { + minor_min = SSL_MINOR_VERSION_0; + minor_max = SSL_MINOR_VERSION_0; + } + + if (protocols & NGX_SSL_TLSv1) { + minor_min = ngx_min(minor_min, SSL_MINOR_VERSION_1); + minor_max = SSL_MINOR_VERSION_1; + } + + if (protocols & NGX_SSL_TLSv1_1) { + minor_min = ngx_min(minor_min, SSL_MINOR_VERSION_2); + minor_max = SSL_MINOR_VERSION_2; + } + + if (protocols & NGX_SSL_TLSv1_2) { + minor_min = ngx_min(minor_min, SSL_MINOR_VERSION_3); + minor_max = SSL_MINOR_VERSION_3; + } + + ssl->minor_min = minor_min; + ssl->minor_max = minor_max; + + /* Initialize the rest of the global state with sane defaults */ + + ssl->ciphersuites = NULL; + ngx_memset(&ssl->dhm_ctx, 0, sizeof(dhm_context)); + ngx_memset(&ssl->own_cert, 0, sizeof(x509_cert)); + ngx_memset(&ssl->own_key, 0, sizeof(rsa_context)); + ngx_memset(&ssl->ca_cert, 0, sizeof(x509_cert)); + ngx_memset(&ssl->ca_crl, 0, sizeof(x509_crl)); + ssl->have_own_cert = 0; + ssl->have_ca_cert = 0; + ssl->have_ca_crl = 0; + + ssl->ctx = ssl; + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, + ngx_str_t *key) +{ + int sslerr; + + if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) { + return NGX_ERROR; + } + + sslerr = x509parse_crtfile(&ssl->own_cert, (char *) cert->data); + if (sslerr != 0) { + ngx_polarssl_error(NGX_LOG_EMERG, ssl->log, 0, sslerr, + "x509parse_crtfile(%p, \"%s\") failed", + &ssl->own_cert, cert->data); + return NGX_ERROR; + } + + if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) { + return NGX_ERROR; + } + + sslerr = x509parse_keyfile(&ssl->own_key, (char *) key->data, NULL); + if (sslerr != 0) { + ngx_polarssl_error(NGX_LOG_EMERG, ssl->log, 0, sslerr, + "x509parse_keyfile(%p, \"%s\", NULL) failed", + &ssl->own_key, key->data); + return NGX_ERROR; + } + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, + ngx_int_t depth) +{ + int sslerr; + + if (cert->len == 0) { + return NGX_OK; + } + + if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) { + return NGX_ERROR; + } + + sslerr = x509parse_crtfile(&ssl->ca_cert, (char *) cert->data); + if (sslerr != 0) { + ngx_polarssl_error(NGX_LOG_EMERG, ssl->log, 0, sslerr, + "x509parse_crtfile(%p, \"%s\") failed", + &ssl->ca_cert, cert->data); + return NGX_ERROR; + } + + ssl->have_ca_cert = 1; + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, + ngx_int_t depth) +{ + int sslerr; + + if (cert->len == 0) { + return NGX_OK; + } + + if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) { + return NGX_ERROR; + } + + /* Just add the certificate to the CA cert chain */ + + sslerr = x509parse_crtfile(&ssl->ca_cert, (char *) cert->data); + if (sslerr != 0) { + ngx_polarssl_error(NGX_LOG_EMERG, ssl->log, 0, sslerr, + "x509parse_crtfile(%p, \"%s\") failed", + &ssl->ca_cert, cert->data); + return NGX_ERROR; + } + + ssl->have_ca_cert = 1; + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl) +{ + int sslerr; + + if (crl->len == 0) { + return NGX_OK; + } + + if (ngx_conf_full_name(cf->cycle, crl, 1) != NGX_OK) { + return NGX_ERROR; + } + + sslerr = x509parse_crlfile(&ssl->ca_crl, (char *) crl->data); + if (sslerr != 0) { + ngx_polarssl_error(NGX_LOG_EMERG, ssl->log, 0, sslerr, + "x509parse_crlfile(%p, \"%s\") failed", + &ssl->ca_crl, crl->data, sslerr); + return NGX_ERROR; + } + + ssl->have_ca_crl = 1; + + return NGX_ERROR; +} + +ngx_int_t +ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file, + ngx_str_t *responder, ngx_uint_t verify) +{ + + /* Not supported by PolarSSL */ + + return NGX_ERROR; +} + +ngx_int_t +ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_resolver_t *resolver, ngx_msec_t resolver_timeout) +{ + + /* Not supported by PolarSSL */ + + return NGX_ERROR; +} + +RSA * +ngx_ssl_rsa512_key_callback(SSL *ssl, int is_export, int key_length) +{ + + /* + * Not supported by PolarSSL, but clients that are too old more than likely + * will not support SSL 3.0 (or higher) anyway. + */ + + return NULL; +} + +ngx_int_t +ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) +{ + int sslerr; + static unsigned char dh1024_pem[] = { + "-----BEGIN DH PARAMETERS-----\n" + "MIGHAoGBALu8LcrYRnSQfEP89YDpz9vZWKP1aLQtSwju1OsPs1BMbAMCducQgAxc\n" + "y7qokiYUxb7spWWl/fHSh6K8BJvmd4Bg6RqSp1fjBI9osHb302zI8pul34HcLKcl\n" + "7OZicMyaUDXYzs7vnqAnSmOrHlj6/UmI0PZdFGdX2gcd8EXP4WubAgEC\n" + "-----END DH PARAMETERS-----" + }; + + if (file->len == 0) { + sslerr = x509parse_dhm(&ssl->dhm_ctx, dh1024_pem, + ngx_strlen(dh1024_pem)); + if (sslerr != 0) { + ngx_polarssl_error(NGX_LOG_EMERG, ssl->log, 0, sslerr, + "x509parse_dhm() failed"); + + return NGX_ERROR; + } + + return NGX_OK; + } + + if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) { + return NGX_ERROR; + } + + sslerr = x509parse_dhmfile(&ssl->dhm_ctx, (char *) file->data); + if (sslerr != 0) { + ngx_polarssl_error(NGX_LOG_EMERG, ssl->log, 0, sslerr, + "x509parse_dhmfile(%p, \"%s\") failed", + &ssl->dhm_ctx, file->data); + + return NGX_ERROR; + } + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name) +{ + + /* ECDH is not supported by PolarSSL */ + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, + ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t + timeout) +{ + + /* + * Setting up the session cache is done on a per connection basis + * like everything else in PolarSSL, so save the user provided + * setting till later, unless they want to use the builtin + * cache. + * + * If they want to use the builtin cache, log an error because + * the builtin cache is not supported (and probably not worth + * supporting since it is rather trivial, and the one that this + * module provides is better within the context of ngnix). + */ + + if (builtin_session_cache == NGX_SSL_DFLT_BUILTIN_SCACHE) { + ngx_log_error(NGX_LOG_EMERG, ssl->log, 0, + "PolarSSL's builtin session cache is not supported."); + return NGX_ERROR; + } + + ssl->builtin_session_cache = builtin_session_cache; + + if (builtin_session_cache != NGX_SSL_NO_SCACHE) { + ssl->cache_shm_zone = shm_zone; + ssl->cache_ttl = timeout; + } + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data) +{ + size_t len; + ngx_slab_pool_t *shpool; + ngx_ssl_session_cache_t *cache; + + if (data) { + shm_zone->data = data; + return NGX_OK; + } + + if (shm_zone->shm.exists) { + shm_zone->data = data; + return NGX_OK; + } + + /* + * Much like ngx_event_openssl, we use a red-black tree and a queue as + * the backing store for our cache. + */ + + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t)); + if (cache == NULL) { + return NGX_ERROR; + } + + shpool->data = cache; + shm_zone->data = cache; + + ngx_rbtree_init(&cache->session_rbtree, &cache->sentinel, + ngx_ssl_session_rbtree_insert_value); + + ngx_queue_init(&cache->expire_queue); + + len = sizeof(" in SSL session shared cache \"\"") + shm_zone->shm.name.len; + + shpool->log_ctx = ngx_slab_alloc(shpool, len); + if (shpool->log_ctx == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(shpool->log_ctx, " in SSL session shared cache \"%V\"%Z", + &shm_zone->shm.name); + + return NGX_OK; +} + +void +ngx_ssl_remove_cached_session(ngx_ssl_t *ssl, ngx_ssl_session_t *sess) +{ + ngx_shm_zone_t *shm_zone; + ngx_slab_pool_t *shpool; + ngx_ssl_session_cache_t *cache; + ngx_rbtree_node_t *node, *sentinel; + ngx_ssl_sess_id_t *sess_id; + int rc; + uint32_t hash; + + shm_zone = ssl->cache_shm_zone; + if (shm_zone == NULL) { + return; + } + + shpool = (ngx_slab_pool_t*) shm_zone->shm.addr; + cache = shm_zone->data; + + hash = ngx_crc32_short(sess->id, sess->length); + + ngx_shmtx_lock(&shpool->mutex); + + node = cache->session_rbtree.root; + sentinel = cache->session_rbtree.sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + sess_id = (ngx_ssl_sess_id_t *) node; + + rc = ngx_memn2cmp(sess->id, sess_id->session->id, sess->length, + node->data); + + if (rc == 0) { + ngx_queue_remove(&sess_id->queue); + + ngx_rbtree_delete(&cache->session_rbtree, node); + + ngx_slab_free_locked(shpool, sess_id->session); + + ngx_slab_free_locked(shpool, sess_id); + + goto done; + } + + node = (rc < 0) ? node->left : node->right; + } + +done: + ngx_shmtx_unlock(&shpool->mutex); +} + +static int +ngx_polarssl_get_cache(void *ctx, ssl_session *session) +{ + ngx_shm_zone_t *shm_zone; + ngx_slab_pool_t *shpool; + ngx_ssl_session_cache_t *cache; + ngx_rbtree_node_t *node, *sentinel; + ngx_ssl_sess_id_t *sess_id; + time_t expires; + int rc; + uint32_t hash; + + if (ctx == NULL) { + /* NGX_SSL_NONE_SCACHE: Every search is a cache miss */ + return 1; + } + + hash = ngx_crc32_short(session->id, session->length); + + shm_zone = ctx; + shpool = (ngx_slab_pool_t*) shm_zone->shm.addr; + cache = shm_zone->data; + + ngx_shmtx_lock(&shpool->mutex); + + node = cache->session_rbtree.root; + sentinel = cache->session_rbtree.sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + sess_id = (ngx_ssl_sess_id_t *) node; + + rc = ngx_memn2cmp(session->id, sess_id->session->id, session->length, + node->data); + + if (rc == 0) { + + if (session->ciphersuite != sess_id->session->ciphersuite || + session->compression != sess_id->session->compression || + session->length != sess_id->session->length) { + /* The ciphersuite/compression changed out from under us */ + goto done; + } + + /* Check the expiry time */ + + expires = (time_t) sess_id->session->peer_cert; + if (expires > ngx_time()) { + /* Cache hit */ + + ngx_memcpy(session->master, sess_id->session->master, 48); + + ngx_shmtx_unlock(&shpool->mutex); + + return 0; + } + + /* Cache entry expired */ + + ngx_queue_remove(&sess_id->queue); + + ngx_rbtree_delete(&cache->session_rbtree, node); + + ngx_slab_free_locked(shpool, sess_id->session); + + ngx_slab_free_locked(shpool, sess_id); + + goto done; + } + + node = (rc < 0) ? node->left : node->right; + } + +done: + ngx_shmtx_unlock(&shpool->mutex); + + return 1; +} + +static int +ngx_polarssl_set_cache(void *ctx, const ssl_session *session) +{ + ngx_shm_zone_t *shm_zone; + ngx_slab_pool_t *shpool; + ngx_ssl_session_cache_t *cache; + ngx_ssl_sess_id_t *sess_id; + ngx_ssl_session_t *cached_sess; + uint32_t hash; + + if (ctx == NULL) { + /* NGX_SSL_NONE_SCACHE: Never cache any entries, but pretend to do so. */ + return 0; + } + + shm_zone = ctx; + shpool = (ngx_slab_pool_t*) shm_zone->shm.addr; + cache = shm_zone->data; + + ngx_shmtx_lock(&shpool->mutex); + + /* + * Because we need to store the entire ssl_session, in the cache we allocate + * the entry and the ssl_session separately. The entry is 64 bytes in size + * on 64 bit architectures, and ssl_session is 112 bytes. + * + * Since we explicitly do not cache the peer certificate (requires a deep + * copy), we hijack session.peer_cert and use that to store the expiration + * time. As far as I know sizeof(void *) == sizeof(time_t) is a reasonable + * assumption to make. This doesn't actually save anything on 64 bit + * systems, but it *may* on 32 bit and it's not practical to break up a + * ssl_session without being vulnerable to PolarSSL code changes. + */ + + /* Prune some sessions from the cache to ensure the allocation succeds */ + + ngx_ssl_expire_sessions(cache, shpool, 1); + + cached_sess = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_session_t)); + if (cached_sess == NULL) { + + /* Prune the oldest non-expired session, and try again */ + + ngx_ssl_expire_sessions(cache, shpool, 0); + + cached_sess = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_session_t)); + if (cached_sess == NULL) { + goto failed; + } + } + + sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t)); + if (sess_id == NULL) { + goto failed; + } + + memcpy(cached_sess, session, sizeof(ngx_ssl_session_t)); + cached_sess->peer_cert = (x509_cert *) (ngx_time() + cache->ttl); + + hash = ngx_crc32_short(cached_sess->id, cached_sess->length); + + sess_id->node.key = hash; + sess_id->node.data = (u_char) cached_sess->length; + sess_id->session = cached_sess; + + ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue); + + ngx_rbtree_insert(&cache->session_rbtree, &sess_id->node); + + ngx_shmtx_unlock(&shpool->mutex); + + return 0; + +failed: + ngx_shmtx_unlock(&shpool->mutex); + + return 1; +} + +static void +ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, + ngx_slab_pool_t *shpool, ngx_uint_t n) +{ + time_t now, then; + ngx_queue_t *q; + ngx_ssl_sess_id_t *sess_id; + + now = ngx_time(); + + while (n < 3) { + + if (ngx_queue_empty(&cache->expire_queue)) { + return; + } + + q = ngx_queue_last(&cache->expire_queue); + + sess_id = ngx_queue_data(q, ngx_ssl_sess_id_t, queue); + + then = (time_t) sess_id->session->peer_cert; + if (n++ != 0 && then > now) { + return; + } + + ngx_queue_remove(q); + + ngx_rbtree_delete(&cache->session_rbtree, &sess_id->node); + + ngx_slab_free_locked(shpool, sess_id->session); + + ngx_slab_free_locked(shpool, sess_id); + } +} + +static void +ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +{ + ngx_rbtree_node_t **p; + ngx_ssl_sess_id_t *sess_id, *sess_id_temp; + + for ( ;; ) { + + if (node->key < temp->key) { + + p = &temp->left; + + } else if (node->key > temp->key) { + + p = &temp->right; + + } else { /* node->key == temp->key */ + + sess_id = (ngx_ssl_sess_id_t *) node; + sess_id_temp = (ngx_ssl_sess_id_t *) temp; + + p = (ngx_memn2cmp(sess_id->session->id, sess_id_temp->session->id, + (size_t) node->data, (size_t) temp->data) + < 0) ? &temp->left : &temp->right; + } + + if (*p == sentinel) { + break; + } + + temp = *p; + } + + *p = node; + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + ngx_rbt_red(node); +} + +ngx_int_t +ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session) +{ + + /* + * TODO: ngx_http_upstream_round_robin uses this to set a SSL session to + * allow session reuse. + * + * PolarSSL has ssl_set_session, but it does the copy on set. The module + * that actually uses this increments a refcount in ngx_ssl_get_session + * instead so implementing this is requires more understanding of how + * ngx_http_upstream_round_robin works. + */ + + return NGX_OK; +} + +ngx_ssl_session_t* +ngx_ssl_get_session(ngx_connection_t *c) +{ + + /* TODO: ngx_http_upstream_round_robin uses this to copy a SSL session */ + + return NULL; +} + +void +ngx_ssl_free_session(ngx_ssl_session_t *session) +{ + + /* TODO: ngx_http_upstream_round_robin uses this to free a copied SSL session */ +} + +ngx_int_t +ngx_ssl_verify_error_optional(int n) +{ + + /* + * As far as I can tell, PolarSSL doesn't return ignorable values on + * verification failure. + */ + + return 0; +} + +ngx_int_t +ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + s->data = (u_char *) ssl_get_version(c->ssl->connection); + return NGX_OK; +} + +ngx_int_t +ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + s->data = (u_char *) ssl_get_ciphersuite(c->ssl->connection); + return NGX_OK; +} + +ngx_int_t +ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + ssl_session *session = c->ssl->connection->session; + + /* + * ngx_event_openssl's implementation of this returns a hexdump of + * the ASN.1 encoded SSL session object. Our implementation just + * returns a hexdump of the session id, because this routine is not + * named ngx_ssl_get_entire_session_object. + */ + + s->len = session->length * 2; + s->data = ngx_pnalloc(pool, s->len); + if (s->data == NULL) { + return NGX_ERROR; + } + + ngx_hex_dump(s->data, session->id, session->length); + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + static const int header_len = 29; + static const int footer_len = 25; + static const unsigned char pem_header[] = { "-----BEGIN CERTIFICATE-----\r\n" }; + static const unsigned char pem_footer[] = { "-----END CERTIFICATE-----" }; + size_t len = 0, i; + const x509_cert *cert; + unsigned char *p = NULL; + + /* + * PolarSSL does not have a built in routine to write certificates + * in PEM format. Thankfully it's relatively easy to do since it + * keeps a copy of the DER format certificate around. + */ + + cert = ssl_get_peer_cert(c->ssl->connection); + if (cert == NULL || cert->raw.len == 0) { + return NGX_OK; + } + + /* Determine how much buffer space is required */ + + base64_encode(p, &len, cert->raw.p, cert->raw.len); + len += (len / 64 + 1) * 2; + len += header_len; + len += footer_len; + + p = s->data = ngx_pnalloc(pool, len); + if (s->data == NULL) { + return NGX_ERROR; + } + + /* Append the header */ + + ngx_memcpy(p, pem_header, header_len); + p += header_len; + + /* Base64 encode the cert, inserting newlines every 64 characters. */ + + for (i = 0; i < cert->raw.len; /* i incremented in body */) { + size_t to_encode = (cert->raw.len - i > 48) ? 48 : cert->raw.len - i; + size_t dlen = len - (p - s->data); + + base64_encode(p, &dlen, cert->raw.p + i, to_encode); + + p += dlen; + *p++ = '\r'; + *p++ = '\n'; + + i+= to_encode; + } + + /* Append the footer */ + + ngx_memcpy(p, pem_footer, footer_len); + p += footer_len; + *p = '\0'; + + s->len = ngx_strlen(s->data); + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + + /* + * As far as I can tell, both of ngx_ssl_get_certificate and + * ngx_ssl_get_raw_certificate just return the peer certificate + * in PEM format, with ngx_ssl_get_certificate messing with + * whitespace. + * + * Since our PEM generator doesn't prefix any lines with whitespace + * at all, the functions can just return identical output. + */ + + return ngx_ssl_get_raw_certificate(c, pool, s); +} + +ngx_int_t +ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + const x509_cert *cert; + int len; + + cert = ssl_get_peer_cert(c->ssl->connection); + if (cert == NULL) { + return NGX_OK; + } + + s->data = ngx_pnalloc(pool, POLARSSL_DN_MAX_LENGTH); + if (s->data == NULL) { + return NGX_ERROR; + } + + len = x509parse_dn_gets((char *) s->data, POLARSSL_DN_MAX_LENGTH - 1, + &cert->subject); + if (len < 0) { + return NGX_ERROR; + } + + s->len = len; + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + const x509_cert *cert; + int len; + + cert = ssl_get_peer_cert(c->ssl->connection); + if (cert == NULL) { + return NGX_OK; + } + + s->data = ngx_pnalloc(pool, POLARSSL_DN_MAX_LENGTH); + if (s->data == NULL) { + return NGX_ERROR; + } + + len = x509parse_dn_gets((char *) s->data, POLARSSL_DN_MAX_LENGTH - 1, + &cert->issuer); + if (len < 0) { + return NGX_ERROR; + } + + s->len = len; + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + const x509_cert *cert; + int len; + + cert = ssl_get_peer_cert(c->ssl->connection); + if (cert == NULL) { + return NGX_OK; + } + + len = cert->serial.len * 3 + 1; + s->data = ngx_palloc(pool, len); + if (s->data == NULL) { + return NGX_ERROR; + } + + len = x509parse_serial_gets((char *) s->data, len - 1, &cert->serial); + if (len < 0) { + return NGX_ERROR; + } + + s->len = len; + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + const x509_cert *cert; + + if (ssl_get_verify_result(c->ssl->connection) != 0) { + ngx_str_set(s, "FAILED"); + return NGX_OK; + } + + cert = ssl_get_peer_cert(c->ssl->connection); + + if (cert) { + ngx_str_set(s, "SUCCESS"); + } else { + ngx_str_set(s, "NONE"); + } + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, + ngx_uint_t flags) +{ + ngx_ssl_connection_t *sc; + ngx_ssl_conn_t *ssl_ctx; + ngx_ssl_session_cache_t *cache; + int sslerr; + + sc = ngx_pcalloc(c->pool, sizeof(ngx_ssl_connection_t)); + if (sc == NULL) { + return NGX_ERROR; + } + + sc->buffer = ((flags % NGX_SSL_BUFFER) != 0); + + /* Allocate the PolarSSL context */ + + ssl_ctx = ngx_pcalloc(c->pool, sizeof(ngx_ssl_conn_t)); + if (sc == NULL) { + return NGX_ERROR; + } + + /* + * Initialize this PolarSSL context + * + * Note: We also setup the options traditionally set in ngx_ssl_create + * here since each ssl_ctx is unique to each fd. + */ + + sslerr = ssl_init(ssl_ctx); + if (sslerr != 0) { + ngx_polarssl_error(NGX_LOG_ALERT, ssl->log, 0, sslerr, + "ssl_init failed"); + return NGX_ERROR; + } + + if (flags & NGX_SSL_CLIENT) { + ssl_set_endpoint(ssl_ctx, SSL_IS_CLIENT); + + if (ssl->have_own_cert) { + ssl_set_own_cert(ssl_ctx, &ssl->own_cert, &ssl->own_key); + } + } else { + ssl_set_endpoint(ssl_ctx, SSL_IS_SERVER); + ssl_set_own_cert(ssl_ctx, &ssl->own_cert, &ssl->own_key); + } + + if (ssl->have_ca_cert) { + if (ssl->have_ca_crl) { + ssl_set_ca_chain(ssl_ctx, &ssl->ca_cert, &ssl->ca_crl, NULL); + } else { + ssl_set_ca_chain(ssl_ctx, &ssl->ca_cert, NULL, NULL); + } + + /* + * ngx_event_openssl has the callback rigged to allow the handshake + * to continue even if verification fails. We shall do the same. + */ + + ssl_set_authmode(ssl_ctx, SSL_VERIFY_OPTIONAL); + } else { + ssl_set_authmode(ssl_ctx, SSL_VERIFY_NONE); + } + + ssl_set_min_version(ssl_ctx, SSL_MAJOR_VERSION_3, ssl->minor_min); + ssl_set_max_version(ssl_ctx, SSL_MAJOR_VERSION_3, ssl->minor_max); + + ssl_set_renegotiation(ssl_ctx, SSL_RENEGOTIATION_ENABLED); + ssl_legacy_renegotiation(ssl_ctx, SSL_LEGACY_NO_RENEGOTIATION); + + ssl_set_rng(ssl_ctx, ngx_polarssl_rng, &ngx_ctr_drbg); + ssl_set_bio(ssl_ctx, net_recv, &c->fd, net_send, &c->fd); + + ssl_set_dh_param_ctx(ssl_ctx, &ssl->dhm_ctx); + ssl_set_ciphersuites(ssl_ctx, ssl->ciphersuites); + + if (ssl->builtin_session_cache == NGX_SSL_NONE_SCACHE) { + ssl_set_session_cache(ssl_ctx, + ngx_polarssl_get_cache, NULL, + ngx_polarssl_set_cache, NULL); + } + + if (ssl->builtin_session_cache != NGX_SSL_NO_SCACHE) { + cache = ssl->cache_shm_zone->data; + cache->ttl = ssl->cache_ttl; + + ssl_set_session_cache(ssl_ctx, + ngx_polarssl_get_cache, ssl->cache_shm_zone, + ngx_polarssl_set_cache, ssl->cache_shm_zone); + } + + /* All done, the connection is good to go now */ + + sc->connection = ssl_ctx; + c->ssl = sc; + + return NGX_OK; +} + +ngx_int_t +ngx_ssl_handshake(ngx_connection_t *c) +{ + int sslerr; + + sslerr = ssl_handshake(c->ssl->connection); + + if (sslerr == 0) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + return NGX_ERROR; + } + + c->ssl->handshaked = 1; + + c->recv = ngx_ssl_recv; + c->send = ngx_ssl_write; + c->recv_chain = ngx_ssl_recv_chain; + c->send_chain = ngx_ssl_send_chain; + + /* + * Versions of PolarSSL this is developed against are not vulnerable + * to CVE-2009-3555, leave renegotiaton as is. + */ + + return NGX_OK; + } + + if (sslerr == POLARSSL_ERR_NET_WANT_READ) { + c->read->ready = 0; + c->read->handler = ngx_ssl_handshake_handler; + c->write->handler = ngx_ssl_handshake_handler; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_AGAIN; + } + + if (sslerr == POLARSSL_ERR_NET_WANT_WRITE) { + c->write->ready = 0; + c->read->handler = ngx_ssl_handshake_handler; + c->write->handler = ngx_ssl_handshake_handler; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_AGAIN; + } + + c->ssl->no_send_shutdown = 1; + c->read->eof = 1; + + if (sslerr == POLARSSL_ERR_SSL_CONN_EOF) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "peer closed connection in SSL handshake"); + return NGX_ERROR; + } + + c->read->error = 1; + + ngx_polarssl_error(NGX_LOG_ERR, c->log, 0, sslerr, "ssl_handshake() failed"); + + return NGX_ERROR; +} + +static void +ngx_ssl_handshake_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + + c = ev->data; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL handshake handler: %d", ev->write); + + if (ev->timedout) { + c->ssl->handler(c); + return; + } + + if (ngx_ssl_handshake(c) == NGX_AGAIN) { + return; + } + + c->ssl->handler(c); +} + +ssize_t +ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size) +{ + int n, bytes; + + if (c->ssl->last == NGX_ERROR) { + c->read->error = 1; + return NGX_ERROR; + } + + if (c->ssl->last == NGX_DONE) { + c->read->ready = 0; + c->read->eof = 1; + return 0; + } + + bytes = 0; + + for ( ;; ) { + + n = ssl_read(c->ssl->connection, buf, size); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "ssl_read: %d", n); + + if (n > 0) { + bytes += n; + } + + c->ssl->last = ngx_ssl_handle_recv(c, n); + + if (c->ssl->last == NGX_OK) { + size -= n; + + if (size == 0) { + return bytes; + } + + buf += n; + + continue; + } + + if (bytes) { + return bytes; + } + + switch (c->ssl->last) { + + case NGX_DONE: + c->read->ready = 0; + c->read->eof = 1; + return 0; + + case NGX_ERROR: + c->read->error = 1; + + /* fall through */ + + case NGX_AGAIN: + return c->ssl->last; + } + } +} + +static ngx_int_t +ngx_ssl_handle_recv(ngx_connection_t *c, int n) +{ + if (n > 0) { + if (c->ssl->saved_write_handler) { + c->write->handler = c->ssl->saved_write_handler; + c->ssl->saved_write_handler = NULL; + c->write->ready = 1; + + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + return NGX_ERROR; + } + + ngx_post_event(c->write, &ngx_posted_events); + } + + return NGX_OK; + } + + if (n == POLARSSL_ERR_NET_WANT_READ) { + c->read->ready = 0; + return NGX_AGAIN; + } + + if (n == POLARSSL_ERR_NET_WANT_WRITE) { + c->write->ready = 0; + + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + return NGX_ERROR; + } + + /* + * we do not set the timer because there is already the read event timer + */ + + if (c->ssl->saved_write_handler == NULL) { + c->ssl->saved_write_handler = c->write->handler; + c->write->handler = ngx_ssl_write_handler; + } + + return NGX_AGAIN; + } + + c->ssl->no_send_shutdown = 1; + + if (n == 0 || n == POLARSSL_ERR_SSL_CONN_EOF || + n == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "peer shutdown SSL cleanly"); + return NGX_DONE; + } + + ngx_polarssl_error(NGX_LOG_ERR, c->log, 0, n, "ssl_read() failed %d ", n); + + return NGX_ERROR; +} + +static void +ngx_ssl_write_handler(ngx_event_t *wev) +{ + ngx_connection_t *c; + + c = wev->data; + + c->read->handler(c->read); +} + +ssize_t +ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) +{ + int n; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size); + + n = ssl_write(c->ssl->connection, data, size); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "ssl_write: %d", n); + + if (n > 0) { + + if (c->ssl->saved_read_handler) { + + c->read->handler = c->ssl->saved_read_handler; + c->ssl->saved_read_handler = NULL; + c->read->ready = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + ngx_post_event(c->read, &ngx_posted_events); + } + + return n; + } + + if (n == POLARSSL_ERR_NET_WANT_WRITE) { + c->write->ready = 0; + return NGX_AGAIN; + } + + if (n == POLARSSL_ERR_NET_WANT_READ) { + + /* FIXME: Should this actually log? It's handled fine. */ + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "peer started SSL renegotiation"); + + c->read->ready = 0; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + /* + * we do not set the timer because there is already + * the write event timer + */ + + if (c->ssl->saved_read_handler == NULL) { + c->ssl->saved_read_handler = c->read->handler; + c->read->handler = ngx_ssl_read_handler; + } + + return NGX_AGAIN; + } + + c->ssl->no_send_shutdown = 1; + c->write->error = 1; + + ngx_polarssl_error(NGX_LOG_ERR, c->log, 0, n, "ssl_write() failed"); + + return NGX_ERROR; +} + +static void +ngx_ssl_read_handler(ngx_event_t *rev) +{ + ngx_connection_t *c; + + c = rev->data; + + c->write->handler(c->write); +} + +ssize_t +ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl) +{ + u_char *last; + ssize_t n, bytes; + ngx_buf_t *b; + + bytes = 0; + + b = cl->buf; + last = b->last; + + for ( ;; ) { + + n = ngx_ssl_recv(c, last, b->end - last); + + if (n > 0) { + last += n; + bytes += n; + + if (last == b->end) { + cl = cl->next; + + if (cl == NULL) { + return bytes; + } + + b = cl->buf; + last = b->last; + } + + continue; + } + + if (bytes) { + if (n == 0 || n == NGX_ERROR) { + c->read->ready = 1; + } + + return bytes; + } + + return n; + } +} + +ngx_chain_t * +ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) +{ + int n; + ngx_uint_t flush; + ssize_t send, size; + ngx_buf_t *buf; + + if (!c->ssl->buffer) { + + while (in) { + if (ngx_buf_special(in->buf)) { + in = in->next; + continue; + } + + n = ngx_ssl_write(c, in->buf->pos, in->buf->last - in->buf->pos); + + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (n == NGX_AGAIN) { + return in; + } + + in->buf->pos += n; + c->sent += n; + + if (in->buf->pos == in->buf->last) { + in = in->next; + } + } + + return in; + } + + /* the maximum limit size is the maximum int32_t value - the page size */ + + if (limit == 0 || limit > (off_t) (NGX_MAX_INT32_VALUE - ngx_pagesize)) { + limit = NGX_MAX_INT32_VALUE - ngx_pagesize; + } + + buf = c->ssl->buf; + + if (buf == NULL) { + buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE); + if (buf == NULL) { + return NGX_CHAIN_ERROR; + } + + c->ssl->buf = buf; + } + + send = buf->last - buf->pos; + flush = (in == NULL) ? 1 : buf->flush; + + for ( ;; ) { + + while (in && buf->last < buf->end && send < limit) { + if (in->buf->last_buf || in->buf->flush) { + flush = 1; + } + + if (ngx_buf_special(in->buf)) { + in = in->next; + continue; + } + + size = in->buf->last - in->buf->pos; + + if (size > buf->end - buf->last) { + size = buf->end - buf->last; + } + + if (send + size > limit) { + size = (ssize_t) (limit - send); + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL buf copy: %d", size); + + ngx_memcpy(buf->last, in->buf->pos, size); + + buf->last += size; + in->buf->pos += size; + send += size; + + if (in->buf->pos == in->buf->last) { + in = in->next; + } + } + + if (!flush && send < limit && buf->last < buf->end) { + break; + } + + size = buf->last - buf->pos; + + if (size == 0) { + buf->flush = 0; + c->buffered &= ~NGX_SSL_BUFFERED; + return in; + } + + n = ngx_ssl_write(c, buf->pos, size); + + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (n == NGX_AGAIN) { + break; + } + + buf->pos += n; + c->sent += n; + + if (n < size) { + break; + } + + flush = 0; + + buf->pos = buf->start; + buf->last = buf->start; + + if (in == NULL || send == limit) { + break; + } + } + + buf->flush = flush; + + if (buf->pos < buf->last) { + c->buffered |= NGX_SSL_BUFFERED; + + } else { + c->buffered &= ~NGX_SSL_BUFFERED; + } + + return in; +} + +void +ngx_ssl_free_buffer(ngx_connection_t *c) +{ + if (c->ssl->buf && c->ssl->buf->start) { + if (ngx_pfree(c->pool, c->ssl->buf->start) == NGX_OK) { + c->ssl->buf->start = NULL; + } + } +} + +static void ngx_cdecl +ngx_polarssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, int sslerr, + char *fmt, ...) +{ + va_list args; + u_char *p, *last; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + last = errstr + NGX_MAX_CONF_ERRSTR; + + va_start(args, fmt); + p = ngx_vslprintf(errstr, last - 1, fmt, args); + va_end(args); + + p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p); + error_strerror(sslerr, (char *) p, last - p); + + ngx_log_error(level, log, err, "%s", errstr); + +} + +void ngx_cdecl +ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...) +{ + va_list args; + u_char *p, *last; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + last = errstr + NGX_MAX_CONF_ERRSTR; + + va_start(args, fmt); + p = ngx_vslprintf(errstr, last - 1, fmt, args); + va_end(args); + + /* + * PolarSSL does not have an error queue so it's not possible to access the + * last error. This doesn't really matter since this routine is called from + * all of 2 places outside of the SSL event module, both locations which are + * on SSL_CTX_set_cipher_list failure, and we implement our own logging for + * that anyway. + */ + + ngx_log_error(level, log, err, "%s", errstr); +} + +ngx_int_t +ngx_ssl_shutdown(ngx_connection_t *c) +{ + int sslerr; + + if (c->timedout || c->ssl->no_send_shutdown || c->ssl->no_wait_shutdown) { + ssl_free(c->ssl->connection); + c->ssl = NULL; + + return NGX_OK; + } + + sslerr = ssl_close_notify(c->ssl->connection); + + if (sslerr == 0 || sslerr == POLARSSL_ERR_SSL_CONN_EOF) { + ssl_free(c->ssl->connection); + c->ssl = NULL; + + return NGX_OK; + } + + if (sslerr == POLARSSL_ERR_NET_WANT_READ || + sslerr == POLARSSL_ERR_NET_WANT_WRITE) { + c->read->handler = ngx_ssl_shutdown_handler; + c->write->handler = ngx_ssl_shutdown_handler; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + return NGX_ERROR; + } + + if (sslerr == POLARSSL_ERR_NET_WANT_READ) { + ngx_add_timer(c->read, 300000); + } + + return NGX_AGAIN; + } + + ngx_polarssl_error(NGX_LOG_ERR, c->log, 0, sslerr, + "ssl_close_notify() failed"); + + ssl_free(c->ssl->connection); + c->ssl = NULL; + + return NGX_ERROR; +} + +static void +ngx_ssl_shutdown_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_connection_handler_pt handler; + + c = ev->data; + handler = c->ssl->handler; + + if (ev->timedout) { + c->timedout = 1; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "SSL shutdown handler"); + + if (ngx_ssl_shutdown(c) == NGX_AGAIN) { + return; + } + + handler(c); +} + +void +ngx_ssl_cleanup_ctx(void *data) +{ + ngx_ssl_t *ssl = data; + + if (ssl->ciphersuites != NULL) { + ngx_free(ssl->ciphersuites); + } + + dhm_free(&ssl->dhm_ctx); + if (ssl->have_own_cert) { + x509_free(&ssl->own_cert); + rsa_free(&ssl->own_key); + } + if (ssl->have_ca_cert) { + x509_free(&ssl->ca_cert); + } + if (ssl->have_ca_crl) { + x509_crl_free(&ssl->ca_crl); + } +} + +static int +ngx_polarssl_rng(void *data, unsigned char *output, size_t output_len) +{ + int rval; + +#if (NGX_THREADS) + ngx_mutex_lock(ngx_ctr_drbg_mutex); +#endif + + rval = ctr_drbg_random(data, output, output_len); + +#if (NGX_THREADS) + ngx_mutex_unlock(ngx_ctr_drbg_mutex); +#endif + + return rval; +} + +static void +ngx_polarssl_exit(ngx_cycle_t *cycle) +{ +#if (NGX_THREADS) + ngx_mutex_destroy(ngx_ctr_drbg_mutex); +#endif +} + +static int +ngx_polarssl_cipher_in_list(const int id, const int *ciphersuites) +{ + int i; + + for (i = 0; ciphersuites[i] != 0; i++) { + if (id == ciphersuites[i]) { + return 1; + } + } + + return 0; +} + +int +SSL_CTX_set_cipher_list(void *ctx, const char *ciphers) +{ + static const char ngx_default_ciphers[] = "HIGH:!aNULL:!MD5"; + const int *supported_ciphersuites; + char cipher_name[POLARSSL_SSL_CIPHER_MAX_LENGTH]; + ngx_ssl_t *ssl = ctx; + const char *c, *end, *sep; + int i, idx, cipher_id; + + /* + * OpenSSL format cipher lists are somewhat nonsensical as the options + * available under PolarSSL are somewhat more limited (most of the things a + * user would chose to disable are flat out unsupported). + * + * Till someone can provide a really good reason otherwise, supporting the + * nginx default (HIGH:!aNULL:!MD5) and allowing the user to pass in a + * specific list should be sufficient. + * + * Note: We mimick the OpenSSL behavior of ignoring unknown entries, + * mostly because the modules that call this don't bail out even if 0 + * is returned (total failure to configure ciphersuites should be + * a fatal error at config time). + */ + + supported_ciphersuites = ssl_list_ciphersuites(); + for (i = 0; supported_ciphersuites[i] != 0; i++); + + ssl->ciphersuites = ngx_alloc((i + 1) * sizeof(int), ssl->log); + if (ssl->ciphersuites == NULL) { + return 0; + } + + if (ngx_strcmp(ciphers, ngx_default_ciphers) == 0) { + + /* + * Special case for the default: "HIGH:!aNULL:!MD5": + * + * Just using the list from PolarSSL while probably reasonable does + * not exclude options that are not included in "HIGH" and also will + * (as a last resort) use TLS_RSA_RC4_128_MD5. + */ + + for (i = 0, idx = 0; supported_ciphersuites[idx] != 0; idx++) { + + switch (supported_ciphersuites[idx]) { + /* aNULL ciphers - Never enabled by default, listed for clarity */ + case TLS_RSA_WITH_NULL_MD5: + case TLS_RSA_WITH_NULL_SHA: + case TLS_RSA_WITH_NULL_SHA256: + + /* MD5 ciphers */ + case TLS_RSA_WITH_RC4_128_MD5: + + /* Weak ciphers */ + case TLS_RSA_WITH_DES_CBC_SHA: + case TLS_DHE_RSA_WITH_DES_CBC_SHA: + case TLS_RSA_WITH_3DES_EDE_CBC_SHA: /* Key size < 128 */ + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: /* Key size < 128 */ + continue; + break; + } + + ssl->ciphersuites[i] = supported_ciphersuites[idx]; + i++; + } + + ssl->ciphersuites[i] = 0; + + return (i != 0); + } + + /* Tokenize the list of ciphers */ + + c = ciphers; + i = 0; + end = ciphers + ngx_strlen(ciphers); + for (;;) { + + ssl->ciphersuites[i] = 0; + + sep = ngx_strchr(c, ':'); + if (sep == NULL) { + sep = end; + } + + /* FIXME: This is probably somewhat cryptic */ + + if (sep - c > POLARSSL_SSL_CIPHER_MAX_LENGTH) { + ngx_log_error(NGX_LOG_EMERG, ssl->log, 0, + "Out of buffer space when parsing cipher list: %s", + ciphers); + goto skip; + } + + ngx_memcpy(cipher_name, c, sep - c); + cipher_name[sep - c] = '\0'; + + cipher_id = ssl_get_ciphersuite_id(cipher_name); + if (cipher_id == 0) { + ngx_log_error(NGX_LOG_EMERG, ssl->log, 0, + "Unknown cipher requsted: %s", cipher_name); + goto skip; + } + + /* + * There are certain ciphers that can be enabled but will never + * be returned in the list obtained by ssl_list_ciphersuites(). + * + * While technically a PolarSSL bug, said ciphers are those that + * no one in their right mind will ever enable, so just silently + * ignore them (Not supporting the WEAK/NULL ciphers is a feature). + * + * Additionally, ensure that each cipher is only included once. + */ + + if (ngx_polarssl_cipher_in_list(cipher_id, supported_ciphersuites) && + !ngx_polarssl_cipher_in_list(cipher_id, ssl->ciphersuites)) { + + ssl->ciphersuites[i] = cipher_id; + i++; + } + +skip: + c = sep + 1; + + if (sep == end) { + break; + } + } + + return (i != 0); +} + +long +SSL_CTX_set_options(void *ctx, long options) +{ + + /* + * The only thing that this is used for as far as I can tell is + * SSL_OP_CIPHER_SERVER_PREFERENCE which has no PolarSSL equivalent. + */ + + return 0; +} + +void +SSL_CTX_set_tmp_rsa_callback(void *ctx, + RSA *(*tmp_rsa_callback)(SSL *ssl, int is_export, int keylength)) +{ + + /* Not supported by PolarSSL, see ngx_ssl_rsa512_key_callback */ +} + +void * +SSL_get0_session(const SSL *ssl) +{ + return ssl->session; +} + +long +SSL_get_verify_result(const SSL *ssl) +{ + int rval = ssl_get_verify_result(ssl); + + return (rval == 0) ? X509_V_OK : rval; +} + +X509 * +SSL_get_peer_certificate(SSL *ssl) +{ + /* + * Cast off the const, this is only used by ngx_http_request and the + * it's use case is harmless. + */ + + return (X509 *) ssl_get_peer_cert(ssl); +} + +const char * +X509_verify_cert_error_string(long n) +{ + /* + * n is a bit vector consisting of BADCERT_EXPIRED, BADCERT_REVOKED, + * BADCERT_CN_MISMATCH, BADCERT_NOT_TRUSTED. + */ + + switch (n) { + case BADCERT_EXPIRED: + return "Certificate expired"; + case BADCERT_REVOKED: + return "Certificate revoked"; + case BADCERT_CN_MISMATCH: + return "Certificate CN mismatch"; + case BADCERT_NOT_TRUSTED: + return "Certificate not trusted"; + + case BADCERT_EXPIRED | BADCERT_REVOKED: + return "Certificate expired/revoked"; + case BADCERT_EXPIRED | BADCERT_CN_MISMATCH: + return "Certificate expired/CN mismatch"; + case BADCERT_EXPIRED | BADCERT_NOT_TRUSTED: + return "Certificate expired/not trusted"; + case BADCERT_REVOKED | BADCERT_CN_MISMATCH: + return "Certificate revoked/CN mismatch"; + case BADCERT_REVOKED | BADCERT_NOT_TRUSTED: + return "Certificate revoked/not trusted"; + case BADCERT_CN_MISMATCH | BADCERT_NOT_TRUSTED: + return "Certificate CN mismatch/not trusted"; + + case BADCERT_EXPIRED | BADCERT_REVOKED | BADCERT_CN_MISMATCH: + return "Certificate expired/revoked/CN mismatch"; + case BADCERT_EXPIRED | BADCERT_REVOKED | BADCERT_NOT_TRUSTED: + return "Certificate expired/revoked/not trusted"; + case BADCERT_EXPIRED | BADCERT_CN_MISMATCH | BADCERT_NOT_TRUSTED: + return "Certificate expired/CN mismatch/not trusted"; + case BADCERT_REVOKED | BADCERT_CN_MISMATCH | BADCERT_NOT_TRUSTED: + return "Certificate revoked/CN mismatch/not trusted"; + + case BADCERT_EXPIRED | BADCERT_REVOKED | BADCERT_CN_MISMATCH | + BADCERT_NOT_TRUSTED: + return "Certificate expired/revoked/CN mismatch/not trusted"; + } + + return NULL; +} + +void +X509_free(X509 *cert) +{ + /* + * Don't need to free anything, we aren't OpenSSL, and the only way a + * consumer can get a x509_cert is via the SSL_get_peer_certificate + * compatibility wrapper which returns a reference. + */ +} + diff -uNr nginx-1.3.12/src/event/ngx_event_polarssl.h nginx-1.3.12-polarssl/src/event/ngx_event_polarssl.h --- nginx-1.3.12/src/event/ngx_event_polarssl.h 1969-12-31 16:00:00.000000000 -0800 +++ nginx-1.3.12-polarssl/src/event/ngx_event_polarssl.h 2013-02-16 22:53:33.000000000 -0800 @@ -0,0 +1,206 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + * Copyright (C) Yawning Angel <yawning at schwanenlied dot me> + */ + +#ifndef _NGX_EVENT_POLARSSL_H_INCLUDED_ +#define _NGX_EVENT_POLARSSL_H_INCLUDED_ + +#include <ngx_config.h> +#include <ngx_core.h> + +#include "polarssl/config.h" + +#include "polarssl/base64.h" +#include "polarssl/entropy.h" +#include "polarssl/ctr_drbg.h" +#include "polarssl/net.h" +#include "polarssl/ssl.h" +#include "polarssl/certs.h" +#include "polarssl/x509.h" +#include "polarssl/error.h" + +#define NGX_SSL_NAME "PolarSSL" + +#define ngx_ssl_session_t ssl_session +#define ngx_ssl_conn_t ssl_context + +#define RSA rsa_context +#define SSL ssl_context + +typedef struct { + ngx_log_t *log; + void *data; + + ssize_t builtin_session_cache; + ngx_shm_zone_t *cache_shm_zone; + time_t cache_ttl; + + ngx_uint_t minor_min; + ngx_uint_t minor_max; + + int *ciphersuites; + dhm_context dhm_ctx; + x509_cert own_cert; + rsa_context own_key; + x509_cert ca_cert; + x509_crl ca_crl; + + unsigned have_own_cert:1; + unsigned have_ca_cert:1; + unsigned have_ca_crl:1; + + /* + * HACK: ngx_http_ssl_module expects to be able to get at the OpenSSL + * ctx. Eventually this should be better abstracted so this is not + * needed. + */ + void *ctx; +} ngx_ssl_t; + +typedef struct { + ngx_ssl_conn_t *connection; + + ngx_int_t last; + ngx_buf_t *buf; + + ngx_connection_handler_pt handler; + + ngx_event_handler_pt saved_read_handler; + ngx_event_handler_pt saved_write_handler; + + unsigned handshaked:1; + unsigned buffer:1; + unsigned no_send_shutdown:1; + unsigned no_wait_shutdown:1; +} ngx_ssl_connection_t; + +typedef struct ngx_ssl_sess_id_s ngx_ssl_sess_id_t; + +struct ngx_ssl_sess_id_s { + ngx_rbtree_node_t node; + ngx_queue_t queue; + ngx_ssl_session_t *session; +}; + +typedef struct { + ngx_rbtree_t session_rbtree; + ngx_rbtree_node_t sentinel; + ngx_queue_t expire_queue; + time_t ttl; +} ngx_ssl_session_cache_t; + + +#define NGX_SSL_NO_SCACHE -2 +#define NGX_SSL_NONE_SCACHE -3 +#define NGX_SSL_NO_BUILTIN_SCACHE -4 +#define NGX_SSL_DFLT_BUILTIN_SCACHE -5 + +#define NGX_SSL_SSLv2 0x0002 +#define NGX_SSL_SSLv3 0x0004 +#define NGX_SSL_TLSv1 0x0008 +#define NGX_SSL_TLSv1_1 0x0010 +#define NGX_SSL_TLSv1_2 0x0020 + +#define NGX_SSL_BUFFER 1 +#define NGX_SSL_CLIENT 2 + +#define NGX_SSL_BUFSIZE 16384 + + +ngx_int_t ngx_ssl_init(ngx_log_t *log); +ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data); + +ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_str_t *cert, ngx_str_t *key); +ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_str_t *cert, ngx_int_t depth); +ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_str_t *cert, ngx_int_t depth); +ngx_int_t ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl); +ngx_int_t ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify); +ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_resolver_t *resolver, ngx_msec_t resolver_timeout); +RSA *ngx_ssl_rsa512_key_callback(SSL *ssl, int is_export, int key_length); +ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file); +ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name); + +ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, + ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t + timeout); +ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data); +void ngx_ssl_remove_cached_session(ngx_ssl_t *ssl, ngx_ssl_session_t *sess); +ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session); +ngx_ssl_session_t *ngx_ssl_get_session(ngx_connection_t *c); +void ngx_ssl_free_session(ngx_ssl_session_t *session); +/* ngx_connection_t *ngx_ssl_get_connection(ngx_ssl_conn_t *ssl_conn); */ + +ngx_int_t ngx_ssl_verify_error_optional(int n); + +ngx_int_t ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); +ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); +ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); +ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); +ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); +ngx_int_t ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); +ngx_int_t ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); +ngx_int_t ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); +ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); + +ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, + ngx_uint_t flags); +ngx_int_t ngx_ssl_handshake(ngx_connection_t *c); +ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size); +ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size); +ssize_t ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl); +ngx_chain_t *ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); +void ngx_ssl_free_buffer(ngx_connection_t *c); +ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c); +void ngx_cdecl ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, + char *fmt, ...); +void ngx_ssl_cleanup_ctx(void *data); + + +/* + * The various modules aren't actually SSL implementation agnostic, + * so provide wrappers till they are changed to do the right thing. + * + * In an ideal world, this section shouldn't grow any further. + * + * Other things that could be abstracted better are: + * * ngx_md5 and ngx_sha1 currently rely on polarssl/openssl.h + * * ngx_ssl_rsa512_key_callback likewise uses definitions from + * polarssl/openssl.h + * * The SNI support in ngx_http_ssl_module/ngx_http_request needs + * to be rewritten since it's too painful to try to provide wrappers. + */ + +#define X509 x509_cert +#define X509_V_OK 0 +#define SSL_OP_CIPHER_SERVER_PREFERENCE 0x1 + +int SSL_CTX_set_cipher_list(void *ctx, const char *ciphers); +long SSL_CTX_set_options(void *ctx, long options); +void SSL_CTX_set_tmp_rsa_callback(void *ctx, + RSA *(*tmp_rsa_callback)(SSL *ssl, int is_export, int keylength)); +void *SSL_get0_session(const SSL *ssl); +long SSL_get_verify_result(const SSL *ssl); + +X509 *SSL_get_peer_certificate(SSL *ssl); +const char *X509_verify_cert_error_string(long n); +void X509_free(X509 *cert); + +#endif /* _NGX_EVENT_POLARSSL_H_INCLUDED_ */ diff -uNr nginx-1.3.12/src/http/ngx_http_upstream_round_robin.c nginx-1.3.12-polarssl/src/http/ngx_http_upstream_round_robin.c --- nginx-1.3.12/src/http/ngx_http_upstream_round_robin.c 2013-01-10 04:58:55.000000000 -0800 +++ nginx-1.3.12-polarssl/src/http/ngx_http_upstream_round_robin.c 2013-02-14 04:34:52.000000000 -0800 @@ -658,9 +658,11 @@ rc = ngx_ssl_set_session(pc->connection, ssl_session); +#ifdef NGX_OPENSSL ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, "set session: %p:%d", ssl_session, ssl_session ? ssl_session->references : 0); +#endif /* ngx_unlock_mutex(rrp->peers->mutex); */ @@ -683,8 +685,10 @@ return; } +#ifdef NGX_OPENSSL ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, "save session: %p:%d", ssl_session, ssl_session->references); +#endif peer = &rrp->peers->peer[rrp->current]; @@ -698,9 +702,11 @@ if (old_ssl_session) { +#ifdef NGX_OPENSSL ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, "old session: %p:%d", old_ssl_session, old_ssl_session->references); +#endif /* TODO: may block */