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,©)) 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