xref: /openbsd-src/lib/libssl/ssl_sess.c (revision 62a742911104f98b9185b2c6b6007d9b1c36396c)
1 /* ssl/ssl_sess.c */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@cryptsoft.com).
7  * The implementation was written so as to conform with Netscapes SSL.
8  *
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15  *
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@cryptsoft.com)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  *
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  *
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58 
59 #include <stdio.h>
60 #include "lhash.h"
61 #include "rand.h"
62 #include "ssl_locl.h"
63 
64 #ifndef NOPROTO
65 static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s);
66 static void SSL_SESSION_list_add(SSL_CTX *ctx,SSL_SESSION *s);
67 #else
68 static void SSL_SESSION_list_remove();
69 static void SSL_SESSION_list_add();
70 #endif
71 
72 static ssl_session_num=0;
73 static STACK *ssl_session_meth=NULL;
74 
75 SSL_SESSION *SSL_get_session(ssl)
76 SSL *ssl;
77 	{
78 	return(ssl->session);
79 	}
80 
81 int SSL_SESSION_get_ex_new_index(argl,argp,new_func,dup_func,free_func)
82 long argl;
83 char *argp;
84 int (*new_func)();
85 int (*dup_func)();
86 void (*free_func)();
87         {
88         ssl_session_num++;
89         return(CRYPTO_get_ex_new_index(ssl_session_num-1,
90 		&ssl_session_meth,
91                 argl,argp,new_func,dup_func,free_func));
92         }
93 
94 int SSL_SESSION_set_ex_data(s,idx,arg)
95 SSL_SESSION *s;
96 int idx;
97 char *arg;
98 	{
99 	return(CRYPTO_set_ex_data(&s->ex_data,idx,arg));
100 	}
101 
102 char *SSL_SESSION_get_ex_data(s,idx)
103 SSL_SESSION *s;
104 int idx;
105 	{
106 	return(CRYPTO_get_ex_data(&s->ex_data,idx));
107 	}
108 
109 SSL_SESSION *SSL_SESSION_new()
110 	{
111 	SSL_SESSION *ss;
112 
113 	ss=(SSL_SESSION *)Malloc(sizeof(SSL_SESSION));
114 	if (ss == NULL)
115 		{
116 		SSLerr(SSL_F_SSL_SESSION_NEW,ERR_R_MALLOC_FAILURE);
117 		return(0);
118 		}
119 	memset(ss,0,sizeof(SSL_SESSION));
120 
121 	ss->references=1;
122 	ss->timeout=60*5+4; /* 5 minute timeout by default */
123 	ss->time=time(NULL);
124 	ss->prev=NULL;
125 	ss->next=NULL;
126 	CRYPTO_new_ex_data(ssl_session_meth,(char *)ss,&ss->ex_data);
127 	return(ss);
128 	}
129 
130 int ssl_get_new_session(s, session)
131 SSL *s;
132 int session;
133 	{
134 	SSL_SESSION *ss=NULL;
135 
136 	if ((ss=SSL_SESSION_new()) == NULL) return(0);
137 
138 	/* If the context has a default timeout, use it */
139 	if (s->ctx->session_timeout != 0)
140 		ss->timeout=SSL_get_default_timeout(s);
141 
142 	if (s->session != NULL)
143 		{
144 		SSL_SESSION_free(s->session);
145 		s->session=NULL;
146 		}
147 
148 	if (session)
149 		{
150 		if (s->version == SSL2_CLIENT_VERSION)
151 			{
152 			ss->ssl_version=SSL2_VERSION;
153 			ss->session_id_length=SSL2_SSL_SESSION_ID_LENGTH;
154 			}
155 		else if (s->version == SSL3_VERSION)
156 			{
157 			ss->ssl_version=SSL3_VERSION;
158 			ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
159 			}
160 		else if (s->version == TLS1_VERSION)
161 			{
162 			ss->ssl_version=TLS1_VERSION;
163 			ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
164 			}
165 		else
166 			{
167 			SSLerr(SSL_F_SSL_GET_NEW_SESSION,SSL_R_UNSUPPORTED_SSL_VERSION);
168 			SSL_SESSION_free(ss);
169 			return(0);
170 			}
171 
172 		for (;;)
173 			{
174 			SSL_SESSION *r;
175 
176 			RAND_bytes(ss->session_id,ss->session_id_length);
177 			CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
178 			r=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,
179 				(char *)ss);
180 			CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
181 			if (r == NULL) break;
182 			/* else - woops a session_id match */
183 			}
184 		}
185 	else
186 		{
187 		ss->session_id_length=0;
188 		}
189 
190 	s->session=ss;
191 	ss->ssl_version=s->version;
192 
193 	return(1);
194 	}
195 
196 int ssl_get_prev_session(s,session_id,len)
197 SSL *s;
198 unsigned char *session_id;
199 int len;
200 	{
201 	SSL_SESSION *ret=NULL,data;
202 
203 	/* conn_init();*/
204 	data.ssl_version=s->version;
205 	data.session_id_length=len;
206 	if (len > SSL_MAX_SSL_SESSION_ID_LENGTH)
207 		return(0);
208 	memcpy(data.session_id,session_id,len);;
209 
210 	if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
211 		{
212 		CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
213 		ret=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,(char *)&data);
214 		CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
215 		}
216 
217 	if (ret == NULL)
218 		{
219 		int copy=1;
220 
221 		s->ctx->sess_miss++;
222 		ret=NULL;
223 		if ((s->ctx->get_session_cb != NULL) &&
224 			((ret=s->ctx->get_session_cb(s,session_id,len,&copy))
225 				!= NULL))
226 			{
227 			s->ctx->sess_cb_hit++;
228 
229 			/* The following should not return 1, otherwise,
230 			 * things are very strange */
231 			SSL_CTX_add_session(s->ctx,ret);
232 			/* auto free it */
233 			if (!copy)
234 				SSL_SESSION_free(ret);
235 			}
236 		if (ret == NULL) return(0);
237 		}
238 
239 	if (ret->cipher == NULL)
240 		{
241 		char buf[5],*p;
242 		unsigned long l;
243 
244 		p=buf;
245 		l=ret->cipher_id;
246 		l2n(l,p);
247 		if ((ret->ssl_version>>8) == SSL3_VERSION_MAJOR)
248 			ret->cipher=ssl_get_cipher_by_char(s,&(buf[2]));
249 		else
250 			ret->cipher=ssl_get_cipher_by_char(s,&(buf[1]));
251 		if (ret->cipher == NULL)
252 			return(0);
253 		}
254 
255 	/* If a thread got the session, then 'swaped', and another got
256 	 * it and then due to a time-out decided to 'Free' it we could
257 	 * be in trouble.  So I'll increment it now, then double decrement
258 	 * later - am I speaking rubbish?. */
259 	CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION);
260 
261 	if ((long)(ret->time+ret->timeout) < (long)time(NULL)) /* timeout */
262 		{
263 		s->ctx->sess_timeout++;
264 		/* remove it from the cache */
265 		SSL_CTX_remove_session(s->ctx,ret);
266 		SSL_SESSION_free(ret);		/* again to actually Free it */
267 		return(0);
268 		}
269 
270 	s->ctx->sess_hit++;
271 
272 	/* ret->time=time(NULL); */ /* rezero timeout? */
273 	/* again, just leave the session
274 	 * if it is the same session, we have just incremented and
275 	 * then decremented the reference count :-) */
276 	if (s->session != NULL)
277 		SSL_SESSION_free(s->session);
278 	s->session=ret;
279 	return(1);
280 	}
281 
282 int SSL_CTX_add_session(ctx,c)
283 SSL_CTX *ctx;
284 SSL_SESSION *c;
285 	{
286 	int ret=0;
287 	SSL_SESSION *s;
288 
289 	/* conn_init(); */
290 	CRYPTO_add(&c->references,1,CRYPTO_LOCK_SSL_SESSION);
291 
292 	CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
293 	s=(SSL_SESSION *)lh_insert(ctx->sessions,(char *)c);
294 
295 	/* Put on the end of the queue unless it is already in the cache */
296 	if (s == NULL)
297 		SSL_SESSION_list_add(ctx,c);
298 
299 	/* If the same session if is being 're-added', Free the old
300 	 * one when the last person stops using it.
301 	 * This will also work if it is alread in the cache.
302 	 * The references will go up and then down :-) */
303 	if (s != NULL)
304 		{
305 		SSL_SESSION_free(s);
306 		ret=0;
307 		}
308 	else
309 		{
310 		ret=1;
311 
312 		if (SSL_CTX_sess_get_cache_size(ctx) > 0)
313 			{
314 			while (SSL_CTX_sess_number(ctx) >
315 				SSL_CTX_sess_get_cache_size(ctx))
316 				{
317 				if (!SSL_CTX_remove_session(ctx,
318 					ctx->session_cache_tail))
319 					break;
320 				else
321 					ctx->sess_cache_full++;
322 				}
323 			}
324 		}
325 	CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
326 	return(ret);
327 	}
328 
329 int SSL_CTX_remove_session(ctx,c)
330 SSL_CTX *ctx;
331 SSL_SESSION *c;
332 	{
333 	SSL_SESSION *r;
334 	int ret=0;
335 
336 	if ((c != NULL) && (c->session_id_length != 0))
337 		{
338 		CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
339 		r=(SSL_SESSION *)lh_delete(ctx->sessions,(char *)c);
340 		if (r != NULL)
341 			{
342 			ret=1;
343 			SSL_SESSION_list_remove(ctx,c);
344 			}
345 
346 		CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
347 
348 		if (ret)
349 			{
350 			r->not_resumable=1;
351 			if (ctx->remove_session_cb != NULL)
352 				ctx->remove_session_cb(ctx,r);
353 			SSL_SESSION_free(r);
354 			}
355 		}
356 	else
357 		ret=0;
358 	return(ret);
359 	}
360 
361 void SSL_SESSION_free(ss)
362 SSL_SESSION *ss;
363 	{
364 	int i;
365 
366 	i=CRYPTO_add(&ss->references,-1,CRYPTO_LOCK_SSL_SESSION);
367 #ifdef REF_PRINT
368 	REF_PRINT("SSL_SESSION",ss);
369 #endif
370 	if (i > 0) return;
371 #ifdef REF_CHECK
372 	if (i < 0)
373 		{
374 		fprintf(stderr,"SSL_SESSION_free, bad reference count\n");
375 		abort(); /* ok */
376 		}
377 #endif
378 
379 	CRYPTO_free_ex_data(ssl_session_meth,(char *)ss,&ss->ex_data);
380 
381 	memset(ss->key_arg,0,SSL_MAX_KEY_ARG_LENGTH);
382 	memset(ss->master_key,0,SSL_MAX_MASTER_KEY_LENGTH);
383 	memset(ss->session_id,0,SSL_MAX_SSL_SESSION_ID_LENGTH);
384 	if (ss->cert != NULL) ssl_cert_free(ss->cert);
385 	if (ss->peer != NULL) X509_free(ss->peer);
386 	if (ss->ciphers != NULL) sk_free(ss->ciphers);
387 	memset(ss,0,sizeof(*ss));
388 	Free(ss);
389 	}
390 
391 int SSL_set_session(s, session)
392 SSL *s;
393 SSL_SESSION *session;
394 	{
395 	int ret=0;
396 	SSL_METHOD *meth;
397 
398 	if (session != NULL)
399 		{
400 		meth=s->ctx->method->get_ssl_method(session->ssl_version);
401 		if (meth == NULL)
402 			meth=s->method->get_ssl_method(session->ssl_version);
403 		if (meth == NULL)
404 			{
405 			SSLerr(SSL_F_SSL_SET_SESSION,SSL_R_UNABLE_TO_FIND_SSL_METHOD);
406 			return(0);
407 			}
408 
409 		if (meth != s->method)
410 			{
411 			if (!SSL_set_ssl_method(s,meth))
412 				return(0);
413 			session->timeout=SSL_get_default_timeout(s);
414 			}
415 
416 		/* CRYPTO_w_lock(CRYPTO_LOCK_SSL);*/
417 		CRYPTO_add(&session->references,1,CRYPTO_LOCK_SSL_SESSION);
418 		if (s->session != NULL)
419 			SSL_SESSION_free(s->session);
420 		s->session=session;
421 		/* CRYPTO_w_unlock(CRYPTO_LOCK_SSL);*/
422 		ret=1;
423 		}
424 	else
425 		{
426 		if (s->session != NULL)
427 			{
428 			SSL_SESSION_free(s->session);
429 			s->session=NULL;
430 			}
431 		}
432 	return(ret);
433 	}
434 
435 long SSL_SESSION_set_timeout(s,t)
436 SSL_SESSION *s;
437 long t;
438 	{
439 	if (s == NULL) return(0);
440 	s->timeout=t;
441 	return(1);
442 	}
443 
444 long SSL_SESSION_get_timeout(s)
445 SSL_SESSION *s;
446 	{
447 	if (s == NULL) return(0);
448 	return(s->timeout);
449 	}
450 
451 long SSL_SESSION_get_time(s)
452 SSL_SESSION *s;
453 	{
454 	if (s == NULL) return(0);
455 	return(s->time);
456 	}
457 
458 long SSL_SESSION_set_time(s,t)
459 SSL_SESSION *s;
460 long t;
461 	{
462 	if (s == NULL) return(0);
463 	s->time=t;
464 	return(t);
465 	}
466 
467 typedef struct timeout_param_st
468 	{
469 	SSL_CTX *ctx;
470 	long time;
471 	LHASH *cache;
472 	} TIMEOUT_PARAM;
473 
474 static void timeout(s,p)
475 SSL_SESSION *s;
476 TIMEOUT_PARAM *p;
477 	{
478 	if ((p->time == 0) || (p->time > (s->time+s->timeout))) /* timeout */
479 		{
480 		/* The reason we don't call SSL_CTX_remove_session() is to
481 		 * save on locking overhead */
482 		lh_delete(p->cache,(char *)s);
483 		SSL_SESSION_list_remove(p->ctx,s);
484 		s->not_resumable=1;
485 		if (p->ctx->remove_session_cb != NULL)
486 			p->ctx->remove_session_cb(p->ctx,s);
487 		SSL_SESSION_free(s);
488 		}
489 	}
490 
491 void SSL_CTX_flush_sessions(s,t)
492 SSL_CTX *s;
493 long t;
494 	{
495 	unsigned long i;
496 	TIMEOUT_PARAM tp;
497 
498 	tp.ctx=s;
499 	tp.cache=SSL_CTX_sessions(s);
500 	if (tp.cache == NULL) return;
501 	tp.time=t;
502 	CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
503 	i=tp.cache->down_load;
504 	tp.cache->down_load=0;
505 	lh_doall_arg(tp.cache,(void (*)())timeout,(char *)&tp);
506 	tp.cache->down_load=i;
507 	CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
508 	}
509 
510 int ssl_clear_bad_session(s)
511 SSL *s;
512 	{
513 	if (	(s->session != NULL) &&
514 		!(s->shutdown & SSL_SENT_SHUTDOWN) &&
515 		!(SSL_in_init(s) || SSL_in_before(s)))
516 		{
517 		SSL_CTX_remove_session(s->ctx,s->session);
518 		return(1);
519 		}
520 	else
521 		return(0);
522 	}
523 
524 /* locked by SSL_CTX in the calling function */
525 static void SSL_SESSION_list_remove(ctx,s)
526 SSL_CTX *ctx;
527 SSL_SESSION *s;
528 	{
529 	if ((s->next == NULL) || (s->prev == NULL)) return;
530 
531 	if (s->next == (SSL_SESSION *)&(ctx->session_cache_tail))
532 		{ /* last element in list */
533 		if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head))
534 			{ /* only one element in list */
535 			ctx->session_cache_head=NULL;
536 			ctx->session_cache_tail=NULL;
537 			}
538 		else
539 			{
540 			ctx->session_cache_tail=s->prev;
541 			s->prev->next=(SSL_SESSION *)&(ctx->session_cache_tail);
542 			}
543 		}
544 	else
545 		{
546 		if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head))
547 			{ /* first element in list */
548 			ctx->session_cache_head=s->next;
549 			s->next->prev=(SSL_SESSION *)&(ctx->session_cache_head);
550 			}
551 		else
552 			{ /* middle of list */
553 			s->next->prev=s->prev;
554 			s->prev->next=s->next;
555 			}
556 		}
557 	s->prev=s->next=NULL;
558 	}
559 
560 static void SSL_SESSION_list_add(ctx,s)
561 SSL_CTX *ctx;
562 SSL_SESSION *s;
563 	{
564 	if ((s->next != NULL) && (s->prev != NULL))
565 		SSL_SESSION_list_remove(ctx,s);
566 
567 	if (ctx->session_cache_head == NULL)
568 		{
569 		ctx->session_cache_head=s;
570 		ctx->session_cache_tail=s;
571 		s->prev=(SSL_SESSION *)&(ctx->session_cache_head);
572 		s->next=(SSL_SESSION *)&(ctx->session_cache_tail);
573 		}
574 	else
575 		{
576 		s->next=ctx->session_cache_head;
577 		s->next->prev=s;
578 		s->prev=(SSL_SESSION *)&(ctx->session_cache_head);
579 		ctx->session_cache_head=s;
580 		}
581 	}
582 
583