X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fssl_sess.c;h=c21aeed8b18fba3557924165081c480a03870e66;hp=3f0b19558d7a3429e6c1b1f317c60c97cf0576f7;hb=e636e2acd753fb68f587c9fac2f381ad8c153528;hpb=08557cf22cd7c337d7430c32fb21ed29a77a8131 diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index 3f0b19558d..c21aeed8b1 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -231,13 +231,18 @@ const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len) return s->session_id; } -/* Even with SSLv2, we have 16 bytes (128 bits) of session ID space. SSLv3/TLSv1 - * has 32 bytes (256 bits). As such, filling the ID with random gunk repeatedly +unsigned int SSL_SESSION_get_compress_id(const SSL_SESSION *s) + { + return s->compress_meth; + } + +/* SSLv3/TLSv1 has 32 bytes (256 bits) of session ID space. As such, filling + * the ID with random junk repeatedly * until we have no conflict is going to complete in one iteration pretty much * "most" of the time (btw: understatement). So, if it takes us 10 iterations * and we still can't avoid a conflict - well that's a reasonable point to call * it quits. Either the RAND code is broken or someone is trying to open roughly - * very close to 2^128 (or 2^256) SSL sessions to our server. How you might + * very close to 2^256 SSL sessions to our server. How you might * store that many sessions is perhaps a more interesting question ... */ #define MAX_SESS_ID_ATTEMPTS 10 @@ -288,12 +293,7 @@ int ssl_get_new_session(SSL *s, int session) if (session) { - if (s->version == SSL2_VERSION) - { - ss->ssl_version=SSL2_VERSION; - ss->session_id_length=SSL2_SSL_SESSION_ID_LENGTH; - } - else if (s->version == SSL3_VERSION) + if (s->version == SSL3_VERSION) { ss->ssl_version=SSL3_VERSION; ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH; @@ -308,6 +308,11 @@ int ssl_get_new_session(SSL *s, int session) ss->ssl_version=TLS1_1_VERSION; ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH; } + else if (s->version == TLS1_2_VERSION) + { + ss->ssl_version=TLS1_2_VERSION; + ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH; + } else if (s->version == DTLS1_BAD_VER) { ss->ssl_version=DTLS1_BAD_VER; @@ -318,6 +323,11 @@ int ssl_get_new_session(SSL *s, int session) ss->ssl_version=DTLS1_VERSION; ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH; } + else if (s->version == DTLS1_2_VERSION) + { + ss->ssl_version=DTLS1_2_VERSION; + ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH; + } else { SSLerr(SSL_F_SSL_GET_NEW_SESSION,SSL_R_UNSUPPORTED_SSL_VERSION); @@ -325,7 +335,21 @@ int ssl_get_new_session(SSL *s, int session) return(0); } #ifndef OPENSSL_NO_TLSEXT - /* If RFC4507 ticket use empty session ID */ + /*- + * If RFC5077 ticket, use empty session ID (as server). + * Note that: + * (a) ssl_get_prev_session() does lookahead into the + * ClientHello extensions to find the session ticket. + * When ssl_get_prev_session() fails, s3_srvr.c calls + * ssl_get_new_session() in ssl3_get_client_hello(). + * At that point, it has not yet parsed the extensions, + * however, because of the lookahead, it already knows + * whether a ticket is expected or not. + * + * (b) s3_clnt.c calls ssl_get_new_session() before parsing + * ServerHello extensions, and before recording the session + * ID received from the server, so this block is a noop. + */ if (s->tlsext_ticket_expected) { ss->session_id_length = 0; @@ -359,11 +383,7 @@ int ssl_get_new_session(SSL *s, int session) SSL_SESSION_free(ss); return(0); } - /* If the session length was shrunk and we're SSLv2, pad it */ - if((tmp < ss->session_id_length) && (s->version == SSL2_VERSION)) - memset(ss->session_id + tmp, 0, ss->session_id_length - tmp); - else - ss->session_id_length = tmp; + ss->session_id_length = tmp; /* Finally, check for a conflict */ if(SSL_has_matching_session_id(s, ss->session_id, ss->session_id_length)) @@ -383,32 +403,6 @@ int ssl_get_new_session(SSL *s, int session) return 0; } } -#ifndef OPENSSL_NO_EC - if (s->tlsext_ecpointformatlist) - { - if (ss->tlsext_ecpointformatlist != NULL) OPENSSL_free(ss->tlsext_ecpointformatlist); - if ((ss->tlsext_ecpointformatlist = OPENSSL_malloc(s->tlsext_ecpointformatlist_length)) == NULL) - { - SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_MALLOC_FAILURE); - SSL_SESSION_free(ss); - return 0; - } - ss->tlsext_ecpointformatlist_length = s->tlsext_ecpointformatlist_length; - memcpy(ss->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length); - } - if (s->tlsext_ellipticcurvelist) - { - if (ss->tlsext_ellipticcurvelist != NULL) OPENSSL_free(ss->tlsext_ellipticcurvelist); - if ((ss->tlsext_ellipticcurvelist = OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL) - { - SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_MALLOC_FAILURE); - SSL_SESSION_free(ss); - return 0; - } - ss->tlsext_ellipticcurvelist_length = s->tlsext_ellipticcurvelist_length; - memcpy(ss->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length); - } -#endif #endif } else @@ -431,6 +425,26 @@ int ssl_get_new_session(SSL *s, int session) return(1); } +/*- + * ssl_get_prev attempts to find an SSL_SESSION to be used to resume this + * connection. It is only called by servers. + * + * session_id: points at the session ID in the ClientHello. This code will + * read past the end of this in order to parse out the session ticket + * extension, if any. + * len: the length of the session ID. + * limit: a pointer to the first byte after the ClientHello. + * + * Returns: + * -1: error + * 0: a session may have been found. + * + * Side effects: + * - If a session is found then s->session is pointed at it (after freeing an + * existing session if need be) and s->verify_result is set from the session. + * - Both for new and resumed sessions, s->tlsext_ticket_expected is set to 1 + * if the server should issue a new session ticket (to 0 otherwise). + */ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len, const unsigned char *limit) { @@ -438,27 +452,40 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len, SSL_SESSION *ret=NULL; int fatal = 0; + int try_session_cache = 1; #ifndef OPENSSL_NO_TLSEXT int r; #endif if (len > SSL_MAX_SSL_SESSION_ID_LENGTH) goto err; + + if (len == 0) + try_session_cache = 0; + #ifndef OPENSSL_NO_TLSEXT + /* sets s->tlsext_ticket_expected */ r = tls1_process_ticket(s, session_id, len, limit, &ret); - if (r == -1) + switch (r) { + case -1: /* Error during processing */ fatal = 1; goto err; + case 0: /* No ticket found */ + case 1: /* Zero length ticket found */ + break; /* Ok to carry on processing session id. */ + case 2: /* Ticket found but not decrypted. */ + case 3: /* Ticket decrypted, *ret has been set. */ + try_session_cache = 0; + break; + default: + abort(); } - else if (r == 0 || (!ret && !len)) - goto err; - else if (!ret && !(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) -#else - if (len == 0) - goto err; - if (!(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) #endif + + if (try_session_cache && + ret == NULL && + !(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) { SSL_SESSION data; data.ssl_version=s->version; @@ -469,20 +496,22 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len, CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); ret=lh_SSL_SESSION_retrieve(s->session_ctx->sessions,&data); if (ret != NULL) - /* don't allow other threads to steal it: */ - CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); + { + /* don't allow other threads to steal it: */ + CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); + } CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); + if (ret == NULL) + s->session_ctx->stats.sess_miss++; } - if (ret == NULL) + if (try_session_cache && + ret == NULL && + s->session_ctx->get_session_cb != NULL) { int copy=1; - s->session_ctx->stats.sess_miss++; - ret=NULL; - if (s->session_ctx->get_session_cb != NULL - && (ret=s->session_ctx->get_session_cb(s,session_id,len,©)) - != NULL) + if ((ret=s->session_ctx->get_session_cb(s,session_id,len,©))) { s->session_ctx->stats.sess_cb_hit++; @@ -501,23 +530,18 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len, * things are very strange */ SSL_CTX_add_session(s->session_ctx,ret); } - if (ret == NULL) - goto err; } - /* Now ret is non-NULL, and we own one of its reference counts. */ + if (ret == NULL) + goto err; + + /* Now ret is non-NULL and we own one of its reference counts. */ if (ret->sid_ctx_length != s->sid_ctx_length || memcmp(ret->sid_ctx,s->sid_ctx,ret->sid_ctx_length)) { - /* We've found the session named by the client, but we don't + /* We have the session requested by the client, but we don't * want to use it in this context. */ - -#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 */ } @@ -554,39 +578,38 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len, 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 'OPENSSL_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 (ret->timeout < (long)(time(NULL) - ret->time)) /* timeout */ { s->session_ctx->stats.sess_timeout++; - /* remove it from the cache */ - SSL_CTX_remove_session(s->session_ctx,ret); + if (try_session_cache) + { + /* session was from the cache, so remove it */ + SSL_CTX_remove_session(s->session_ctx,ret); + } goto err; } s->session_ctx->stats.sess_hit++; - /* ret->time=time(NULL); */ /* rezero timeout? */ - /* again, just leave the session - * if it is the same session, we have just incremented and - * then decremented the reference count :-) */ if (s->session != NULL) SSL_SESSION_free(s->session); s->session=ret; s->verify_result = s->session->verify_result; - return(1); + return 1; err: if (ret != NULL) + { SSL_SESSION_free(ret); +#ifndef OPENSSL_NO_TLSEXT + if (!try_session_cache) + { + /* The session was from a ticket, so we should + * issue a ticket for the new session */ + s->tlsext_ticket_expected = 1; + } +#endif + } if (fatal) return -1; else @@ -715,7 +738,6 @@ void SSL_SESSION_free(SSL_SESSION *ss) CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data); - OPENSSL_cleanse(ss->key_arg,sizeof ss->key_arg); OPENSSL_cleanse(ss->master_key,sizeof ss->master_key); OPENSSL_cleanse(ss->session_id,sizeof ss->session_id); if (ss->sess_cert != NULL) ssl_sess_cert_free(ss->sess_cert); @@ -765,10 +787,6 @@ int SSL_set_session(SSL *s, SSL_SESSION *session) { if (!SSL_set_ssl_method(s,meth)) return(0); - if (s->ctx->session_timeout == 0) - session->timeout=SSL_get_default_timeout(s); - else - session->timeout=s->ctx->session_timeout; } #ifndef OPENSSL_NO_KRB5 @@ -776,6 +794,11 @@ int SSL_set_session(SSL *s, SSL_SESSION *session) session->krb5_client_princ_len > 0) { s->kssl_ctx->client_princ = (char *)OPENSSL_malloc(session->krb5_client_princ_len + 1); + if (s->kssl_ctx->client_princ == NULL) + { + SSLerr(SSL_F_SSL_SET_SESSION, ERR_R_MALLOC_FAILURE); + return(0); + } memcpy(s->kssl_ctx->client_princ,session->krb5_client_princ, session->krb5_client_princ_len); s->kssl_ctx->client_princ[session->krb5_client_princ_len] = '\0'; @@ -836,16 +859,6 @@ long SSL_SESSION_set_time(SSL_SESSION *s, long t) return(t); } -unsigned int SSL_SESSION_get_id_len(SSL_SESSION *s) - { - return s->session_id_length; - } - -const unsigned char *SSL_SESSION_get0_id(SSL_SESSION *s) - { - return s->session_id; - } - X509 *SSL_SESSION_get0_peer(SSL_SESSION *s) { return s->peer; @@ -853,17 +866,17 @@ X509 *SSL_SESSION_get0_peer(SSL_SESSION *s) int SSL_SESSION_set1_id_context(SSL_SESSION *s,const unsigned char *sid_ctx, unsigned int sid_ctx_len) - { - if(sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) { - SSLerr(SSL_F_SSL_SESSION_SET1_ID_CONTEXT,SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); - return 0; - } - s->sid_ctx_length=sid_ctx_len; - memcpy(s->sid_ctx,sid_ctx,sid_ctx_len); + if(sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) + { + SSLerr(SSL_F_SSL_SESSION_SET1_ID_CONTEXT,SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); + return 0; + } + s->sid_ctx_length=sid_ctx_len; + memcpy(s->sid_ctx,sid_ctx,sid_ctx_len); - return 1; - } + return 1; + } long SSL_CTX_set_timeout(SSL_CTX *s, long t) {