Codebase list openssl / 25959e0
Optimize session cache flushing Sort SSL_SESSION structures by timeout in the linked list. Iterate over the linked list for timeout, stopping when no more session can be flushed. Do SSL_SESSION_free() outside of SSL_CTX lock Update timeout upon use Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Paul Dale <pauli@openssl.org> (Merged from https://github.com/openssl/openssl/pull/8687) Todd Short authored 5 years ago Pauli committed 2 years ago
8 changed file(s) with 326 addition(s) and 75 deletion(s). Raw diff Collapse all Expand all
104104 Enable both SSL_SESS_CACHE_NO_INTERNAL_LOOKUP and
105105 SSL_SESS_CACHE_NO_INTERNAL_STORE at the same time.
106106
107 =item SSL_SESS_CACHE_UPDATE_TIME
108
109 Updates the timestamp of the session when it is used, increasing the lifespan
110 of the session. The session timeout applies to last use, rather then creation
111 time.
107112
108113 =back
109114
669669 # define SSL_SESS_CACHE_NO_INTERNAL_STORE 0x0200
670670 # define SSL_SESS_CACHE_NO_INTERNAL \
671671 (SSL_SESS_CACHE_NO_INTERNAL_LOOKUP|SSL_SESS_CACHE_NO_INTERNAL_STORE)
672 # define SSL_SESS_CACHE_UPDATE_TIME 0x0400
672673
673674 LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx);
674675 # define SSL_CTX_sess_number(ctx) \
162162 ssl_session_oinit(&as.session_id_context, &sid_ctx,
163163 in->sid_ctx, in->sid_ctx_length);
164164
165 as.time = in->time;
166 as.timeout = in->timeout;
165 as.time = (int64_t)in->time;
166 as.timeout = (int64_t)in->timeout;
167167 as.verify_result = in->verify_result;
168168
169169 as.peer = in->peer;
301301 ret->master_key_length = tmpl;
302302
303303 if (as->time != 0)
304 ret->time = (long)as->time;
305 else
306 ret->time = (long)time(NULL);
304 ret->time = (time_t)as->time;
305 else
306 ret->time = time(NULL);
307307
308308 if (as->timeout != 0)
309 ret->timeout = (long)as->timeout;
309 ret->timeout = (time_t)as->timeout;
310310 else
311311 ret->timeout = 3;
312 ssl_session_calculate_timeout(ret);
312313
313314 X509_free(ret->peer);
314315 ret->peer = as->peer;
592592 */
593593 long verify_result; /* only for servers */
594594 CRYPTO_REF_COUNT references;
595 long timeout;
596 long time;
595 time_t timeout;
596 time_t time;
597 time_t calc_timeout;
598 int timeout_ovf;
597599 unsigned int compress_meth; /* Need to lookup the method */
598600 const SSL_CIPHER *cipher;
599601 unsigned long cipher_id; /* when ASN.1 loaded, this needs to be used to
633635 unsigned char *ticket_appdata;
634636 size_t ticket_appdata_len;
635637 uint32_t flags;
638 SSL_CTX *owner;
636639 CRYPTO_RWLOCK *lock;
637640 };
638641
28422845 int ssl_srp_calc_a_param_intern(SSL *s);
28432846 int ssl_srp_server_param_with_username_intern(SSL *s, int *ad);
28442847
2848 void ssl_session_calculate_timeout(SSL_SESSION* ss);
2849
28452850 # else /* OPENSSL_UNIT_TEST */
28462851
28472852 # define ssl_init_wbio_buffer SSL_test_functions()->p_ssl_init_wbio_buffer
2222 static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s);
2323 static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s);
2424 static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck);
25
26 DEFINE_STACK_OF(SSL_SESSION)
27
28 __owur static int sess_timedout(time_t t, SSL_SESSION *ss)
29 {
30 /* if timeout overflowed, it can never timeout! */
31 if (ss->timeout_ovf)
32 return 0;
33 return t > ss->calc_timeout;
34 }
35
36 /*
37 * Returns -1/0/+1 as other XXXcmp-type functions
38 * Takes overflow of calculated timeout into consideration
39 */
40 __owur static int timeoutcmp(SSL_SESSION *a, SSL_SESSION *b)
41 {
42 /* if only one overflowed, then it is greater */
43 if (a->timeout_ovf && !b->timeout_ovf)
44 return 1;
45 if (!a->timeout_ovf && b->timeout_ovf)
46 return -1;
47 /* No overflow, or both overflowed, so straight compare is safe */
48 if (a->calc_timeout < b->calc_timeout)
49 return -1;
50 if (a->calc_timeout > b->calc_timeout)
51 return 1;
52 return 0;
53 }
54
55 /*
56 * Calculates effective timeout, saving overflow state
57 * Locking must be done by the caller of this function
58 */
59 void ssl_session_calculate_timeout(SSL_SESSION *ss)
60 {
61 /* Force positive timeout */
62 if (ss->timeout < 0)
63 ss->timeout = 0;
64 ss->calc_timeout = ss->time + ss->timeout;
65 /*
66 * |timeout| is always zero or positive, so the check for
67 * overflow only needs to consider if |time| is positive
68 */
69 ss->timeout_ovf = ss->time > 0 && ss->calc_timeout < ss->time;
70 /*
71 * N.B. Realistic overflow can only occur in our lifetimes on a
72 * 32-bit machine in January 2038.
73 * However, There are no controls to limit the |timeout|
74 * value, except to keep it positive.
75 */
76 }
2577
2678 /*
2779 * SSL_get_session() and SSL_get1_session() are problematic in TLS1.3 because,
82134 ss->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */
83135 ss->references = 1;
84136 ss->timeout = 60 * 5 + 4; /* 5 minute timeout by default */
85 ss->time = (unsigned long)time(NULL);
137 ss->time = time(NULL);
138 ssl_session_calculate_timeout(ss);
86139 ss->lock = CRYPTO_THREAD_lock_new();
87140 if (ss->lock == NULL) {
88141 ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
586639 goto err;
587640 }
588641
589 if (ret->timeout < (long)(time(NULL) - ret->time)) { /* timeout */
642 if (sess_timedout(time(NULL), ret)) {
590643 tsan_counter(&s->session_ctx->stats.sess_timeout);
591644 if (try_session_cache) {
592645 /* session was from the cache, so remove it */
687740 s = c;
688741 }
689742
690 /* Put at the head of the queue unless it is already in the cache */
691 if (s == NULL)
692 SSL_SESSION_list_add(ctx, c);
743 /* Adjust last used time, and add back into the cache at the appropriate spot */
744 if (ctx->session_cache_mode & SSL_SESS_CACHE_UPDATE_TIME) {
745 c->time = time(NULL);
746 ssl_session_calculate_timeout(c);
747 }
748 SSL_SESSION_list_add(ctx, c);
693749
694750 if (s != NULL) {
695751 /*
831887
832888 long SSL_SESSION_set_timeout(SSL_SESSION *s, long t)
833889 {
890 time_t new_timeout = (time_t)t;
891
892 if (s == NULL || t < 0)
893 return 0;
894 if (s->owner != NULL) {
895 if (!CRYPTO_THREAD_write_lock(s->owner->lock))
896 return 0;
897 s->timeout = new_timeout;
898 ssl_session_calculate_timeout(s);
899 SSL_SESSION_list_add(s->owner, s);
900 CRYPTO_THREAD_unlock(s->owner->lock);
901 } else {
902 s->timeout = new_timeout;
903 ssl_session_calculate_timeout(s);
904 }
905 return 1;
906 }
907
908 long SSL_SESSION_get_timeout(const SSL_SESSION *s)
909 {
834910 if (s == NULL)
835911 return 0;
836 s->timeout = t;
837 return 1;
838 }
839
840 long SSL_SESSION_get_timeout(const SSL_SESSION *s)
912 return (long)s->timeout;
913 }
914
915 long SSL_SESSION_get_time(const SSL_SESSION *s)
841916 {
842917 if (s == NULL)
843918 return 0;
844 return s->timeout;
845 }
846
847 long SSL_SESSION_get_time(const SSL_SESSION *s)
848 {
919 return (long)s->time;
920 }
921
922 long SSL_SESSION_set_time(SSL_SESSION *s, long t)
923 {
924 time_t new_time = (time_t)t;
925
849926 if (s == NULL)
850927 return 0;
851 return s->time;
852 }
853
854 long SSL_SESSION_set_time(SSL_SESSION *s, long t)
855 {
856 if (s == NULL)
857 return 0;
858 s->time = t;
928 if (s->owner != NULL) {
929 if (!CRYPTO_THREAD_write_lock(s->owner->lock))
930 return 0;
931 s->time = new_time;
932 ssl_session_calculate_timeout(s);
933 SSL_SESSION_list_add(s->owner, s);
934 CRYPTO_THREAD_unlock(s->owner->lock);
935 } else {
936 s->time = new_time;
937 ssl_session_calculate_timeout(s);
938 }
859939 return t;
860940 }
861941
10491129 return 0;
10501130 }
10511131
1052 typedef struct timeout_param_st {
1053 SSL_CTX *ctx;
1054 long time;
1055 LHASH_OF(SSL_SESSION) *cache;
1056 } TIMEOUT_PARAM;
1057
1058 static void timeout_cb(SSL_SESSION *s, TIMEOUT_PARAM *p)
1059 {
1060 if ((p->time == 0) || (p->time > (s->time + s->timeout))) { /* timeout */
1061 /*
1062 * The reason we don't call SSL_CTX_remove_session() is to save on
1063 * locking overhead
1064 */
1065 (void)lh_SSL_SESSION_delete(p->cache, s);
1066 SSL_SESSION_list_remove(p->ctx, s);
1067 s->not_resumable = 1;
1068 if (p->ctx->remove_session_cb != NULL)
1069 p->ctx->remove_session_cb(p->ctx, s);
1070 SSL_SESSION_free(s);
1071 }
1072 }
1073
1074 IMPLEMENT_LHASH_DOALL_ARG(SSL_SESSION, TIMEOUT_PARAM);
1075
10761132 void SSL_CTX_flush_sessions(SSL_CTX *s, long t)
10771133 {
1134 STACK_OF(SSL_SESSION) *sk;
1135 SSL_SESSION *current;
10781136 unsigned long i;
1079 TIMEOUT_PARAM tp;
1080
1081 tp.ctx = s;
1082 tp.cache = s->sessions;
1083 if (tp.cache == NULL)
1084 return;
1085 tp.time = t;
1137
10861138 if (!CRYPTO_THREAD_write_lock(s->lock))
10871139 return;
1140
1141 sk = sk_SSL_SESSION_new_null();
10881142 i = lh_SSL_SESSION_get_down_load(s->sessions);
10891143 lh_SSL_SESSION_set_down_load(s->sessions, 0);
1090 lh_SSL_SESSION_doall_TIMEOUT_PARAM(tp.cache, timeout_cb, &tp);
1144
1145 /*
1146 * Iterate over the list from the back (oldest), and stop
1147 * when a session can no longer be removed.
1148 * Add the session to a temporary list to be freed outside
1149 * the SSL_CTX lock.
1150 * But still do the remove_session_cb() within the lock.
1151 */
1152 while (s->session_cache_tail != NULL) {
1153 current = s->session_cache_tail;
1154 if (t == 0 || sess_timedout((time_t)t, current)) {
1155 lh_SSL_SESSION_delete(s->sessions, current);
1156 SSL_SESSION_list_remove(s, current);
1157 current->not_resumable = 1;
1158 if (s->remove_session_cb != NULL)
1159 s->remove_session_cb(s, current);
1160 /*
1161 * Throw the session on a stack, it's entirely plausible
1162 * that while freeing outside the critical section, the
1163 * session could be re-added, so avoid using the next/prev
1164 * pointers. If the stack failed to create, or the session
1165 * couldn't be put on the stack, just free it here
1166 */
1167 if (sk == NULL || !sk_SSL_SESSION_push(sk, current))
1168 SSL_SESSION_free(current);
1169 } else {
1170 break;
1171 }
1172 }
1173
10911174 lh_SSL_SESSION_set_down_load(s->sessions, i);
10921175 CRYPTO_THREAD_unlock(s->lock);
1176
1177 sk_SSL_SESSION_pop_free(sk, SSL_SESSION_free);
10931178 }
10941179
10951180 int ssl_clear_bad_session(SSL *s)
11311216 }
11321217 }
11331218 s->prev = s->next = NULL;
1219 s->owner = NULL;
11341220 }
11351221
11361222 static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s)
11371223 {
1224 SSL_SESSION *next;
1225
11381226 if ((s->next != NULL) && (s->prev != NULL))
11391227 SSL_SESSION_list_remove(ctx, s);
11401228
11441232 s->prev = (SSL_SESSION *)&(ctx->session_cache_head);
11451233 s->next = (SSL_SESSION *)&(ctx->session_cache_tail);
11461234 } else {
1147 s->next = ctx->session_cache_head;
1148 s->next->prev = s;
1149 s->prev = (SSL_SESSION *)&(ctx->session_cache_head);
1150 ctx->session_cache_head = s;
1151 }
1235 if (timeoutcmp(s, ctx->session_cache_head) >= 0) {
1236 /*
1237 * if we timeout after (or the same time as) the first
1238 * session, put us first - usual case
1239 */
1240 s->next = ctx->session_cache_head;
1241 s->next->prev = s;
1242 s->prev = (SSL_SESSION *)&(ctx->session_cache_head);
1243 ctx->session_cache_head = s;
1244 } else if (timeoutcmp(s, ctx->session_cache_tail) < 0) {
1245 /* if we timeout before the last session, put us last */
1246 s->prev = ctx->session_cache_tail;
1247 s->prev->next = s;
1248 s->next = (SSL_SESSION *)&(ctx->session_cache_tail);
1249 ctx->session_cache_tail = s;
1250 } else {
1251 /*
1252 * we timeout somewhere in-between - if there is only
1253 * one session in the cache it will be caught above
1254 */
1255 next = ctx->session_cache_head->next;
1256 while (next != (SSL_SESSION*)&(ctx->session_cache_tail)) {
1257 if (timeoutcmp(s, next) >= 0) {
1258 s->next = next;
1259 s->prev = next->prev;
1260 next->prev->next = s;
1261 next->prev = s;
1262 break;
1263 }
1264 next = next->next;
1265 }
1266 }
1267 }
1268 s->owner = ctx;
11521269 }
11531270
11541271 void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx,
25092509 s->session = new_sess;
25102510 }
25112511
2512 /*
2513 * Technically the cast to long here is not guaranteed by the C standard -
2514 * but we use it elsewhere, so this should be ok.
2515 */
2516 s->session->time = (long)time(NULL);
2512 s->session->time = time(NULL);
2513 ssl_session_calculate_timeout(s->session);
25172514
25182515 OPENSSL_free(s->session->ext.tick);
25192516 s->session->ext.tick = NULL;
36323632 */
36333633 if (!WPACKET_put_bytes_u32(pkt,
36343634 (s->hit && !SSL_IS_TLS13(s))
3635 ? 0 : s->session->timeout)) {
3635 ? 0 : (uint32_t)s->session->timeout)) {
36363636 SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
36373637 return 0;
36383638 }
39293929 }
39303930 s->session->master_key_length = hashlen;
39313931
3932 s->session->time = (long)time(NULL);
3932 s->session->time = time(NULL);
3933 ssl_session_calculate_timeout(s->session);
39333934 if (s->s3.alpn_selected != NULL) {
39343935 OPENSSL_free(s->session->ext.alpn_selected);
39353936 s->session->ext.alpn_selected =
81218121 }
81228122 #endif /* OPENSSL_NO_TLS1_2 */
81238123
8124 static int test_session_timeout(int test)
8125 {
8126 /*
8127 * Test session ordering and timeout
8128 * Can't explicitly test performance of the new code,
8129 * but can test to see if the ordering of the sessions
8130 * are correct, and they they are removed as expected
8131 */
8132 SSL_SESSION *early = NULL;
8133 SSL_SESSION *middle = NULL;
8134 SSL_SESSION *late = NULL;
8135 SSL_CTX *ctx;
8136 int testresult = 0;
8137 long now = (long)time(NULL);
8138 #define TIMEOUT 10
8139
8140 if (!TEST_ptr(ctx = SSL_CTX_new_ex(libctx, NULL, TLS_method()))
8141 || !TEST_ptr(early = SSL_SESSION_new())
8142 || !TEST_ptr(middle = SSL_SESSION_new())
8143 || !TEST_ptr(late = SSL_SESSION_new()))
8144 goto end;
8145
8146 /* assign unique session ids */
8147 early->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
8148 memset(early->session_id, 1, SSL3_SSL_SESSION_ID_LENGTH);
8149 middle->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
8150 memset(middle->session_id, 2, SSL3_SSL_SESSION_ID_LENGTH);
8151 late->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
8152 memset(late->session_id, 3, SSL3_SSL_SESSION_ID_LENGTH);
8153
8154 if (!TEST_int_eq(SSL_CTX_add_session(ctx, early), 1)
8155 || !TEST_int_eq(SSL_CTX_add_session(ctx, middle), 1)
8156 || !TEST_int_eq(SSL_CTX_add_session(ctx, late), 1))
8157 goto end;
8158
8159 /* Make sure they are all added */
8160 if (!TEST_ptr(early->prev)
8161 || !TEST_ptr(middle->prev)
8162 || !TEST_ptr(late->prev))
8163 goto end;
8164
8165 if (!TEST_int_ne(SSL_SESSION_set_time(early, now - 10), 0)
8166 || !TEST_int_ne(SSL_SESSION_set_time(middle, now), 0)
8167 || !TEST_int_ne(SSL_SESSION_set_time(late, now + 10), 0))
8168 goto end;
8169
8170 if (!TEST_int_ne(SSL_SESSION_set_timeout(early, TIMEOUT), 0)
8171 || !TEST_int_ne(SSL_SESSION_set_timeout(middle, TIMEOUT), 0)
8172 || !TEST_int_ne(SSL_SESSION_set_timeout(late, TIMEOUT), 0))
8173 goto end;
8174
8175 /* Make sure they are all still there */
8176 if (!TEST_ptr(early->prev)
8177 || !TEST_ptr(middle->prev)
8178 || !TEST_ptr(late->prev))
8179 goto end;
8180
8181 /* Make sure they are in the expected order */
8182 if (!TEST_ptr_eq(late->next, middle)
8183 || !TEST_ptr_eq(middle->next, early)
8184 || !TEST_ptr_eq(early->prev, middle)
8185 || !TEST_ptr_eq(middle->prev, late))
8186 goto end;
8187
8188 /* This should remove "early" */
8189 SSL_CTX_flush_sessions(ctx, now + TIMEOUT - 1);
8190 if (!TEST_ptr_null(early->prev)
8191 || !TEST_ptr(middle->prev)
8192 || !TEST_ptr(late->prev))
8193 goto end;
8194
8195 /* This should remove "middle" */
8196 SSL_CTX_flush_sessions(ctx, now + TIMEOUT + 1);
8197 if (!TEST_ptr_null(early->prev)
8198 || !TEST_ptr_null(middle->prev)
8199 || !TEST_ptr(late->prev))
8200 goto end;
8201
8202 /* This should remove "late" */
8203 SSL_CTX_flush_sessions(ctx, now + TIMEOUT + 11);
8204 if (!TEST_ptr_null(early->prev)
8205 || !TEST_ptr_null(middle->prev)
8206 || !TEST_ptr_null(late->prev))
8207 goto end;
8208
8209 /* Add them back in again */
8210 if (!TEST_int_eq(SSL_CTX_add_session(ctx, early), 1)
8211 || !TEST_int_eq(SSL_CTX_add_session(ctx, middle), 1)
8212 || !TEST_int_eq(SSL_CTX_add_session(ctx, late), 1))
8213 goto end;
8214
8215 /* Make sure they are all added */
8216 if (!TEST_ptr(early->prev)
8217 || !TEST_ptr(middle->prev)
8218 || !TEST_ptr(late->prev))
8219 goto end;
8220
8221 /* This should remove all of them */
8222 SSL_CTX_flush_sessions(ctx, 0);
8223 if (!TEST_ptr_null(early->prev)
8224 || !TEST_ptr_null(middle->prev)
8225 || !TEST_ptr_null(late->prev))
8226 goto end;
8227
8228 (void)SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_UPDATE_TIME
8229 | SSL_CTX_get_session_cache_mode(ctx));
8230
8231 /* make sure |now| is NOT equal to the current time */
8232 now -= 10;
8233 if (!TEST_int_ne(SSL_SESSION_set_time(early, now), 0)
8234 || !TEST_int_eq(SSL_CTX_add_session(ctx, early), 1)
8235 || !TEST_long_ne(SSL_SESSION_get_time(early), now))
8236 goto end;
8237
8238 testresult = 1;
8239 end:
8240 SSL_CTX_free(ctx);
8241 SSL_SESSION_free(early);
8242 SSL_SESSION_free(middle);
8243 SSL_SESSION_free(late);
8244 return testresult;
8245 }
8246
81248247 /*
81258248 * Test 0: Client sets servername and server acknowledges it (TLSv1.2)
81268249 * Test 1: Client sets servername and server does not acknowledge it (TLSv1.2)
92869409 #endif
92879410 ADD_TEST(test_inherit_verify_param);
92889411 ADD_TEST(test_set_alpn);
9412 ADD_ALL_TESTS(test_session_timeout, 1);
92899413 return 1;
92909414
92919415 err: