enum ssl_session_result_t ssl_get_prev_session( SSL *ssl, SSL_SESSION **out_session, int *out_tickets_supported, int *out_renew_ticket, const SSL_CLIENT_HELLO *client_hello) { /* This is used only by servers. */ assert(ssl->server); SSL_SESSION *session = NULL; int renew_ticket = 0; /* If tickets are disabled, always behave as if no tickets are present. */ const uint8_t *ticket = NULL; size_t ticket_len = 0; const int tickets_supported = !(SSL_get_options(ssl) & SSL_OP_NO_TICKET) && ssl->version > SSL3_VERSION && SSL_early_callback_ctx_extension_get( client_hello, TLSEXT_TYPE_session_ticket, &ticket, &ticket_len); if (tickets_supported && ticket_len > 0) { switch (ssl_process_ticket(ssl, &session, &renew_ticket, ticket, ticket_len, client_hello->session_id, client_hello->session_id_len)) { case ssl_ticket_aead_success: break; case ssl_ticket_aead_ignore_ticket: assert(session == NULL); break; case ssl_ticket_aead_error: return ssl_session_error; case ssl_ticket_aead_retry: return ssl_session_ticket_retry; } } else { /* The client didn't send a ticket, so the session ID is a real ID. */ enum ssl_session_result_t lookup_ret = ssl_lookup_session( ssl, &session, client_hello->session_id, client_hello->session_id_len); if (lookup_ret != ssl_session_success) { return lookup_ret; } } *out_session = session; *out_tickets_supported = tickets_supported; *out_renew_ticket = renew_ticket; return ssl_session_success; }
enum ssl_session_result_t ssl_get_prev_session( SSL *ssl, SSL_SESSION **out_session, int *out_send_ticket, const struct ssl_early_callback_ctx *ctx) { /* This is used only by servers. */ assert(ssl->server); SSL_SESSION *session = NULL; int renew_ticket = 0; /* If tickets are disabled, always behave as if no tickets are present. */ const uint8_t *ticket = NULL; size_t ticket_len = 0; const int tickets_supported = !(SSL_get_options(ssl) & SSL_OP_NO_TICKET) && ssl->version > SSL3_VERSION && SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_session_ticket, &ticket, &ticket_len); int from_cache = 0; if (tickets_supported && ticket_len > 0) { if (!tls_process_ticket(ssl, &session, &renew_ticket, ticket, ticket_len, ctx->session_id, ctx->session_id_len)) { return ssl_session_error; } } else { /* The client didn't send a ticket, so the session ID is a real ID. */ enum ssl_session_result_t lookup_ret = ssl_lookup_session( ssl, &session, ctx->session_id, ctx->session_id_len); if (lookup_ret != ssl_session_success) { return lookup_ret; } from_cache = 1; } if (session == NULL || session->sid_ctx_length != ssl->sid_ctx_length || memcmp(session->sid_ctx, ssl->sid_ctx, ssl->sid_ctx_length) != 0) { /* The client did not offer a suitable ticket or session ID. If supported, * the new session should use a ticket. */ goto no_session; } if ((ssl->verify_mode & SSL_VERIFY_PEER) && ssl->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_R_SESSION_ID_CONTEXT_UNINITIALIZED); SSL_SESSION_free(session); return ssl_session_error; } if (session->timeout < (long)(time(NULL) - session->time)) { if (from_cache) { /* The session was from the cache, so remove it. */ SSL_CTX_remove_session(ssl->initial_ctx, session); } goto no_session; } *out_session = session; *out_send_ticket = renew_ticket; return ssl_session_success; no_session: *out_session = NULL; *out_send_ticket = tickets_supported; SSL_SESSION_free(session); return ssl_session_success; }