From b2ce05839b435bb21fe70acd0fc00abfa918f41e Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Fri, 20 Jun 2014 12:00:00 -0700 Subject: [PATCH] Add support for asynchronous session lookup. --- ssl/s3_srvr.c | 43 ++++++++++++++++++++++++++++++++----------- ssl/ssl.h | 8 ++++++++ ssl/ssl_lib.c | 3 +++ ssl/ssl_locl.h | 2 ++ ssl/ssl_sess.c | 17 +++++++++++++++++ ssl/ssl_stat.c | 2 ++ 6 files changed, 64 insertions(+), 11 deletions(-) diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 3a39cfd0..d8cb4748 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -321,9 +321,14 @@ 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; s->renegotiate = 2; s->state=SSL3_ST_SW_SRVR_HELLO_A; @@ -887,16 +892,27 @@ int ssl3_get_client_hello(SSL *s) { 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 (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; + } - if (!ok) return((int)n); - s->first_packet=0; d=p=(unsigned char *)s->init_msg; /* use version from inside client hello, not from record header @@ -967,6 +983,11 @@ int ssl3_get_client_hello(SSL *s) } else if (i == -1) goto err; + else if (i == PENDING_SESSION) + { + ret = PENDING_SESSION; + goto err; + } else /* i == 0 */ { if (!ssl_get_new_session(s,1)) @@ -1337,7 +1358,7 @@ f_err: } err: if (ciphers != NULL) sk_SSL_CIPHER_free(ciphers); - return ret < 0 ? -1 : ret; + return ret; } int ssl3_send_server_hello(SSL *s) diff --git a/ssl/ssl.h b/ssl/ssl.h index e5aa03a6..6b7ffe56 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -1146,6 +1146,11 @@ void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx, void (*remove_session_cb)(struct s void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))(struct ssl_ctx_st *ctx, SSL_SESSION *sess); void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx, SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl, unsigned char *data,int len,int *copy)); 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)); void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl,int type,int val); void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey)); @@ -1251,12 +1256,14 @@ int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned short ext_type, #define SSL_WRITING 2 #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 @@ -1666,6 +1673,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 diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index c5366007..c08dbb3a 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -2707,6 +2707,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); diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index cbfa1725..91c8c1c9 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -474,6 +474,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 --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index 9054fd11..5d8b054c 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -143,10 +143,20 @@ #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 */ { @@ -500,6 +510,13 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len, if ((ret=s->session_ctx->get_session_cb(s,session_id,len,©))) { + 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++; /* Increment reference count now if the session callback diff --git a/ssl/ssl_stat.c b/ssl/ssl_stat.c index c8851ff5..6d0c7416 100644 --- a/ssl/ssl_stat.c +++ b/ssl/ssl_stat.c @@ -149,6 +149,7 @@ case SSL3_ST_SW_FLUSH: str="SSLv3 flush data"; break; case SSL3_ST_SR_CLNT_HELLO_A: str="SSLv3 read client hello A"; break; case SSL3_ST_SR_CLNT_HELLO_B: str="SSLv3 read client hello B"; break; 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_SW_HELLO_REQ_A: str="SSLv3 write hello request A"; break; case SSL3_ST_SW_HELLO_REQ_B: str="SSLv3 write hello request B"; break; case SSL3_ST_SW_HELLO_REQ_C: str="SSLv3 write hello request C"; break; @@ -268,6 +269,7 @@ case SSL3_ST_SW_HELLO_REQ_C: str="3WHR_C"; break; case SSL3_ST_SR_CLNT_HELLO_A: str="3RCH_A"; break; case SSL3_ST_SR_CLNT_HELLO_B: str="3RCH_B"; break; 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_SW_SRVR_HELLO_A: str="3WSH_A"; break; case SSL3_ST_SW_SRVR_HELLO_B: str="3WSH_B"; break; case SSL3_ST_SW_CERT_A: str="3WSC_A"; break;