提交 8876bc05 编写于 作者: B Bodo Möller

Let ssl_get_prev_session reliably work in multi-threaded settings.

上级 3550ec4f
...@@ -557,7 +557,9 @@ static int ssl3_get_client_hello(SSL *s) ...@@ -557,7 +557,9 @@ static int ssl3_get_client_hello(SSL *s)
{ /* previous session */ { /* previous session */
s->hit=1; s->hit=1;
} }
else else if (i == -1)
goto err;
else /* i == 0 */
{ {
if (!ssl_get_new_session(s,1)) if (!ssl_get_new_session(s,1))
goto err; goto err;
......
...@@ -188,18 +188,21 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len) ...@@ -188,18 +188,21 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len)
/* This is used only by servers. */ /* This is used only by servers. */
SSL_SESSION *ret=NULL,data; SSL_SESSION *ret=NULL,data;
int fatal = 0;
/* conn_init();*/ /* conn_init();*/
data.ssl_version=s->version; data.ssl_version=s->version;
data.session_id_length=len; data.session_id_length=len;
if (len > SSL_MAX_SSL_SESSION_ID_LENGTH) if (len > SSL_MAX_SSL_SESSION_ID_LENGTH)
return(0); goto err;
memcpy(data.session_id,session_id,len); memcpy(data.session_id,session_id,len);
if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
{ {
CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
ret=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,(char *)&data); ret=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,(char *)&data);
/* don't allow other threads to steal it: */
CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION);
CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
} }
...@@ -215,27 +218,52 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len) ...@@ -215,27 +218,52 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len)
{ {
s->ctx->stats.sess_cb_hit++; s->ctx->stats.sess_cb_hit++;
/* Increment reference count now if the session callback
* asks us to do so (note that if the session structures
* returned by the callback are shared between threads,
* it must handle the reference count itself [i.e. copy == 0],
* or things won't be thread-safe). */
if (copy)
CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION);
/* The following should not return 1, otherwise, /* The following should not return 1, otherwise,
* things are very strange */ * things are very strange */
SSL_CTX_add_session(s->ctx,ret); SSL_CTX_add_session(s->ctx,ret);
/* auto free it (decrement reference count now) */
if (!copy)
SSL_SESSION_free(ret);
} }
if (ret == NULL) return(0); if (ret == NULL)
goto err;
} }
/* Now ret is non-NULL, and we own one of its reference counts. */
if((s->verify_mode&SSL_VERIFY_PEER) if((s->verify_mode&SSL_VERIFY_PEER)
&& (!s->sid_ctx_length || ret->sid_ctx_length != s->sid_ctx_length && (!s->sid_ctx_length || ret->sid_ctx_length != s->sid_ctx_length
|| memcmp(ret->sid_ctx,s->sid_ctx,ret->sid_ctx_length))) || memcmp(ret->sid_ctx,s->sid_ctx,ret->sid_ctx_length)))
{ {
if (s->sid_ctx_length) /* We've found the session named by the client, but we don't
SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT); * want to use it in this context. */
else
/* application should have used SSL[_CTX]_set_session_id_context */ if (s->sid_ctx_length == 0)
{
/* application should have used SSL[_CTX]_set_session_id_context
* -- we could tolerate this and just pretend we never heard
* of this session, but then applications could effectively
* disable the session cache by accident without anyone noticing */
SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED); SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED);
return 0; fatal = 1;
} goto err;
}
else
{
#if 0 /* The client cannot always know when a session is not appropriate,
* so we shouldn't generate an error message. */
SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
#endif
goto err; /* treat like cache miss */
}
}
if (ret->cipher == NULL) if (ret->cipher == NULL)
{ {
...@@ -250,22 +278,25 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len) ...@@ -250,22 +278,25 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len)
else else
ret->cipher=ssl_get_cipher_by_char(s,&(buf[1])); ret->cipher=ssl_get_cipher_by_char(s,&(buf[1]));
if (ret->cipher == NULL) if (ret->cipher == NULL)
return(0); goto err;
} }
#if 0 /* This is way too late. */
/* If a thread got the session, then 'swaped', and another got /* If a thread got the session, then 'swaped', and another got
* it and then due to a time-out decided to 'Free' it we could * it and then due to a time-out decided to 'Free' it we could
* be in trouble. So I'll increment it now, then double decrement * be in trouble. So I'll increment it now, then double decrement
* later - am I speaking rubbish?. */ * later - am I speaking rubbish?. */
CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION);
#endif
if ((long)(ret->time+ret->timeout) < (long)time(NULL)) /* timeout */ if ((long)(ret->time+ret->timeout) < (long)time(NULL)) /* timeout */
{ {
s->ctx->stats.sess_timeout++; s->ctx->stats.sess_timeout++;
/* remove it from the cache */ /* remove it from the cache */
SSL_CTX_remove_session(s->ctx,ret); SSL_CTX_remove_session(s->ctx,ret);
SSL_SESSION_free(ret); /* again to actually Free it */ goto err;
return(0);
} }
s->ctx->stats.sess_hit++; s->ctx->stats.sess_hit++;
...@@ -278,6 +309,14 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len) ...@@ -278,6 +309,14 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len)
SSL_SESSION_free(s->session); SSL_SESSION_free(s->session);
s->session=ret; s->session=ret;
return(1); return(1);
err:
if (ret != NULL)
SSL_SESSION_free(ret);
if (fatal)
return -1;
else
return 0;
} }
int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册