X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fssl_sess.c;h=6292d011266258e7daca1f9b7f57ac60ce784c92;hp=c0fc8b356c2e56d4dd327a4c629db328e5f82ff3;hb=98e1d93454a5d0b34e929f28528756ba9a636e5c;hpb=ddf6ec006963d49e8b0dce55fe22fb8e844c3fbf diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index c0fc8b356c..6292d01126 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -1,5 +1,6 @@ /* - * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2005 Nokia. All rights reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -7,37 +8,11 @@ * https://www.openssl.org/source/license.html */ -/* ==================================================================== - * Copyright 2005 Nokia. All rights reserved. - * - * The portions of the attached software ("Contribution") is developed by - * Nokia Corporation and is licensed pursuant to the OpenSSL open source - * license. - * - * The Contribution, originally written by Mika Kousa and Pasi Eronen of - * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites - * support (see RFC 4279) to OpenSSL. - * - * No patent licenses or other rights except those expressly stated in - * the OpenSSL open source license shall be deemed granted or received - * expressly, by implication, estoppel, or otherwise. - * - * No assurances are provided by Nokia that the Contribution does not - * infringe the patent or other intellectual property rights of any third - * party or that the license provides you with all the necessary rights - * to make use of the Contribution. - * - * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN - * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA - * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY - * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR - * OTHERWISE. - */ - #include #include #include #include +#include "internal/refcount.h" #include "ssl_locl.h" #include "statem/statem_locl.h" @@ -46,12 +21,12 @@ 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_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. The preferred way for applications to obtain + * a resumable session is to use SSL_CTX_sess_set_new_cb(). */ SSL_SESSION *SSL_get_session(const SSL *ssl) @@ -119,6 +94,11 @@ SSL_SESSION *SSL_SESSION_new(void) return ss; } +SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *src) +{ + return ssl_session_dup(src, 1); +} + /* * Create a new SSL_SESSION and duplicate the contents of |src| into it. If * ticket == 0 then no ticket information is duplicated, otherwise it is. @@ -148,9 +128,13 @@ SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket) dest->ext.supportedgroups = NULL; #endif dest->ext.tick = NULL; + dest->ext.alpn_selected = NULL; #ifndef OPENSSL_NO_SRP dest->srp_username = NULL; #endif + dest->peer_chain = NULL; + dest->peer = NULL; + dest->ext.tick_nonce = NULL; memset(&dest->ex_data, 0, sizeof(dest->ex_data)); /* We deliberately don't copy the prev and next pointers */ @@ -163,8 +147,14 @@ SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket) if (dest->lock == NULL) goto err; - if (src->peer != NULL) - X509_up_ref(src->peer); + if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, dest, &dest->ex_data)) + goto err; + + if (src->peer != NULL) { + if (!X509_up_ref(src->peer)) + goto err; + dest->peer = src->peer; + } if (src->peer_chain != NULL) { dest->peer_chain = X509_chain_up_ref(src->peer_chain); @@ -220,7 +210,7 @@ SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket) } #endif - if (ticket != 0) { + if (ticket != 0 && src->ext.tick != NULL) { dest->ext.tick = OPENSSL_memdup(src->ext.tick, src->ext.ticklen); if (dest->ext.tick == NULL) @@ -230,6 +220,22 @@ SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket) dest->ext.ticklen = 0; } + if (src->ext.alpn_selected) { + dest->ext.alpn_selected = + (unsigned char*)OPENSSL_strndup((char*)src->ext.alpn_selected, + src->ext.alpn_selected_len); + if (dest->ext.alpn_selected == NULL) { + goto err; + } + } + + if (src->ext.tick_nonce != NULL) { + dest->ext.tick_nonce = OPENSSL_memdup(src->ext.tick_nonce, + src->ext.tick_nonce_len); + if (dest->ext.tick_nonce == NULL) + goto err; + } + #ifndef OPENSSL_NO_SRP if (src->srp_username) { dest->srp_username = OPENSSL_strdup(src->srp_username); @@ -277,12 +283,12 @@ unsigned int SSL_SESSION_get_compress_id(const SSL_SESSION *s) */ #define MAX_SESS_ID_ATTEMPTS 10 -static int def_generate_session_id(const SSL *ssl, unsigned char *id, +static int def_generate_session_id(SSL *ssl, unsigned char *id, unsigned int *id_len) { unsigned int retry = 0; do - if (RAND_bytes(id, *id_len) <= 0) + if (ssl_randbytes(ssl, id, *id_len) <= 0) return 0; while (SSL_has_matching_session_id(ssl, id, *id_len) && (++retry < MAX_SESS_ID_ATTEMPTS)) ; @@ -458,7 +464,7 @@ 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. */ @@ -468,10 +474,11 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) TICKET_RETURN r; if (SSL_IS_TLS13(s)) { - int al; - - if (!tls_parse_extension(s, TLSEXT_IDX_psk, EXT_CLIENT_HELLO, - hello->pre_proc_exts, NULL, 0, &al)) + if (!tls_parse_extension(s, TLSEXT_IDX_psk_kex_modes, + SSL_EXT_CLIENT_HELLO, hello->pre_proc_exts, + NULL, 0, al) + || !tls_parse_extension(s, TLSEXT_IDX_psk, SSL_EXT_CLIENT_HELLO, + hello->pre_proc_exts, NULL, 0, al)) return -1; ret = s->session; @@ -480,15 +487,16 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) r = tls_get_ticket_from_client(s, hello, &ret); switch (r) { case TICKET_FATAL_ERR_MALLOC: - case TICKET_FATAL_ERR_OTHER: /* Error during processing */ + case TICKET_FATAL_ERR_OTHER: fatal = 1; goto err; - case TICKET_NONE: /* No ticket found */ - case TICKET_EMPTY: /* Zero length ticket found */ - try_session_cache = 1; - break; /* Ok to carry on processing session id. */ - case TICKET_NO_DECRYPT: /* Ticket found but not decrypted. */ - case TICKET_SUCCESS: /* Ticket decrypted, *ret has been set. */ + case TICKET_NONE: + case TICKET_EMPTY: + if (hello->session_id_len > 0) + try_session_cache = 1; + break; + case TICKET_NO_DECRYPT: + case TICKET_SUCCESS: case TICKET_SUCCESS_RENEW: break; } @@ -501,7 +509,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; @@ -545,11 +552,11 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) (s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE)) { /* - * The following should not return 1, otherwise, things are - * very strange + * Either return value of SSL_CTX_add_session should not + * interrupt the session resumption process. The return + * value is intentionally ignored. */ - if (SSL_CTX_add_session(s->session_ctx, ret)) - goto err; + SSL_CTX_add_session(s->session_ctx, ret); } } } @@ -603,7 +610,7 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) /* If old session includes extms, but new does not: abort handshake */ if (!(s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS)) { SSLerr(SSL_F_SSL_GET_PREV_SESSION, SSL_R_INCONSISTENT_EXTMS); - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); fatal = 1; goto err; } @@ -637,10 +644,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) @@ -790,6 +799,8 @@ void SSL_SESSION_free(SSL_SESSION *ss) #ifndef OPENSSL_NO_SRP OPENSSL_free(ss->srp_username); #endif + OPENSSL_free(ss->ext.alpn_selected); + OPENSSL_free(ss->ext.tick_nonce); CRYPTO_THREAD_lock_free(ss->lock); OPENSSL_clear_free(ss, sizeof(*ss)); } @@ -833,7 +844,8 @@ int SSL_SESSION_set1_id(SSL_SESSION *s, const unsigned char *sid, return 0; } s->session_id_length = sid_len; - memcpy(s->session_id, sid, sid_len); + if (sid != s->session_id) + memcpy(s->session_id, sid, sid_len); return 1; } @@ -872,11 +884,23 @@ int SSL_SESSION_get_protocol_version(const SSL_SESSION *s) return s->ssl_version; } +int SSL_SESSION_set_protocol_version(SSL_SESSION *s, int version) +{ + s->ssl_version = version; + return 1; +} + const SSL_CIPHER *SSL_SESSION_get0_cipher(const SSL_SESSION *s) { return s->cipher; } +int SSL_SESSION_set_cipher(SSL_SESSION *s, const SSL_CIPHER *cipher) +{ + s->cipher = cipher; + return 1; +} + const char *SSL_SESSION_get0_hostname(const SSL_SESSION *s) { return s->ext.hostname; @@ -900,6 +924,18 @@ void SSL_SESSION_get0_ticket(const SSL_SESSION *s, const unsigned char **tick, *tick = s->ext.tick; } +uint32_t SSL_SESSION_get_max_early_data(const SSL_SESSION *s) +{ + return s->ext.max_early_data; +} + +int SSL_SESSION_set_max_early_data(SSL_SESSION *s, uint32_t max_early_data) +{ + s->ext.max_early_data = max_early_data; + + return 1; +} + X509 *SSL_SESSION_get0_peer(SSL_SESSION *s) { return s->peer; @@ -914,11 +950,22 @@ int SSL_SESSION_set1_id_context(SSL_SESSION *s, const unsigned char *sid_ctx, return 0; } s->sid_ctx_length = sid_ctx_len; - memcpy(s->sid_ctx, sid_ctx, sid_ctx_len); + if (sid_ctx != s->sid_ctx) + memcpy(s->sid_ctx, sid_ctx, sid_ctx_len); return 1; } +int SSL_SESSION_is_resumable(const SSL_SESSION *s) +{ + /* + * In the case of EAP-FAST, we can have a pre-shared "ticket" without a + * session ID. + */ + return !s->not_resumable + && (s->session_id_length > 0 || s->ext.ticklen > 0); +} + long SSL_CTX_set_timeout(SSL_CTX *s, long t) { long l;