X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=ssl%2Fssl_sess.c;h=74ec2178a936a0cadcf62cb6e7ddbc6aababd022;hb=bb7cd4e3ebb9c1114b7fb6f6d0e4c280ef984889;hp=3872b419283db7e0057d3cbe11440a1a70ad65d7;hpb=9a193d88250a38fd4dc5094ec4b501598cd23009;p=oweals%2Fopenssl.git diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index 3872b41928..74ec2178a9 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -67,19 +67,41 @@ static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck); static int ssl_session_num=0; static STACK *ssl_session_meth=NULL; +#if 1 /* traditional SSLeay behaviour */ SSL_SESSION *SSL_get_session(SSL *ssl) { return(ssl->session); } +#else /* suggested change: increase reference counter so that a session + * can later be set in a new SSL object. + * Objections: + * -- the modified function should have a new name (or old + * applications, including s_client, leak memory); + * -- the locking seems unnecessary given that SSL structures + * usually cannot be safely shared between threads anyway. */ +SSL_SESSION *SSL_get_session(SSL *ssl) + { + SSL_SESSION *sess; + /* Need to lock this all up rather than just use CRYPTO_add so that + * somebody doesn't free ssl->session between when we check it's + * non-null and when we up the reference count. */ + CRYPTO_r_lock(CRYPTO_LOCK_SSL_SESSION); + sess = ssl->session; + if(sess) + sess->references++; + CRYPTO_r_unlock(CRYPTO_LOCK_SSL_SESSION); + return(sess); + } +#endif int SSL_SESSION_get_ex_new_index(long argl, char *argp, int (*new_func)(), int (*dup_func)(), void (*free_func)()) - { - ssl_session_num++; - return(CRYPTO_get_ex_new_index(ssl_session_num-1, + { + ssl_session_num++; + return(CRYPTO_get_ex_new_index(ssl_session_num-1, &ssl_session_meth, - argl,argp,new_func,dup_func,free_func)); - } + argl,argp,new_func,dup_func,free_func)); + } int SSL_SESSION_set_ex_data(SSL_SESSION *s, int idx, void *arg) { @@ -103,6 +125,7 @@ SSL_SESSION *SSL_SESSION_new(void) } memset(ss,0,sizeof(SSL_SESSION)); + ss->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */ ss->references=1; ss->timeout=60*5+4; /* 5 minute timeout by default */ ss->time=time(NULL); @@ -168,6 +191,8 @@ int ssl_get_new_session(SSL *s, int session) CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); if (r == NULL) break; /* else - woops a session_id match */ + /* XXX should also check external cache! + * (But the probability of a collision is negligible, anyway...) */ } } else @@ -179,6 +204,7 @@ int ssl_get_new_session(SSL *s, int session) ss->sid_ctx_length=s->sid_ctx_length; s->session=ss; ss->ssl_version=s->version; + ss->verify_result = X509_V_OK; return(1); } @@ -188,18 +214,22 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len) /* This is used only by servers. */ SSL_SESSION *ret=NULL,data; + int fatal = 0; /* conn_init();*/ data.ssl_version=s->version; data.session_id_length=len; if (len > SSL_MAX_SSL_SESSION_ID_LENGTH) - return(0); + goto err; memcpy(data.session_id,session_id,len); if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) { CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); ret=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,(char *)&data); + if (ret != NULL) + /* don't allow other threads to steal it: */ + CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); } @@ -215,27 +245,52 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len) { 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, * things are very strange */ 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) && (!s->sid_ctx_length || ret->sid_ctx_length != s->sid_ctx_length || memcmp(ret->sid_ctx,s->sid_ctx,ret->sid_ctx_length))) { - if (s->sid_ctx_length) - SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT); - else - /* application should have used SSL[_CTX]_set_session_id_context */ + /* We've found the session named by the client, but we don't + * want to use it in this 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); - 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) { @@ -250,22 +305,25 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len) else ret->cipher=ssl_get_cipher_by_char(s,&(buf[1])); 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 * 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 * later - am I speaking rubbish?. */ CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); +#endif if ((long)(ret->time+ret->timeout) < (long)time(NULL)) /* timeout */ { s->ctx->stats.sess_timeout++; /* remove it from the cache */ SSL_CTX_remove_session(s->ctx,ret); - SSL_SESSION_free(ret); /* again to actually Free it */ - return(0); + goto err; } s->ctx->stats.sess_hit++; @@ -277,7 +335,16 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len) if (s->session != NULL) SSL_SESSION_free(s->session); s->session=ret; + s->verify_result = s->session->verify_result; 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)