@@ -321,9 +321,14 @@ int ssl3_accept(SSL *s) | |||||
case SSL3_ST_SR_CLNT_HELLO_A: | case SSL3_ST_SR_CLNT_HELLO_A: | ||||
case SSL3_ST_SR_CLNT_HELLO_B: | case SSL3_ST_SR_CLNT_HELLO_B: | ||||
case SSL3_ST_SR_CLNT_HELLO_C: | case SSL3_ST_SR_CLNT_HELLO_C: | ||||
case SSL3_ST_SR_CLNT_HELLO_D: | |||||
s->shutdown=0; | s->shutdown=0; | ||||
ret=ssl3_get_client_hello(s); | 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; | if (ret <= 0) goto end; | ||||
s->renegotiate = 2; | s->renegotiate = 2; | ||||
s->state=SSL3_ST_SW_SRVR_HELLO_A; | 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->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; | d=p=(unsigned char *)s->init_msg; | ||||
/* use version from inside client hello, not from record header | /* 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) | else if (i == -1) | ||||
goto err; | 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)) | if (!ssl_get_new_session(s,1)) | ||||
@@ -1337,7 +1358,7 @@ f_err: | |||||
} | } | ||||
err: | err: | ||||
if (ciphers != NULL) sk_SSL_CIPHER_free(ciphers); | if (ciphers != NULL) sk_SSL_CIPHER_free(ciphers); | ||||
return ret < 0 ? -1 : ret; | |||||
return ret; | |||||
} | } | ||||
int ssl3_send_server_hello(SSL *s) | int ssl3_send_server_hello(SSL *s) | ||||
@@ -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_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)); | 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_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_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_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)); | 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_WRITING 2 | ||||
#define SSL_READING 3 | #define SSL_READING 3 | ||||
#define SSL_X509_LOOKUP 4 | #define SSL_X509_LOOKUP 4 | ||||
#define SSL_PENDING_SESSION 7 | |||||
/* These will only be used when doing non-blocking IO */ | /* These will only be used when doing non-blocking IO */ | ||||
#define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING) | #define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING) | ||||
#define SSL_want_read(s) (SSL_want(s) == SSL_READING) | #define SSL_want_read(s) (SSL_want(s) == SSL_READING) | ||||
#define SSL_want_write(s) (SSL_want(s) == SSL_WRITING) | #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_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_READ_MAC_STREAM 1 | ||||
#define SSL_MAC_FLAG_WRITE_MAC_STREAM 2 | #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_ZERO_RETURN 6 | ||||
#define SSL_ERROR_WANT_CONNECT 7 | #define SSL_ERROR_WANT_CONNECT 7 | ||||
#define SSL_ERROR_WANT_ACCEPT 8 | #define SSL_ERROR_WANT_ACCEPT 8 | ||||
#define SSL_ERROR_PENDING_SESSION 11 | |||||
#define SSL_CTRL_NEED_TMP_RSA 1 | #define SSL_CTRL_NEED_TMP_RSA 1 | ||||
#define SSL_CTRL_SET_TMP_RSA 2 | #define SSL_CTRL_SET_TMP_RSA 2 | ||||
@@ -2707,6 +2707,9 @@ int SSL_get_error(const SSL *s,int i) | |||||
return(SSL_ERROR_SSL); | return(SSL_ERROR_SSL); | ||||
} | } | ||||
if ((i < 0) && SSL_want_session(s)) | |||||
return(SSL_ERROR_PENDING_SESSION); | |||||
if ((i < 0) && SSL_want_read(s)) | if ((i < 0) && SSL_want_read(s)) | ||||
{ | { | ||||
bio=SSL_get_rbio(s); | bio=SSL_get_rbio(s); | ||||
@@ -474,6 +474,8 @@ | |||||
#define CERT_PRIVATE_KEY 2 | #define CERT_PRIVATE_KEY 2 | ||||
*/ | */ | ||||
#define PENDING_SESSION -10000 | |||||
#ifndef OPENSSL_NO_EC | #ifndef OPENSSL_NO_EC | ||||
/* From ECC-TLS draft, used in encoding the curve type in | /* From ECC-TLS draft, used in encoding the curve type in | ||||
* ECParameters | * ECParameters | ||||
@@ -143,10 +143,20 @@ | |||||
#include "ssl_locl.h" | #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_remove(SSL_CTX *ctx, SSL_SESSION *s); | ||||
static void SSL_SESSION_list_add(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); | 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) | SSL_SESSION *SSL_get_session(const SSL *ssl) | ||||
/* aka SSL_get0_session; gets 0 objects, just returns a copy of the pointer */ | /* 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=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++; | s->session_ctx->stats.sess_cb_hit++; | ||||
/* Increment reference count now if the session callback | /* Increment reference count now if the session callback | ||||
@@ -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_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_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_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_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_B: str="SSLv3 write hello request B"; break; | ||||
case SSL3_ST_SW_HELLO_REQ_C: str="SSLv3 write hello request C"; 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_A: str="3RCH_A"; break; | ||||
case SSL3_ST_SR_CLNT_HELLO_B: str="3RCH_B"; 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_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_A: str="3WSH_A"; break; | ||||
case SSL3_ST_SW_SRVR_HELLO_B: str="3WSH_B"; break; | case SSL3_ST_SW_SRVR_HELLO_B: str="3WSH_B"; break; | ||||
case SSL3_ST_SW_CERT_A: str="3WSC_A"; break; | case SSL3_ST_SW_CERT_A: str="3WSC_A"; break; | ||||