X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fssl_sess.c;h=cc9eeadc1282a97fe0a4c0bb20a67aeb297a16eb;hp=0ea74389c2ac7abb97cd0a31669e1b2400182395;hb=f637004037a11bc04682f54571e3ff11d48d8e36;hpb=1ed327f7dfe02a062e50cd844a925c970c645c7c diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index 0ea74389c2..cc9eeadc12 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -39,11 +39,21 @@ #include #include #include "ssl_locl.h" +#include "statem/statem_locl.h" 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); +/* + * TODO(TLS1.3): SSL_get_session() and SSL_get1_session() are problematic in + * TLS1.3 because, unlike in earlier protocol versions, the session ticket + * may not have been sent yet even though a handshake has finished. The session + * ticket data could come in sometime later...or even change if multiple session + * ticket messages are sent from the server. We need to work out how to deal + * with this. + */ + SSL_SESSION *SSL_get_session(const SSL *ssl) /* aka SSL_get0_session; gets 0 objects, just returns a copy of the pointer */ { @@ -81,6 +91,9 @@ SSL_SESSION *SSL_SESSION_new(void) { SSL_SESSION *ss; + if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL)) + return NULL; + ss = OPENSSL_zalloc(sizeof(*ss)); if (ss == NULL) { SSLerr(SSL_F_SSL_SESSION_NEW, ERR_R_MALLOC_FAILURE); @@ -435,8 +448,9 @@ int ssl_get_new_session(SSL *s, int session) * hello: The parsed ClientHello data * * Returns: - * -1: error - * 0: a session may have been found. + * -1: fatal error + * 0: no session found + * 1: a session may have been found. * * Side effects: * - If a session is found then s->session is pointed at it (after freeing an @@ -444,33 +458,40 @@ int ssl_get_new_session(SSL *s, int session) * - Both for new and resumed sessions, s->ext.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, CLIENTHELLO_MSG *hello) +int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello, int *al) { /* This is used only by servers. */ SSL_SESSION *ret = NULL; int fatal = 0; - int try_session_cache = 1; - int r; + int try_session_cache = 0; + TICKET_RETURN r; - if (hello->session_id_len == 0) - try_session_cache = 0; + if (SSL_IS_TLS13(s)) { + if (!tls_parse_extension(s, TLSEXT_IDX_psk_kex_modes, EXT_CLIENT_HELLO, + hello->pre_proc_exts, NULL, 0, al) + || !tls_parse_extension(s, TLSEXT_IDX_psk, EXT_CLIENT_HELLO, + hello->pre_proc_exts, NULL, 0, al)) + return -1; - /* sets s->ext.ticket_expected */ - r = tls_get_ticket_from_client(s, hello, &ret); - 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(); + ret = s->session; + } else { + /* sets s->ext.ticket_expected */ + r = tls_get_ticket_from_client(s, hello, &ret); + switch (r) { + case TICKET_FATAL_ERR_MALLOC: + case TICKET_FATAL_ERR_OTHER: + fatal = 1; + goto err; + case TICKET_NONE: + case TICKET_EMPTY: + try_session_cache = 1; + break; + case TICKET_NO_DECRYPT: + case TICKET_SUCCESS: + case TICKET_SUCCESS_RENEW: + break; + } } if (try_session_cache && @@ -480,7 +501,6 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) SSL_SESSION data; data.ssl_version = s->version; - memset(data.session_id, 0, sizeof(data.session_id)); memcpy(data.session_id, hello->session_id, hello->session_id_len); data.session_id_length = hello->session_id_len; @@ -538,6 +558,10 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) /* Now ret is non-NULL and we own one of its reference counts. */ + /* Check TLS version consistency */ + if (ret->ssl_version != s->version) + goto err; + if (ret->sid_ctx_length != s->sid_ctx_length || memcmp(ret->sid_ctx, s->sid_ctx, ret->sid_ctx_length)) { /* @@ -564,21 +588,6 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) goto err; } - if (ret->cipher == NULL) { - unsigned char buf[5], *p; - unsigned long l; - - p = buf; - l = ret->cipher_id; - l2n(l, p); - if ((ret->ssl_version >> 8) >= SSL3_VERSION_MAJOR) - ret->cipher = ssl_get_cipher_by_char(s, &(buf[2])); - else - ret->cipher = ssl_get_cipher_by_char(s, &(buf[1])); - if (ret->cipher == NULL) - goto err; - } - if (ret->timeout < (long)(time(NULL) - ret->time)) { /* timeout */ s->session_ctx->stats.sess_timeout++; if (try_session_cache) { @@ -588,23 +597,6 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) goto err; } - /* - * TODO(TLS1.3): This is temporary, because TLSv1.3 resumption is completely - * different. For now though we're still using the old resumption logic, so - * to avoid test failures we need this. Remove this code! - * - * Check TLS version consistency. We can't resume <=TLSv1.2 session if we - * have negotiated TLSv1.3, and vice versa. - */ - if (!SSL_IS_DTLS(s) - && ((ret->ssl_version <= TLS1_2_VERSION - && s->version >=TLS1_3_VERSION) - || (ret->ssl_version >= TLS1_3_VERSION - && s->version <= TLS1_2_VERSION))) { - /* Continue but do not resume */ - goto err; - } - /* Check extended master secret extension consistency */ if (ret->flags & SSL_SESS_FLAG_EXTMS) { /* If old session includes extms, but new does not: abort handshake */ @@ -619,16 +611,22 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) goto err; } - s->session_ctx->stats.sess_hit++; + if (!SSL_IS_TLS13(s)) { + /* We already did this for TLS1.3 */ + SSL_SESSION_free(s->session); + s->session = ret; + } - SSL_SESSION_free(s->session); - s->session = ret; + s->session_ctx->stats.sess_hit++; s->verify_result = s->session->verify_result; return 1; err: if (ret != NULL) { SSL_SESSION_free(ret); + /* In TLSv1.3 s->session was already set to ret, so we NULL it out */ + if (SSL_IS_TLS13(s)) + s->session = NULL; if (!try_session_cache) { /* @@ -638,10 +636,12 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) s->ext.ticket_expected = 1; } } - if (fatal) + if (fatal) { + *al = SSL_AD_INTERNAL_ERROR; return -1; - else - return 0; + } + + return 0; } int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) @@ -678,6 +678,15 @@ int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) * obtain the same session from an external cache) */ s = NULL; + } else if (s == NULL && + lh_SSL_SESSION_retrieve(ctx->sessions, c) == NULL) { + /* s == NULL can also mean OOM error in lh_SSL_SESSION_insert ... */ + + /* + * ... so take back the extra reference and also don't add + * the session to the SSL_SESSION_list at this time + */ + s = c; } /* Put at the head of the queue unless it is already in the cache */ @@ -782,6 +791,7 @@ void SSL_SESSION_free(SSL_SESSION *ss) #ifndef OPENSSL_NO_SRP OPENSSL_free(ss->srp_username); #endif + OPENSSL_free(ss->ext.alpn_selected); CRYPTO_THREAD_lock_free(ss->lock); OPENSSL_clear_free(ss, sizeof(*ss)); }