SSL_SESSION *SSL_get1_session(SSL *ssl) { SSL_SESSION *ret = SSL_get_session(ssl); if (ret != NULL) { SSL_SESSION_up_ref(ret); } return ret; }
void SSLSessionImpl::upRef() { if (session_) { #if defined(OPENSSL_IS_102) || defined(OPENSSL_IS_101) CRYPTO_add(&session_->references, 1, CRYPTO_LOCK_SSL_SESSION); #elif defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_110) SSL_SESSION_up_ref(session_); #endif } }
int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) { int ret = 0; SSL_SESSION *s; /* add just 1 reference count for the SSL_CTX's session cache even though it * has two ways of access: each session is in a doubly linked list and an * lhash */ SSL_SESSION_up_ref(c); /* if session c is in already in cache, we take back the increment later */ CRYPTO_MUTEX_lock_write(&ctx->lock); if (!lh_SSL_SESSION_insert(ctx->sessions, &s, c)) { CRYPTO_MUTEX_unlock(&ctx->lock); return 0; } /* s != NULL iff we already had a session with the given PID. In this case, s * == c should hold (then we did not really modify ctx->sessions), or we're * in trouble. */ if (s != NULL && s != c) { /* We *are* in trouble ... */ SSL_SESSION_list_remove(ctx, s); SSL_SESSION_free(s); /* ... so pretend the other session did not exist in cache (we cannot * handle two SSL_SESSION structures with identical session ID in the same * cache, which could happen e.g. when two threads concurrently obtain the * same session from an external cache) */ s = NULL; } /* Put at the head of the queue unless it is already in the cache */ if (s == NULL) { SSL_SESSION_list_add(ctx, c); } if (s != NULL) { /* existing cache entry -- decrement previously incremented reference count * because it already takes into account the cache */ SSL_SESSION_free(s); /* s == c */ ret = 0; } else { /* new cache entry -- remove old ones if cache has become too large */ ret = 1; if (SSL_CTX_sess_get_cache_size(ctx) > 0) { while (SSL_CTX_sess_number(ctx) > SSL_CTX_sess_get_cache_size(ctx)) { if (!remove_session_lock(ctx, ctx->session_cache_tail, 0)) { break; } } } } CRYPTO_MUTEX_unlock(&ctx->lock); return ret; }
void ssl_set_session(SSL *ssl, SSL_SESSION *session) { if (ssl->session == session) { return; } SSL_SESSION_free(ssl->session); ssl->session = session; if (session != NULL) { SSL_SESSION_up_ref(session); } }
int SSL_set_session(SSL *ssl, SSL_SESSION *session) { if (ssl->session == session) { return 1; } SSL_SESSION_free(ssl->session); ssl->session = session; if (session != NULL) { SSL_SESSION_up_ref(session); ssl->verify_result = session->verify_result; } return 1; }
SSL_SESSION *SSL_get1_session(SSL *ssl) /* variant of SSL_get_session: caller really gets something */ { 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_THREAD_read_lock(ssl->lock); sess = ssl->session; if (sess) SSL_SESSION_up_ref(sess); CRYPTO_THREAD_unlock(ssl->lock); return sess; }
int SSL_set_session(SSL *s, SSL_SESSION *session) { ssl_clear_bad_session(s); if (s->ctx->method != s->method) { if (!SSL_set_ssl_method(s, s->ctx->method)) return 0; } if (session != NULL) { SSL_SESSION_up_ref(session); s->verify_result = session->verify_result; } SSL_SESSION_free(s->session); s->session = session; return 1; }
int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *session) { /* Although |session| is inserted into two structures (a doubly-linked list * and the hash table), |ctx| only takes one reference. */ SSL_SESSION_up_ref(session); SSL_SESSION *old_session; CRYPTO_MUTEX_lock_write(&ctx->lock); if (!lh_SSL_SESSION_insert(ctx->sessions, &old_session, session)) { CRYPTO_MUTEX_unlock(&ctx->lock); SSL_SESSION_free(session); return 0; } if (old_session != NULL) { if (old_session == session) { /* |session| was already in the cache. */ CRYPTO_MUTEX_unlock(&ctx->lock); SSL_SESSION_free(old_session); return 0; } /* There was a session ID collision. |old_session| must be removed from * the linked list and released. */ SSL_SESSION_list_remove(ctx, old_session); SSL_SESSION_free(old_session); } SSL_SESSION_list_add(ctx, session); /* Enforce any cache size limits. */ if (SSL_CTX_sess_get_cache_size(ctx) > 0) { while (SSL_CTX_sess_number(ctx) > SSL_CTX_sess_get_cache_size(ctx)) { if (!remove_session_lock(ctx, ctx->session_cache_tail, 0)) { break; } } } CRYPTO_MUTEX_unlock(&ctx->lock); return 1; }
/* ssl_lookup_session looks up |session_id| in the session cache and sets * |*out_session| to an |SSL_SESSION| object if found. The caller takes * ownership of the result. */ static enum ssl_session_result_t ssl_lookup_session( SSL *ssl, SSL_SESSION **out_session, const uint8_t *session_id, size_t session_id_len) { *out_session = NULL; if (session_id_len == 0 || session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) { return ssl_session_success; } SSL_SESSION *session; /* Try the internal cache, if it exists. */ if (!(ssl->initial_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) { SSL_SESSION data; data.ssl_version = ssl->version; data.session_id_length = session_id_len; memcpy(data.session_id, session_id, session_id_len); CRYPTO_MUTEX_lock_read(&ssl->initial_ctx->lock); session = lh_SSL_SESSION_retrieve(ssl->initial_ctx->sessions, &data); if (session != NULL) { SSL_SESSION_up_ref(session); } /* TODO(davidben): This should probably move it to the front of the list. */ CRYPTO_MUTEX_unlock(&ssl->initial_ctx->lock); if (session != NULL) { *out_session = session; return ssl_session_success; } } /* Fall back to the external cache, if it exists. */ if (ssl->initial_ctx->get_session_cb == NULL) { return ssl_session_success; } int copy = 1; session = ssl->initial_ctx->get_session_cb(ssl, (uint8_t *)session_id, session_id_len, ©); if (session == NULL) { return ssl_session_success; } if (session == SSL_magic_pending_session_ptr()) { return ssl_session_retry; } /* 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) { SSL_SESSION_up_ref(session); } /* Add the externally cached session to the internal cache if necessary. */ if (!(ssl->initial_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE)) { SSL_CTX_add_session(ssl->initial_ctx, session); } *out_session = session; return ssl_session_success; }
SSL_SESSION *SSL_get1_session(SSL *ssl) { /* variant of SSL_get_session: caller really gets something */ return SSL_SESSION_up_ref(ssl->session); }
/* ssl_get_prev attempts to find an SSL_SESSION to be used to resume this * connection. It is only called by servers. * * ctx: contains the early callback context, which is the result of a * shallow parse of 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, const struct ssl_early_callback_ctx *ctx) { /* This is used only by servers. */ SSL_SESSION *ret = NULL; int fatal = 0; int try_session_cache = 1; int r; if (ctx->session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) { goto err; } if (ctx->session_id_len == 0) { try_session_cache = 0; } r = tls1_process_ticket(s, ctx, &ret); /* sets s->tlsext_ticket_expected */ 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(); } if (try_session_cache && ret == NULL && !(s->initial_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) { SSL_SESSION data; data.ssl_version = s->version; data.session_id_length = ctx->session_id_len; if (ctx->session_id_len == 0) { return 0; } memcpy(data.session_id, ctx->session_id, ctx->session_id_len); CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); ret = SSL_SESSION_up_ref(lh_SSL_SESSION_retrieve(s->initial_ctx->sessions, &data)); CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); } if (try_session_cache && ret == NULL && s->initial_ctx->get_session_cb != NULL) { int copy = 1; ret = s->initial_ctx->get_session_cb(s, (uint8_t *)ctx->session_id, ctx->session_id_len, ©); if (ret != NULL) { if (ret == SSL_magic_pending_session_ptr()) { /* This is a magic value which indicates that the callback needs to * unwind the stack and figure out the session asynchronously. */ return PENDING_SESSION; } /* 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) { SSL_SESSION_up_ref(ret); } /* Add the externally cached session to the internal cache as well if and * only if we are supposed to. */ if (!(s->initial_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE)) { /* The following should not return 1, otherwise, things are very * strange */ SSL_CTX_add_session(s->initial_ctx, ret); } } } 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 have the session requested by the client, but we don't want to use it * in this context. */ goto err; /* treat like cache miss */ } if ((s->verify_mode & SSL_VERIFY_PEER) && s->sid_ctx_length == 0) { /* We can't be sure if this session is being used out of context, which is * especially important for SSL_VERIFY_PEER. The application should have * used SSL[_CTX]_set_session_id_context. * * For this error case, we generate an error instead of treating the event * like a cache miss (otherwise it would be easy for applications to * effectively disable the session cache by accident without anyone * noticing). */ OPENSSL_PUT_ERROR(SSL, ssl_get_prev_session, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED); fatal = 1; goto err; } if (ret->timeout < (long)(time(NULL) - ret->time)) { /* timeout */ if (try_session_cache) { /* session was from the cache, so remove it */ SSL_CTX_remove_session(s->initial_ctx, ret); } goto err; } 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 (!try_session_cache) { /* The session was from a ticket, so we should * issue a ticket for the new session */ s->tlsext_ticket_expected = 1; } } if (fatal) { return -1; } return 0; }
int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) { int ret = 0; SSL_SESSION *s; /* * add just 1 reference count for the SSL_CTX's session cache even though * it has two ways of access: each session is in a doubly linked list and * an lhash */ SSL_SESSION_up_ref(c); /* * if session c is in already in cache, we take back the increment later */ CRYPTO_THREAD_write_lock(ctx->lock); s = lh_SSL_SESSION_insert(ctx->sessions, c); /* * s != NULL iff we already had a session with the given PID. In this * case, s == c should hold (then we did not really modify * ctx->sessions), or we're in trouble. */ if (s != NULL && s != c) { /* We *are* in trouble ... */ SSL_SESSION_list_remove(ctx, s); SSL_SESSION_free(s); /* * ... so pretend the other session did not exist in cache (we cannot * handle two SSL_SESSION structures with identical session ID in the * same cache, which could happen e.g. when two threads concurrently * 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 */ if (s == NULL) SSL_SESSION_list_add(ctx, c); if (s != NULL) { /* * existing cache entry -- decrement previously incremented reference * count because it already takes into account the cache */ SSL_SESSION_free(s); /* s == c */ ret = 0; } else { /* * new cache entry -- remove old ones if cache has become too large */ ret = 1; if (SSL_CTX_sess_get_cache_size(ctx) > 0) { while (SSL_CTX_sess_number(ctx) > SSL_CTX_sess_get_cache_size(ctx)) { if (!remove_session_lock(ctx, ctx->session_cache_tail, 0)) break; else ctx->stats.sess_cache_full++; } } } CRYPTO_THREAD_unlock(ctx->lock); return ret; }
/*- * ssl_get_prev attempts to find an SSL_SESSION to be used to resume this * connection. It is only called by servers. * * hello: The parsed ClientHello data * * Returns: * -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 * existing session if need be) and s->verify_result is set from the 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 *al) { /* This is used only by servers. */ SSL_SESSION *ret = NULL; int fatal = 0; int try_session_cache = 0; TICKET_RETURN r; if (SSL_IS_TLS13(s)) { 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; } 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 && ret == NULL && !(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) { SSL_SESSION data; data.ssl_version = s->version; memcpy(data.session_id, hello->session_id, hello->session_id_len); data.session_id_length = hello->session_id_len; CRYPTO_THREAD_read_lock(s->session_ctx->lock); ret = lh_SSL_SESSION_retrieve(s->session_ctx->sessions, &data); if (ret != NULL) { /* don't allow other threads to steal it: */ SSL_SESSION_up_ref(ret); } CRYPTO_THREAD_unlock(s->session_ctx->lock); if (ret == NULL) s->session_ctx->stats.sess_miss++; } if (try_session_cache && ret == NULL && s->session_ctx->get_session_cb != NULL) { int copy = 1; ret = s->session_ctx->get_session_cb(s, hello->session_id, hello->session_id_len, ©); if (ret != NULL) { s->session_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) SSL_SESSION_up_ref(ret); /* * Add the externally cached session to the internal cache as * well if and only if we are supposed to. */ if (! (s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE)) { /* * The following should not return 1, otherwise, things are * very strange */ if (SSL_CTX_add_session(s->session_ctx, ret)) goto err; } } } if (ret == NULL) goto err; /* 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)) { /* * We have the session requested by the client, but we don't want to * use it in this context. */ goto err; /* treat like cache miss */ } if ((s->verify_mode & SSL_VERIFY_PEER) && s->sid_ctx_length == 0) { /* * We can't be sure if this session is being used out of context, * which is especially important for SSL_VERIFY_PEER. The application * should have used SSL[_CTX]_set_session_id_context. For this error * case, we generate an error instead of treating the event like a * cache miss (otherwise it would be easy for applications to * effectively disable the session cache by accident without anyone * noticing). */ SSLerr(SSL_F_SSL_GET_PREV_SESSION, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED); fatal = 1; goto err; } if (ret->timeout < (long)(time(NULL) - ret->time)) { /* timeout */ s->session_ctx->stats.sess_timeout++; if (try_session_cache) { /* session was from the cache, so remove it */ SSL_CTX_remove_session(s->session_ctx, ret); } 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 */ 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); fatal = 1; goto err; } } else if (s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) { /* If new session includes extms, but old does not: do not resume */ goto err; } if (!SSL_IS_TLS13(s)) { /* We already did this for TLS1.3 */ 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) { /* * The session was from a ticket, so we should issue a ticket for * the new session */ s->ext.ticket_expected = 1; } } if (fatal) { *al = SSL_AD_INTERNAL_ERROR; return -1; } return 0; }
SSL_SESSION *lookup_sess_in_cache(SSL *s, const unsigned char *sess_id, size_t sess_id_len) { SSL_SESSION *ret = NULL; if ((s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP) == 0) { SSL_SESSION data; data.ssl_version = s->version; if (!ossl_assert(sess_id_len <= SSL_MAX_SSL_SESSION_ID_LENGTH)) return NULL; memcpy(data.session_id, sess_id, sess_id_len); data.session_id_length = sess_id_len; CRYPTO_THREAD_read_lock(s->session_ctx->lock); ret = lh_SSL_SESSION_retrieve(s->session_ctx->sessions, &data); if (ret != NULL) { /* don't allow other threads to steal it: */ SSL_SESSION_up_ref(ret); } CRYPTO_THREAD_unlock(s->session_ctx->lock); if (ret == NULL) tsan_counter(&s->session_ctx->stats.sess_miss); } if (ret == NULL && s->session_ctx->get_session_cb != NULL) { int copy = 1; ret = s->session_ctx->get_session_cb(s, sess_id, sess_id_len, ©); if (ret != NULL) { tsan_counter(&s->session_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) SSL_SESSION_up_ref(ret); /* * Add the externally cached session to the internal cache as * well if and only if we are supposed to. */ if ((s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE) == 0) { /* * Either return value of SSL_CTX_add_session should not * interrupt the session resumption process. The return * value is intentionally ignored. */ (void)SSL_CTX_add_session(s->session_ctx, ret); } } } return ret; }