From 97901f335709e8f3b2dec1c368bba20f3894fccc Mon Sep 17 00:00:00 2001
From: "Yichun Zhang (agentzh)" <agentzh@gmail.com>
Date: Tue, 19 Jul 2016 19:26:08 -0700
Subject: [PATCH] feature: applied the ssl_pending_session.patch to the nginx
 core to support the ssl_session_fetch_by_lua* and ssl_session_store_by_lua*
 in ngx_lua.

also added an openssl patch to support yieldable callback set by
SSL_CTX_sess_set_get_cb().
---
 .../nginx-1.11.2-ssl_pending_session.patch    |  16 ++
 ...openssl-1.0.2h-sess_set_get_cb_yield.patch | 233 ++++++++++++++++++
 util/mirror-tarballs                          |   4 +
 3 files changed, 253 insertions(+)
 create mode 100644 patches/nginx-1.11.2-ssl_pending_session.patch
 create mode 100644 patches/openssl-1.0.2h-sess_set_get_cb_yield.patch

diff --git a/patches/nginx-1.11.2-ssl_pending_session.patch b/patches/nginx-1.11.2-ssl_pending_session.patch
new file mode 100644
index 0000000..7c84fe0
--- /dev/null
+++ b/patches/nginx-1.11.2-ssl_pending_session.patch
@@ -0,0 +1,16 @@
+--- nginx-1.11.2/src/event/ngx_event_openssl.c	2016-07-17 19:20:30.411137606 -0700
++++ nginx-1.11.2-patched/src/event/ngx_event_openssl.c	2016-07-19 16:53:35.539768477 -0700
+@@ -1307,7 +1307,12 @@ ngx_ssl_handshake(ngx_connection_t *c)
+     }
+ 
+ #if OPENSSL_VERSION_NUMBER >= 0x10002000L
+-    if (sslerr == SSL_ERROR_WANT_X509_LOOKUP) {
++    if (sslerr == SSL_ERROR_WANT_X509_LOOKUP
++#   ifdef SSL_ERROR_PENDING_SESSION
++        || sslerr == SSL_ERROR_PENDING_SESSION
++#   endif
++       )
++    {
+         c->read->handler = ngx_ssl_handshake_handler;
+         c->write->handler = ngx_ssl_handshake_handler;
+ 
diff --git a/patches/openssl-1.0.2h-sess_set_get_cb_yield.patch b/patches/openssl-1.0.2h-sess_set_get_cb_yield.patch
new file mode 100644
index 0000000..3a4a655
--- /dev/null
+++ b/patches/openssl-1.0.2h-sess_set_get_cb_yield.patch
@@ -0,0 +1,233 @@
+diff -urp openssl-1.0.2h/ssl/s3_srvr.c openssl-1.0.2h-patched/ssl/s3_srvr.c
+--- openssl-1.0.2h/ssl/s3_srvr.c	2016-05-03 06:44:42.000000000 -0700
++++ openssl-1.0.2h-patched/ssl/s3_srvr.c	2016-07-19 19:18:03.779159083 -0700
+@@ -358,14 +358,20 @@ int ssl3_accept(SSL *s)
+         case SSL3_ST_SR_CLNT_HELLO_A:
+         case SSL3_ST_SR_CLNT_HELLO_B:
+         case SSL3_ST_SR_CLNT_HELLO_C:
++        case SSL3_ST_SR_CLNT_HELLO_D:
+ 
+             s->shutdown = 0;
+             ret = ssl3_get_client_hello(s);
++            if (ret == PENDING_SESSION) {
++                s->state = SSL3_ST_SR_CLNT_HELLO_D;
++                s->rwstate = SSL_PENDING_SESSION;
++                goto end;
++            }
+             if (ret <= 0)
+                 goto end;
+ #ifndef OPENSSL_NO_SRP
+-            s->state = SSL3_ST_SR_CLNT_HELLO_D;
+-        case SSL3_ST_SR_CLNT_HELLO_D:
++            s->state = SSL3_ST_SR_CLNT_HELLO_E;
++        case SSL3_ST_SR_CLNT_HELLO_E:
+             {
+                 int al;
+                 if ((ret = ssl_check_srp_ext_ClientHello(s, &al)) < 0) {
+@@ -925,16 +931,25 @@ int ssl3_get_client_hello(SSL *s)
+     if (s->state == SSL3_ST_SR_CLNT_HELLO_A) {
+         s->state = SSL3_ST_SR_CLNT_HELLO_B;
+     }
+-    s->first_packet = 1;
+-    n = s->method->ssl_get_message(s,
+-                                   SSL3_ST_SR_CLNT_HELLO_B,
+-                                   SSL3_ST_SR_CLNT_HELLO_C,
+-                                   SSL3_MT_CLIENT_HELLO,
+-                                   SSL3_RT_MAX_PLAIN_LENGTH, &ok);
+-
+-    if (!ok)
+-        return ((int)n);
+-    s->first_packet = 0;
++
++    if (s->state != SSL3_ST_SR_CLNT_HELLO_D) {
++        s->first_packet = 1;
++        n = s->method->ssl_get_message(s,
++                                       SSL3_ST_SR_CLNT_HELLO_B,
++                                       SSL3_ST_SR_CLNT_HELLO_C,
++                                       SSL3_MT_CLIENT_HELLO,
++                                       SSL3_RT_MAX_PLAIN_LENGTH, &ok);
++ 
++        if (!ok)
++            return ((int)n);
++        s->first_packet = 0;
++    } else {
++        /* We have previously parsed the ClientHello message, and can't
++         * call ssl_get_message again without hashing the message into
++         * the Finished digest again. */
++        n = s->init_num;
++    }
++
+     d = p = (unsigned char *)s->init_msg;
+ 
+     /*
+@@ -1041,15 +1056,26 @@ int ssl3_get_client_hello(SSL *s)
+         if (i == 1 && s->version == s->session->ssl_version) { /* previous
+                                                                 * session */
+             s->hit = 1;
+-        } else if (i == -1)
++        } else if (i == -1) {
++            goto err;
++        } else if (i == PENDING_SESSION) {
++            ret = PENDING_SESSION;
+             goto err;
+-        else {                  /* i == 0 */
++        } else {                /* i == 0 */
+ 
+             if (!ssl_get_new_session(s, 1))
+                 goto err;
+         }
+     }
+ 
++    /*
++     * Switch to server state ClientHello C once the session lookup
++     * is finished so it can proceed with original state loop.
++     */
++    if (s->state == SSL3_ST_SR_CLNT_HELLO_D) {
++        s->state = SSL3_ST_SR_CLNT_HELLO_C;
++    }
++
+     p += j;
+ 
+     if (SSL_IS_DTLS(s)) {
+diff -urp openssl-1.0.2h/ssl/ssl3.h openssl-1.0.2h-patched/ssl/ssl3.h
+--- openssl-1.0.2h/ssl/ssl3.h	2016-05-03 06:44:42.000000000 -0700
++++ openssl-1.0.2h-patched/ssl/ssl3.h	2016-07-19 19:15:54.117778328 -0700
+@@ -698,6 +698,7 @@ typedef struct ssl3_state_st {
+ # define SSL3_ST_SR_CLNT_HELLO_B         (0x111|SSL_ST_ACCEPT)
+ # define SSL3_ST_SR_CLNT_HELLO_C         (0x112|SSL_ST_ACCEPT)
+ # define SSL3_ST_SR_CLNT_HELLO_D         (0x115|SSL_ST_ACCEPT)
++# define SSL3_ST_SR_CLNT_HELLO_E         (0x116|SSL_ST_ACCEPT)
+ /* write to client */
+ # define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A (0x113|SSL_ST_ACCEPT)
+ # define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B (0x114|SSL_ST_ACCEPT)
+diff -urp openssl-1.0.2h/ssl/ssl.h openssl-1.0.2h-patched/ssl/ssl.h
+--- openssl-1.0.2h/ssl/ssl.h	2016-05-03 06:44:42.000000000 -0700
++++ openssl-1.0.2h-patched/ssl/ssl.h	2016-07-19 19:19:44.699562938 -0700
+@@ -1243,6 +1243,13 @@ void SSL_CTX_sess_set_get_cb(SSL_CTX *ct
+ SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx)) (struct ssl_st *ssl,
+                                                        unsigned char *Data,
+                                                        int len, int *copy);
++
++/* SSL_magic_pending_session_ptr returns a magic SSL_SESSION* which indicates
++ * that the session isn't currently unavailable. SSL_get_error will then return
++ * SSL_ERROR_PENDING_SESSION and the handshake can be retried later when the
++ * lookup has completed. */
++SSL_SESSION *SSL_magic_pending_session_ptr(void);
++
+ void SSL_CTX_set_info_callback(SSL_CTX *ctx,
+                                void (*cb) (const SSL *ssl, int type,
+                                            int val));
+@@ -1408,11 +1415,14 @@ int SSL_extension_supported(unsigned int
+ # define SSL_READING     3
+ # define SSL_X509_LOOKUP 4
+ 
++# define SSL_PENDING_SESSION 7
++
+ /* These will only be used when doing non-blocking IO */
+ # define SSL_want_nothing(s)     (SSL_want(s) == SSL_NOTHING)
+ # define SSL_want_read(s)        (SSL_want(s) == SSL_READING)
+ # define SSL_want_write(s)       (SSL_want(s) == SSL_WRITING)
+ # define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_X509_LOOKUP)
++# define SSL_want_session(s)     (SSL_want(s) == SSL_PENDING_SESSION)
+ 
+ # define SSL_MAC_FLAG_READ_MAC_STREAM 1
+ # define SSL_MAC_FLAG_WRITE_MAC_STREAM 2
+@@ -1865,6 +1875,7 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
+ # define SSL_ERROR_ZERO_RETURN           6
+ # define SSL_ERROR_WANT_CONNECT          7
+ # define SSL_ERROR_WANT_ACCEPT           8
++# define SSL_ERROR_PENDING_SESSION       11
+ # define SSL_CTRL_NEED_TMP_RSA                   1
+ # define SSL_CTRL_SET_TMP_RSA                    2
+ # define SSL_CTRL_SET_TMP_DH                     3
+diff -urp openssl-1.0.2h/ssl/ssl_lib.c openssl-1.0.2h-patched/ssl/ssl_lib.c
+--- openssl-1.0.2h/ssl/ssl_lib.c	2016-05-03 06:44:42.000000000 -0700
++++ openssl-1.0.2h-patched/ssl/ssl_lib.c	2016-07-19 19:21:04.032021549 -0700
+@@ -2709,6 +2709,9 @@ int SSL_get_error(const SSL *s, int i)
+             return (SSL_ERROR_SSL);
+     }
+ 
++    if ((i < 0) && SSL_want_session(s))
++        return (SSL_ERROR_PENDING_SESSION);
++
+     if ((i < 0) && SSL_want_read(s)) {
+         bio = SSL_get_rbio(s);
+         if (BIO_should_read(bio))
+diff -urp openssl-1.0.2h/ssl/ssl_locl.h openssl-1.0.2h-patched/ssl/ssl_locl.h
+--- openssl-1.0.2h/ssl/ssl_locl.h	2016-05-03 06:44:42.000000000 -0700
++++ openssl-1.0.2h-patched/ssl/ssl_locl.h	2016-07-19 19:15:54.117778328 -0700
+@@ -518,6 +518,8 @@
+ #define CERT_PRIVATE_KEY        2
+ */
+ 
++# define PENDING_SESSION        -10000
++
+ # ifndef OPENSSL_NO_EC
+ /*
+  * From ECC-TLS draft, used in encoding the curve type in ECParameters
+diff -urp openssl-1.0.2h/ssl/ssl_sess.c openssl-1.0.2h-patched/ssl/ssl_sess.c
+--- openssl-1.0.2h/ssl/ssl_sess.c	2016-05-03 06:44:42.000000000 -0700
++++ openssl-1.0.2h-patched/ssl/ssl_sess.c	2016-07-19 19:15:54.118778298 -0700
+@@ -143,10 +143,20 @@
+ #endif
+ #include "ssl_locl.h"
+ 
++/* The address of this is a magic value, a pointer to which is returned by
++ * SSL_magic_pending_session_ptr(). It allows a session callback to indicate
++ * that it needs to asynchronously fetch session information. */
++static char g_pending_session_magic;
++
+ static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s);
+ static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s);
+ static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck);
+ 
++SSL_SESSION *SSL_magic_pending_session_ptr()
++{
++    return (SSL_SESSION*) &g_pending_session_magic;
++}
++
+ SSL_SESSION *SSL_get_session(const SSL *ssl)
+ /* aka SSL_get0_session; gets 0 objects, just returns a copy of the pointer */
+ {
+@@ -626,6 +636,12 @@ int ssl_get_prev_session(SSL *s, unsigne
+         int copy = 1;
+ 
+         if ((ret = s->session_ctx->get_session_cb(s, session_id, len, &copy))) {
++            if (ret == SSL_magic_pending_session_ptr()) {
++                /* This is a magic value which indicates that
++                 * the callback needs to unwind the stack and
++                 * figure out the session asynchronously. */
++                return PENDING_SESSION;
++            }
+             s->session_ctx->stats.sess_cb_hit++;
+ 
+             /*
+diff -urp openssl-1.0.2h/ssl/ssl_stat.c openssl-1.0.2h-patched/ssl/ssl_stat.c
+--- openssl-1.0.2h/ssl/ssl_stat.c	2016-05-03 06:44:42.000000000 -0700
++++ openssl-1.0.2h-patched/ssl/ssl_stat.c	2016-07-19 19:15:54.118778298 -0700
+@@ -353,6 +353,12 @@ const char *SSL_state_string_long(const
+     case SSL3_ST_SR_CLNT_HELLO_C:
+         str = "SSLv3 read client hello C";
+         break;
++    case SSL3_ST_SR_CLNT_HELLO_D:
++        str = "SSLv3 read client hello D";
++        break;
++    case SSL3_ST_SR_CLNT_HELLO_E:
++        str = "SSLv3 read client hello E";
++        break;
+     case SSL3_ST_SW_HELLO_REQ_A:
+         str = "SSLv3 write hello request A";
+         break;
+@@ -737,6 +743,12 @@ const char *SSL_state_string(const SSL *
+     case SSL3_ST_SR_CLNT_HELLO_C:
+         str = "3RCH_C";
+         break;
++    case SSL3_ST_SR_CLNT_HELLO_D:
++        str = "3RCH_D";
++        break;
++    case SSL3_ST_SR_CLNT_HELLO_E:
++        str = "3RCH_E";
++        break;
+     case SSL3_ST_SW_SRVR_HELLO_A:
+         str = "3WSH_A";
+         break;
diff --git a/util/mirror-tarballs b/util/mirror-tarballs
index f043759..20bf995 100755
--- a/util/mirror-tarballs
+++ b/util/mirror-tarballs
@@ -325,6 +325,10 @@ echo "$info_txt applying the ssl_cert_cb_yield.patch patch to nginx"
 patch -p1 < $root/patches/nginx-$main_ver-ssl_cert_cb_yield.patch
 echo
 
+echo "$info_txt applying the ssl_pending_session.patch patch to nginx"
+patch -p1 < $root/patches/nginx-$main_ver-ssl_pending_session.patch
+echo
+
 echo "$info_txt applying the upstream_timeout_fields patch for nginx"
 patch -p1 < $root/patches/nginx-$main_ver-upstream_timeout_fields.patch || exit 1
 echo