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 */
 
