diff options
Diffstat (limited to 'src/lib/libssl/ssl_sess.c')
-rw-r--r-- | src/lib/libssl/ssl_sess.c | 89 |
1 files changed, 66 insertions, 23 deletions
diff --git a/src/lib/libssl/ssl_sess.c b/src/lib/libssl/ssl_sess.c index 681499f08a..9e01f72753 100644 --- a/src/lib/libssl/ssl_sess.c +++ b/src/lib/libssl/ssl_sess.c | |||
@@ -65,15 +65,31 @@ static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s); | |||
65 | static void SSL_SESSION_list_add(SSL_CTX *ctx,SSL_SESSION *s); | 65 | static void SSL_SESSION_list_add(SSL_CTX *ctx,SSL_SESSION *s); |
66 | static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck); | 66 | static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck); |
67 | static int ssl_session_num=0; | 67 | static int ssl_session_num=0; |
68 | static STACK *ssl_session_meth=NULL; | 68 | static STACK_OF(CRYPTO_EX_DATA_FUNCS) *ssl_session_meth=NULL; |
69 | 69 | ||
70 | SSL_SESSION *SSL_get_session(SSL *ssl) | 70 | SSL_SESSION *SSL_get_session(SSL *ssl) |
71 | /* aka SSL_get0_session; gets 0 objects, just returns a copy of the pointer */ | ||
71 | { | 72 | { |
72 | return(ssl->session); | 73 | return(ssl->session); |
73 | } | 74 | } |
74 | 75 | ||
75 | int SSL_SESSION_get_ex_new_index(long argl, char *argp, int (*new_func)(), | 76 | SSL_SESSION *SSL_get1_session(SSL *ssl) |
76 | int (*dup_func)(), void (*free_func)()) | 77 | /* variant of SSL_get_session: caller really gets something */ |
78 | { | ||
79 | SSL_SESSION *sess; | ||
80 | /* Need to lock this all up rather than just use CRYPTO_add so that | ||
81 | * somebody doesn't free ssl->session between when we check it's | ||
82 | * non-null and when we up the reference count. */ | ||
83 | CRYPTO_r_lock(CRYPTO_LOCK_SSL_SESSION); | ||
84 | sess = ssl->session; | ||
85 | if(sess) | ||
86 | sess->references++; | ||
87 | CRYPTO_r_unlock(CRYPTO_LOCK_SSL_SESSION); | ||
88 | return(sess); | ||
89 | } | ||
90 | |||
91 | int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, | ||
92 | CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) | ||
77 | { | 93 | { |
78 | ssl_session_num++; | 94 | ssl_session_num++; |
79 | return(CRYPTO_get_ex_new_index(ssl_session_num-1, | 95 | return(CRYPTO_get_ex_new_index(ssl_session_num-1, |
@@ -103,13 +119,14 @@ SSL_SESSION *SSL_SESSION_new(void) | |||
103 | } | 119 | } |
104 | memset(ss,0,sizeof(SSL_SESSION)); | 120 | memset(ss,0,sizeof(SSL_SESSION)); |
105 | 121 | ||
122 | ss->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */ | ||
106 | ss->references=1; | 123 | ss->references=1; |
107 | ss->timeout=60*5+4; /* 5 minute timeout by default */ | 124 | ss->timeout=60*5+4; /* 5 minute timeout by default */ |
108 | ss->time=time(NULL); | 125 | ss->time=time(NULL); |
109 | ss->prev=NULL; | 126 | ss->prev=NULL; |
110 | ss->next=NULL; | 127 | ss->next=NULL; |
111 | ss->compress_meth=0; | 128 | ss->compress_meth=0; |
112 | CRYPTO_new_ex_data(ssl_session_meth,(char *)ss,&ss->ex_data); | 129 | CRYPTO_new_ex_data(ssl_session_meth,ss,&ss->ex_data); |
113 | return(ss); | 130 | return(ss); |
114 | } | 131 | } |
115 | 132 | ||
@@ -161,15 +178,20 @@ int ssl_get_new_session(SSL *s, int session) | |||
161 | { | 178 | { |
162 | SSL_SESSION *r; | 179 | SSL_SESSION *r; |
163 | 180 | ||
164 | RAND_bytes(ss->session_id,ss->session_id_length); | 181 | RAND_pseudo_bytes(ss->session_id,ss->session_id_length); |
165 | CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); | 182 | CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); |
166 | r=(SSL_SESSION *)lh_retrieve(s->ctx->sessions, | 183 | r=(SSL_SESSION *)lh_retrieve(s->ctx->sessions, ss); |
167 | (char *)ss); | ||
168 | CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); | 184 | CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); |
169 | if (r == NULL) break; | 185 | if (r == NULL) break; |
170 | /* else - woops a session_id match */ | 186 | /* else - woops a session_id match */ |
171 | /* XXX should also check external cache! | 187 | /* XXX We should also check the external cache -- |
172 | * (But the probability of a collision is negligible, anyway...) */ | 188 | * but the probability of a collision is negligible, and |
189 | * we could not prevent the concurrent creation of sessions | ||
190 | * with identical IDs since we currently don't have means | ||
191 | * to atomically check whether a session ID already exists | ||
192 | * and make a reservation for it if it does not | ||
193 | * (this problem applies to the internal cache as well). | ||
194 | */ | ||
173 | } | 195 | } |
174 | } | 196 | } |
175 | else | 197 | else |
@@ -181,6 +203,7 @@ int ssl_get_new_session(SSL *s, int session) | |||
181 | ss->sid_ctx_length=s->sid_ctx_length; | 203 | ss->sid_ctx_length=s->sid_ctx_length; |
182 | s->session=ss; | 204 | s->session=ss; |
183 | ss->ssl_version=s->version; | 205 | ss->ssl_version=s->version; |
206 | ss->verify_result = X509_V_OK; | ||
184 | 207 | ||
185 | return(1); | 208 | return(1); |
186 | } | 209 | } |
@@ -192,7 +215,6 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len) | |||
192 | SSL_SESSION *ret=NULL,data; | 215 | SSL_SESSION *ret=NULL,data; |
193 | int fatal = 0; | 216 | int fatal = 0; |
194 | 217 | ||
195 | /* conn_init();*/ | ||
196 | data.ssl_version=s->version; | 218 | data.ssl_version=s->version; |
197 | data.session_id_length=len; | 219 | data.session_id_length=len; |
198 | if (len > SSL_MAX_SSL_SESSION_ID_LENGTH) | 220 | if (len > SSL_MAX_SSL_SESSION_ID_LENGTH) |
@@ -202,7 +224,7 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len) | |||
202 | if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) | 224 | if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) |
203 | { | 225 | { |
204 | CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); | 226 | CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); |
205 | ret=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,(char *)&data); | 227 | ret=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,&data); |
206 | if (ret != NULL) | 228 | if (ret != NULL) |
207 | /* don't allow other threads to steal it: */ | 229 | /* don't allow other threads to steal it: */ |
208 | CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); | 230 | CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); |
@@ -311,6 +333,7 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len) | |||
311 | if (s->session != NULL) | 333 | if (s->session != NULL) |
312 | SSL_SESSION_free(s->session); | 334 | SSL_SESSION_free(s->session); |
313 | s->session=ret; | 335 | s->session=ret; |
336 | s->verify_result = s->session->verify_result; | ||
314 | return(1); | 337 | return(1); |
315 | 338 | ||
316 | err: | 339 | err: |
@@ -327,27 +350,47 @@ int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) | |||
327 | int ret=0; | 350 | int ret=0; |
328 | SSL_SESSION *s; | 351 | SSL_SESSION *s; |
329 | 352 | ||
330 | /* conn_init(); */ | 353 | /* add just 1 reference count for the SSL_CTX's session cache |
354 | * even though it has two ways of access: each session is in a | ||
355 | * doubly linked list and an lhash */ | ||
331 | CRYPTO_add(&c->references,1,CRYPTO_LOCK_SSL_SESSION); | 356 | CRYPTO_add(&c->references,1,CRYPTO_LOCK_SSL_SESSION); |
357 | /* if session c is in already in cache, we take back the increment later */ | ||
332 | 358 | ||
333 | CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); | 359 | CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); |
334 | s=(SSL_SESSION *)lh_insert(ctx->sessions,(char *)c); | 360 | s=(SSL_SESSION *)lh_insert(ctx->sessions,c); |
335 | 361 | ||
336 | /* Put on the end of the queue unless it is already in the cache */ | 362 | /* s != NULL iff we already had a session with the given PID. |
363 | * In this case, s == c should hold (then we did not really modify | ||
364 | * ctx->sessions), or we're in trouble. */ | ||
365 | if (s != NULL && s != c) | ||
366 | { | ||
367 | /* We *are* in trouble ... */ | ||
368 | SSL_SESSION_list_remove(ctx,s); | ||
369 | SSL_SESSION_free(s); | ||
370 | /* ... so pretend the other session did not exist in cache | ||
371 | * (we cannot handle two SSL_SESSION structures with identical | ||
372 | * session ID in the same cache, which could happen e.g. when | ||
373 | * two threads concurrently obtain the same session from an external | ||
374 | * cache) */ | ||
375 | s = NULL; | ||
376 | } | ||
377 | |||
378 | /* Put at the head of the queue unless it is already in the cache */ | ||
337 | if (s == NULL) | 379 | if (s == NULL) |
338 | SSL_SESSION_list_add(ctx,c); | 380 | SSL_SESSION_list_add(ctx,c); |
339 | 381 | ||
340 | /* If the same session if is being 're-added', Free the old | ||
341 | * one when the last person stops using it. | ||
342 | * This will also work if it is alread in the cache. | ||
343 | * The references will go up and then down :-) */ | ||
344 | if (s != NULL) | 382 | if (s != NULL) |
345 | { | 383 | { |
346 | SSL_SESSION_free(s); | 384 | /* existing cache entry -- decrement previously incremented reference |
385 | * count because it already takes into account the cache */ | ||
386 | |||
387 | SSL_SESSION_free(s); /* s == c */ | ||
347 | ret=0; | 388 | ret=0; |
348 | } | 389 | } |
349 | else | 390 | else |
350 | { | 391 | { |
392 | /* new cache entry -- remove old ones if cache has become too large */ | ||
393 | |||
351 | ret=1; | 394 | ret=1; |
352 | 395 | ||
353 | if (SSL_CTX_sess_get_cache_size(ctx) > 0) | 396 | if (SSL_CTX_sess_get_cache_size(ctx) > 0) |
@@ -380,7 +423,7 @@ static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck) | |||
380 | if ((c != NULL) && (c->session_id_length != 0)) | 423 | if ((c != NULL) && (c->session_id_length != 0)) |
381 | { | 424 | { |
382 | if(lck) CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); | 425 | if(lck) CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); |
383 | r=(SSL_SESSION *)lh_delete(ctx->sessions,(char *)c); | 426 | r=(SSL_SESSION *)lh_delete(ctx->sessions,c); |
384 | if (r != NULL) | 427 | if (r != NULL) |
385 | { | 428 | { |
386 | ret=1; | 429 | ret=1; |
@@ -422,7 +465,7 @@ void SSL_SESSION_free(SSL_SESSION *ss) | |||
422 | } | 465 | } |
423 | #endif | 466 | #endif |
424 | 467 | ||
425 | CRYPTO_free_ex_data(ssl_session_meth,(char *)ss,&ss->ex_data); | 468 | CRYPTO_free_ex_data(ssl_session_meth,ss,&ss->ex_data); |
426 | 469 | ||
427 | memset(ss->key_arg,0,SSL_MAX_KEY_ARG_LENGTH); | 470 | memset(ss->key_arg,0,SSL_MAX_KEY_ARG_LENGTH); |
428 | memset(ss->master_key,0,SSL_MAX_MASTER_KEY_LENGTH); | 471 | memset(ss->master_key,0,SSL_MAX_MASTER_KEY_LENGTH); |
@@ -541,7 +584,7 @@ static void timeout(SSL_SESSION *s, TIMEOUT_PARAM *p) | |||
541 | { | 584 | { |
542 | /* The reason we don't call SSL_CTX_remove_session() is to | 585 | /* The reason we don't call SSL_CTX_remove_session() is to |
543 | * save on locking overhead */ | 586 | * save on locking overhead */ |
544 | lh_delete(p->cache,(char *)s); | 587 | lh_delete(p->cache,s); |
545 | SSL_SESSION_list_remove(p->ctx,s); | 588 | SSL_SESSION_list_remove(p->ctx,s); |
546 | s->not_resumable=1; | 589 | s->not_resumable=1; |
547 | if (p->ctx->remove_session_cb != NULL) | 590 | if (p->ctx->remove_session_cb != NULL) |
@@ -562,7 +605,7 @@ void SSL_CTX_flush_sessions(SSL_CTX *s, long t) | |||
562 | CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); | 605 | CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); |
563 | i=tp.cache->down_load; | 606 | i=tp.cache->down_load; |
564 | tp.cache->down_load=0; | 607 | tp.cache->down_load=0; |
565 | lh_doall_arg(tp.cache,(void (*)())timeout,(char *)&tp); | 608 | lh_doall_arg(tp.cache,(void (*)())timeout,&tp); |
566 | tp.cache->down_load=i; | 609 | tp.cache->down_load=i; |
567 | CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); | 610 | CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); |
568 | } | 611 | } |