1*0Sstevel@tonic-gate /* ssl/ssl_sess.c */ 2*0Sstevel@tonic-gate /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3*0Sstevel@tonic-gate * All rights reserved. 4*0Sstevel@tonic-gate * 5*0Sstevel@tonic-gate * This package is an SSL implementation written 6*0Sstevel@tonic-gate * by Eric Young (eay@cryptsoft.com). 7*0Sstevel@tonic-gate * The implementation was written so as to conform with Netscapes SSL. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * This library is free for commercial and non-commercial use as long as 10*0Sstevel@tonic-gate * the following conditions are aheared to. The following conditions 11*0Sstevel@tonic-gate * apply to all code found in this distribution, be it the RC4, RSA, 12*0Sstevel@tonic-gate * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13*0Sstevel@tonic-gate * included with this distribution is covered by the same copyright terms 14*0Sstevel@tonic-gate * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15*0Sstevel@tonic-gate * 16*0Sstevel@tonic-gate * Copyright remains Eric Young's, and as such any Copyright notices in 17*0Sstevel@tonic-gate * the code are not to be removed. 18*0Sstevel@tonic-gate * If this package is used in a product, Eric Young should be given attribution 19*0Sstevel@tonic-gate * as the author of the parts of the library used. 20*0Sstevel@tonic-gate * This can be in the form of a textual message at program startup or 21*0Sstevel@tonic-gate * in documentation (online or textual) provided with the package. 22*0Sstevel@tonic-gate * 23*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 24*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 25*0Sstevel@tonic-gate * are met: 26*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the copyright 27*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 28*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 29*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 30*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 31*0Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 32*0Sstevel@tonic-gate * must display the following acknowledgement: 33*0Sstevel@tonic-gate * "This product includes cryptographic software written by 34*0Sstevel@tonic-gate * Eric Young (eay@cryptsoft.com)" 35*0Sstevel@tonic-gate * The word 'cryptographic' can be left out if the rouines from the library 36*0Sstevel@tonic-gate * being used are not cryptographic related :-). 37*0Sstevel@tonic-gate * 4. If you include any Windows specific code (or a derivative thereof) from 38*0Sstevel@tonic-gate * the apps directory (application code) you must include an acknowledgement: 39*0Sstevel@tonic-gate * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40*0Sstevel@tonic-gate * 41*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42*0Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43*0Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44*0Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45*0Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46*0Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47*0Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48*0Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49*0Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50*0Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51*0Sstevel@tonic-gate * SUCH DAMAGE. 52*0Sstevel@tonic-gate * 53*0Sstevel@tonic-gate * The licence and distribution terms for any publically available version or 54*0Sstevel@tonic-gate * derivative of this code cannot be changed. i.e. this code cannot simply be 55*0Sstevel@tonic-gate * copied and put under another distribution licence 56*0Sstevel@tonic-gate * [including the GNU Public Licence.] 57*0Sstevel@tonic-gate */ 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate #include <stdio.h> 60*0Sstevel@tonic-gate #include <openssl/lhash.h> 61*0Sstevel@tonic-gate #include <openssl/rand.h> 62*0Sstevel@tonic-gate #include "ssl_locl.h" 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s); 65*0Sstevel@tonic-gate static void SSL_SESSION_list_add(SSL_CTX *ctx,SSL_SESSION *s); 66*0Sstevel@tonic-gate static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck); 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate SSL_SESSION *SSL_get_session(SSL *ssl) 69*0Sstevel@tonic-gate /* aka SSL_get0_session; gets 0 objects, just returns a copy of the pointer */ 70*0Sstevel@tonic-gate { 71*0Sstevel@tonic-gate return(ssl->session); 72*0Sstevel@tonic-gate } 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate SSL_SESSION *SSL_get1_session(SSL *ssl) 75*0Sstevel@tonic-gate /* variant of SSL_get_session: caller really gets something */ 76*0Sstevel@tonic-gate { 77*0Sstevel@tonic-gate SSL_SESSION *sess; 78*0Sstevel@tonic-gate /* Need to lock this all up rather than just use CRYPTO_add so that 79*0Sstevel@tonic-gate * somebody doesn't free ssl->session between when we check it's 80*0Sstevel@tonic-gate * non-null and when we up the reference count. */ 81*0Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_SSL_SESSION); 82*0Sstevel@tonic-gate sess = ssl->session; 83*0Sstevel@tonic-gate if(sess) 84*0Sstevel@tonic-gate sess->references++; 85*0Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_SSL_SESSION); 86*0Sstevel@tonic-gate return(sess); 87*0Sstevel@tonic-gate } 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, 90*0Sstevel@tonic-gate CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) 91*0Sstevel@tonic-gate { 92*0Sstevel@tonic-gate return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_SESSION, argl, argp, 93*0Sstevel@tonic-gate new_func, dup_func, free_func); 94*0Sstevel@tonic-gate } 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate int SSL_SESSION_set_ex_data(SSL_SESSION *s, int idx, void *arg) 97*0Sstevel@tonic-gate { 98*0Sstevel@tonic-gate return(CRYPTO_set_ex_data(&s->ex_data,idx,arg)); 99*0Sstevel@tonic-gate } 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate void *SSL_SESSION_get_ex_data(SSL_SESSION *s, int idx) 102*0Sstevel@tonic-gate { 103*0Sstevel@tonic-gate return(CRYPTO_get_ex_data(&s->ex_data,idx)); 104*0Sstevel@tonic-gate } 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate SSL_SESSION *SSL_SESSION_new(void) 107*0Sstevel@tonic-gate { 108*0Sstevel@tonic-gate SSL_SESSION *ss; 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate ss=(SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION)); 111*0Sstevel@tonic-gate if (ss == NULL) 112*0Sstevel@tonic-gate { 113*0Sstevel@tonic-gate SSLerr(SSL_F_SSL_SESSION_NEW,ERR_R_MALLOC_FAILURE); 114*0Sstevel@tonic-gate return(0); 115*0Sstevel@tonic-gate } 116*0Sstevel@tonic-gate memset(ss,0,sizeof(SSL_SESSION)); 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate ss->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */ 119*0Sstevel@tonic-gate ss->references=1; 120*0Sstevel@tonic-gate ss->timeout=60*5+4; /* 5 minute timeout by default */ 121*0Sstevel@tonic-gate ss->time=time(NULL); 122*0Sstevel@tonic-gate ss->prev=NULL; 123*0Sstevel@tonic-gate ss->next=NULL; 124*0Sstevel@tonic-gate ss->compress_meth=0; 125*0Sstevel@tonic-gate CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data); 126*0Sstevel@tonic-gate return(ss); 127*0Sstevel@tonic-gate } 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate /* Even with SSLv2, we have 16 bytes (128 bits) of session ID space. SSLv3/TLSv1 130*0Sstevel@tonic-gate * has 32 bytes (256 bits). As such, filling the ID with random gunk repeatedly 131*0Sstevel@tonic-gate * until we have no conflict is going to complete in one iteration pretty much 132*0Sstevel@tonic-gate * "most" of the time (btw: understatement). So, if it takes us 10 iterations 133*0Sstevel@tonic-gate * and we still can't avoid a conflict - well that's a reasonable point to call 134*0Sstevel@tonic-gate * it quits. Either the RAND code is broken or someone is trying to open roughly 135*0Sstevel@tonic-gate * very close to 2^128 (or 2^256) SSL sessions to our server. How you might 136*0Sstevel@tonic-gate * store that many sessions is perhaps a more interesting question ... */ 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate #define MAX_SESS_ID_ATTEMPTS 10 139*0Sstevel@tonic-gate static int def_generate_session_id(const SSL *ssl, unsigned char *id, 140*0Sstevel@tonic-gate unsigned int *id_len) 141*0Sstevel@tonic-gate { 142*0Sstevel@tonic-gate unsigned int retry = 0; 143*0Sstevel@tonic-gate do 144*0Sstevel@tonic-gate RAND_pseudo_bytes(id, *id_len); 145*0Sstevel@tonic-gate while(SSL_has_matching_session_id(ssl, id, *id_len) && 146*0Sstevel@tonic-gate (++retry < MAX_SESS_ID_ATTEMPTS)); 147*0Sstevel@tonic-gate if(retry < MAX_SESS_ID_ATTEMPTS) 148*0Sstevel@tonic-gate return 1; 149*0Sstevel@tonic-gate /* else - woops a session_id match */ 150*0Sstevel@tonic-gate /* XXX We should also check the external cache -- 151*0Sstevel@tonic-gate * but the probability of a collision is negligible, and 152*0Sstevel@tonic-gate * we could not prevent the concurrent creation of sessions 153*0Sstevel@tonic-gate * with identical IDs since we currently don't have means 154*0Sstevel@tonic-gate * to atomically check whether a session ID already exists 155*0Sstevel@tonic-gate * and make a reservation for it if it does not 156*0Sstevel@tonic-gate * (this problem applies to the internal cache as well). 157*0Sstevel@tonic-gate */ 158*0Sstevel@tonic-gate return 0; 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate int ssl_get_new_session(SSL *s, int session) 162*0Sstevel@tonic-gate { 163*0Sstevel@tonic-gate /* This gets used by clients and servers. */ 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate unsigned int tmp; 166*0Sstevel@tonic-gate SSL_SESSION *ss=NULL; 167*0Sstevel@tonic-gate GEN_SESSION_CB cb = def_generate_session_id; 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate if ((ss=SSL_SESSION_new()) == NULL) return(0); 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate /* If the context has a default timeout, use it */ 172*0Sstevel@tonic-gate if (s->ctx->session_timeout == 0) 173*0Sstevel@tonic-gate ss->timeout=SSL_get_default_timeout(s); 174*0Sstevel@tonic-gate else 175*0Sstevel@tonic-gate ss->timeout=s->ctx->session_timeout; 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate if (s->session != NULL) 178*0Sstevel@tonic-gate { 179*0Sstevel@tonic-gate SSL_SESSION_free(s->session); 180*0Sstevel@tonic-gate s->session=NULL; 181*0Sstevel@tonic-gate } 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate if (session) 184*0Sstevel@tonic-gate { 185*0Sstevel@tonic-gate if (s->version == SSL2_VERSION) 186*0Sstevel@tonic-gate { 187*0Sstevel@tonic-gate ss->ssl_version=SSL2_VERSION; 188*0Sstevel@tonic-gate ss->session_id_length=SSL2_SSL_SESSION_ID_LENGTH; 189*0Sstevel@tonic-gate } 190*0Sstevel@tonic-gate else if (s->version == SSL3_VERSION) 191*0Sstevel@tonic-gate { 192*0Sstevel@tonic-gate ss->ssl_version=SSL3_VERSION; 193*0Sstevel@tonic-gate ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH; 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate else if (s->version == TLS1_VERSION) 196*0Sstevel@tonic-gate { 197*0Sstevel@tonic-gate ss->ssl_version=TLS1_VERSION; 198*0Sstevel@tonic-gate ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH; 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate else 201*0Sstevel@tonic-gate { 202*0Sstevel@tonic-gate SSLerr(SSL_F_SSL_GET_NEW_SESSION,SSL_R_UNSUPPORTED_SSL_VERSION); 203*0Sstevel@tonic-gate SSL_SESSION_free(ss); 204*0Sstevel@tonic-gate return(0); 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate /* Choose which callback will set the session ID */ 207*0Sstevel@tonic-gate CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); 208*0Sstevel@tonic-gate if(s->generate_session_id) 209*0Sstevel@tonic-gate cb = s->generate_session_id; 210*0Sstevel@tonic-gate else if(s->ctx->generate_session_id) 211*0Sstevel@tonic-gate cb = s->ctx->generate_session_id; 212*0Sstevel@tonic-gate CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); 213*0Sstevel@tonic-gate /* Choose a session ID */ 214*0Sstevel@tonic-gate tmp = ss->session_id_length; 215*0Sstevel@tonic-gate if(!cb(s, ss->session_id, &tmp)) 216*0Sstevel@tonic-gate { 217*0Sstevel@tonic-gate /* The callback failed */ 218*0Sstevel@tonic-gate SSLerr(SSL_F_SSL_GET_NEW_SESSION, 219*0Sstevel@tonic-gate SSL_R_SSL_SESSION_ID_CALLBACK_FAILED); 220*0Sstevel@tonic-gate SSL_SESSION_free(ss); 221*0Sstevel@tonic-gate return(0); 222*0Sstevel@tonic-gate } 223*0Sstevel@tonic-gate /* Don't allow the callback to set the session length to zero. 224*0Sstevel@tonic-gate * nor set it higher than it was. */ 225*0Sstevel@tonic-gate if(!tmp || (tmp > ss->session_id_length)) 226*0Sstevel@tonic-gate { 227*0Sstevel@tonic-gate /* The callback set an illegal length */ 228*0Sstevel@tonic-gate SSLerr(SSL_F_SSL_GET_NEW_SESSION, 229*0Sstevel@tonic-gate SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH); 230*0Sstevel@tonic-gate SSL_SESSION_free(ss); 231*0Sstevel@tonic-gate return(0); 232*0Sstevel@tonic-gate } 233*0Sstevel@tonic-gate /* If the session length was shrunk and we're SSLv2, pad it */ 234*0Sstevel@tonic-gate if((tmp < ss->session_id_length) && (s->version == SSL2_VERSION)) 235*0Sstevel@tonic-gate memset(ss->session_id + tmp, 0, ss->session_id_length - tmp); 236*0Sstevel@tonic-gate else 237*0Sstevel@tonic-gate ss->session_id_length = tmp; 238*0Sstevel@tonic-gate /* Finally, check for a conflict */ 239*0Sstevel@tonic-gate if(SSL_has_matching_session_id(s, ss->session_id, 240*0Sstevel@tonic-gate ss->session_id_length)) 241*0Sstevel@tonic-gate { 242*0Sstevel@tonic-gate SSLerr(SSL_F_SSL_GET_NEW_SESSION, 243*0Sstevel@tonic-gate SSL_R_SSL_SESSION_ID_CONFLICT); 244*0Sstevel@tonic-gate SSL_SESSION_free(ss); 245*0Sstevel@tonic-gate return(0); 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate else 249*0Sstevel@tonic-gate { 250*0Sstevel@tonic-gate ss->session_id_length=0; 251*0Sstevel@tonic-gate } 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate if (s->sid_ctx_length > sizeof ss->sid_ctx) 254*0Sstevel@tonic-gate { 255*0Sstevel@tonic-gate SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_INTERNAL_ERROR); 256*0Sstevel@tonic-gate SSL_SESSION_free(ss); 257*0Sstevel@tonic-gate return 0; 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate memcpy(ss->sid_ctx,s->sid_ctx,s->sid_ctx_length); 260*0Sstevel@tonic-gate ss->sid_ctx_length=s->sid_ctx_length; 261*0Sstevel@tonic-gate s->session=ss; 262*0Sstevel@tonic-gate ss->ssl_version=s->version; 263*0Sstevel@tonic-gate ss->verify_result = X509_V_OK; 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate return(1); 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len) 269*0Sstevel@tonic-gate { 270*0Sstevel@tonic-gate /* This is used only by servers. */ 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate SSL_SESSION *ret=NULL,data; 273*0Sstevel@tonic-gate int fatal = 0; 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate data.ssl_version=s->version; 276*0Sstevel@tonic-gate data.session_id_length=len; 277*0Sstevel@tonic-gate if (len > SSL_MAX_SSL_SESSION_ID_LENGTH) 278*0Sstevel@tonic-gate goto err; 279*0Sstevel@tonic-gate memcpy(data.session_id,session_id,len); 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) 282*0Sstevel@tonic-gate { 283*0Sstevel@tonic-gate CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); 284*0Sstevel@tonic-gate ret=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,&data); 285*0Sstevel@tonic-gate if (ret != NULL) 286*0Sstevel@tonic-gate /* don't allow other threads to steal it: */ 287*0Sstevel@tonic-gate CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); 288*0Sstevel@tonic-gate CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate if (ret == NULL) 292*0Sstevel@tonic-gate { 293*0Sstevel@tonic-gate int copy=1; 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate s->ctx->stats.sess_miss++; 296*0Sstevel@tonic-gate ret=NULL; 297*0Sstevel@tonic-gate if (s->ctx->get_session_cb != NULL 298*0Sstevel@tonic-gate && (ret=s->ctx->get_session_cb(s,session_id,len,©)) 299*0Sstevel@tonic-gate != NULL) 300*0Sstevel@tonic-gate { 301*0Sstevel@tonic-gate s->ctx->stats.sess_cb_hit++; 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate /* Increment reference count now if the session callback 304*0Sstevel@tonic-gate * asks us to do so (note that if the session structures 305*0Sstevel@tonic-gate * returned by the callback are shared between threads, 306*0Sstevel@tonic-gate * it must handle the reference count itself [i.e. copy == 0], 307*0Sstevel@tonic-gate * or things won't be thread-safe). */ 308*0Sstevel@tonic-gate if (copy) 309*0Sstevel@tonic-gate CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate /* Add the externally cached session to the internal 312*0Sstevel@tonic-gate * cache as well if and only if we are supposed to. */ 313*0Sstevel@tonic-gate if(!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE)) 314*0Sstevel@tonic-gate /* The following should not return 1, otherwise, 315*0Sstevel@tonic-gate * things are very strange */ 316*0Sstevel@tonic-gate SSL_CTX_add_session(s->ctx,ret); 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate if (ret == NULL) 319*0Sstevel@tonic-gate goto err; 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate /* Now ret is non-NULL, and we own one of its reference counts. */ 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate if((s->verify_mode&SSL_VERIFY_PEER) 325*0Sstevel@tonic-gate && (!s->sid_ctx_length || ret->sid_ctx_length != s->sid_ctx_length 326*0Sstevel@tonic-gate || memcmp(ret->sid_ctx,s->sid_ctx,ret->sid_ctx_length))) 327*0Sstevel@tonic-gate { 328*0Sstevel@tonic-gate /* We've found the session named by the client, but we don't 329*0Sstevel@tonic-gate * want to use it in this context. */ 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate if (s->sid_ctx_length == 0) 332*0Sstevel@tonic-gate { 333*0Sstevel@tonic-gate /* application should have used SSL[_CTX]_set_session_id_context 334*0Sstevel@tonic-gate * -- we could tolerate this and just pretend we never heard 335*0Sstevel@tonic-gate * of this session, but then applications could effectively 336*0Sstevel@tonic-gate * disable the session cache by accident without anyone noticing */ 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED); 339*0Sstevel@tonic-gate fatal = 1; 340*0Sstevel@tonic-gate goto err; 341*0Sstevel@tonic-gate } 342*0Sstevel@tonic-gate else 343*0Sstevel@tonic-gate { 344*0Sstevel@tonic-gate #if 0 /* The client cannot always know when a session is not appropriate, 345*0Sstevel@tonic-gate * so we shouldn't generate an error message. */ 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT); 348*0Sstevel@tonic-gate #endif 349*0Sstevel@tonic-gate goto err; /* treat like cache miss */ 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate } 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate if (ret->cipher == NULL) 354*0Sstevel@tonic-gate { 355*0Sstevel@tonic-gate unsigned char buf[5],*p; 356*0Sstevel@tonic-gate unsigned long l; 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate p=buf; 359*0Sstevel@tonic-gate l=ret->cipher_id; 360*0Sstevel@tonic-gate l2n(l,p); 361*0Sstevel@tonic-gate if ((ret->ssl_version>>8) == SSL3_VERSION_MAJOR) 362*0Sstevel@tonic-gate ret->cipher=ssl_get_cipher_by_char(s,&(buf[2])); 363*0Sstevel@tonic-gate else 364*0Sstevel@tonic-gate ret->cipher=ssl_get_cipher_by_char(s,&(buf[1])); 365*0Sstevel@tonic-gate if (ret->cipher == NULL) 366*0Sstevel@tonic-gate goto err; 367*0Sstevel@tonic-gate } 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate #if 0 /* This is way too late. */ 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate /* If a thread got the session, then 'swaped', and another got 373*0Sstevel@tonic-gate * it and then due to a time-out decided to 'OPENSSL_free' it we could 374*0Sstevel@tonic-gate * be in trouble. So I'll increment it now, then double decrement 375*0Sstevel@tonic-gate * later - am I speaking rubbish?. */ 376*0Sstevel@tonic-gate CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); 377*0Sstevel@tonic-gate #endif 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate if ((long)(ret->time+ret->timeout) < (long)time(NULL)) /* timeout */ 380*0Sstevel@tonic-gate { 381*0Sstevel@tonic-gate s->ctx->stats.sess_timeout++; 382*0Sstevel@tonic-gate /* remove it from the cache */ 383*0Sstevel@tonic-gate SSL_CTX_remove_session(s->ctx,ret); 384*0Sstevel@tonic-gate goto err; 385*0Sstevel@tonic-gate } 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate s->ctx->stats.sess_hit++; 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate /* ret->time=time(NULL); */ /* rezero timeout? */ 390*0Sstevel@tonic-gate /* again, just leave the session 391*0Sstevel@tonic-gate * if it is the same session, we have just incremented and 392*0Sstevel@tonic-gate * then decremented the reference count :-) */ 393*0Sstevel@tonic-gate if (s->session != NULL) 394*0Sstevel@tonic-gate SSL_SESSION_free(s->session); 395*0Sstevel@tonic-gate s->session=ret; 396*0Sstevel@tonic-gate s->verify_result = s->session->verify_result; 397*0Sstevel@tonic-gate return(1); 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate err: 400*0Sstevel@tonic-gate if (ret != NULL) 401*0Sstevel@tonic-gate SSL_SESSION_free(ret); 402*0Sstevel@tonic-gate if (fatal) 403*0Sstevel@tonic-gate return -1; 404*0Sstevel@tonic-gate else 405*0Sstevel@tonic-gate return 0; 406*0Sstevel@tonic-gate } 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) 409*0Sstevel@tonic-gate { 410*0Sstevel@tonic-gate int ret=0; 411*0Sstevel@tonic-gate SSL_SESSION *s; 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate /* add just 1 reference count for the SSL_CTX's session cache 414*0Sstevel@tonic-gate * even though it has two ways of access: each session is in a 415*0Sstevel@tonic-gate * doubly linked list and an lhash */ 416*0Sstevel@tonic-gate CRYPTO_add(&c->references,1,CRYPTO_LOCK_SSL_SESSION); 417*0Sstevel@tonic-gate /* if session c is in already in cache, we take back the increment later */ 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); 420*0Sstevel@tonic-gate s=(SSL_SESSION *)lh_insert(ctx->sessions,c); 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate /* s != NULL iff we already had a session with the given PID. 423*0Sstevel@tonic-gate * In this case, s == c should hold (then we did not really modify 424*0Sstevel@tonic-gate * ctx->sessions), or we're in trouble. */ 425*0Sstevel@tonic-gate if (s != NULL && s != c) 426*0Sstevel@tonic-gate { 427*0Sstevel@tonic-gate /* We *are* in trouble ... */ 428*0Sstevel@tonic-gate SSL_SESSION_list_remove(ctx,s); 429*0Sstevel@tonic-gate SSL_SESSION_free(s); 430*0Sstevel@tonic-gate /* ... so pretend the other session did not exist in cache 431*0Sstevel@tonic-gate * (we cannot handle two SSL_SESSION structures with identical 432*0Sstevel@tonic-gate * session ID in the same cache, which could happen e.g. when 433*0Sstevel@tonic-gate * two threads concurrently obtain the same session from an external 434*0Sstevel@tonic-gate * cache) */ 435*0Sstevel@tonic-gate s = NULL; 436*0Sstevel@tonic-gate } 437*0Sstevel@tonic-gate 438*0Sstevel@tonic-gate /* Put at the head of the queue unless it is already in the cache */ 439*0Sstevel@tonic-gate if (s == NULL) 440*0Sstevel@tonic-gate SSL_SESSION_list_add(ctx,c); 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate if (s != NULL) 443*0Sstevel@tonic-gate { 444*0Sstevel@tonic-gate /* existing cache entry -- decrement previously incremented reference 445*0Sstevel@tonic-gate * count because it already takes into account the cache */ 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate SSL_SESSION_free(s); /* s == c */ 448*0Sstevel@tonic-gate ret=0; 449*0Sstevel@tonic-gate } 450*0Sstevel@tonic-gate else 451*0Sstevel@tonic-gate { 452*0Sstevel@tonic-gate /* new cache entry -- remove old ones if cache has become too large */ 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate ret=1; 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate if (SSL_CTX_sess_get_cache_size(ctx) > 0) 457*0Sstevel@tonic-gate { 458*0Sstevel@tonic-gate while (SSL_CTX_sess_number(ctx) > 459*0Sstevel@tonic-gate SSL_CTX_sess_get_cache_size(ctx)) 460*0Sstevel@tonic-gate { 461*0Sstevel@tonic-gate if (!remove_session_lock(ctx, 462*0Sstevel@tonic-gate ctx->session_cache_tail, 0)) 463*0Sstevel@tonic-gate break; 464*0Sstevel@tonic-gate else 465*0Sstevel@tonic-gate ctx->stats.sess_cache_full++; 466*0Sstevel@tonic-gate } 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); 470*0Sstevel@tonic-gate return(ret); 471*0Sstevel@tonic-gate } 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *c) 474*0Sstevel@tonic-gate { 475*0Sstevel@tonic-gate return remove_session_lock(ctx, c, 1); 476*0Sstevel@tonic-gate } 477*0Sstevel@tonic-gate 478*0Sstevel@tonic-gate static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck) 479*0Sstevel@tonic-gate { 480*0Sstevel@tonic-gate SSL_SESSION *r; 481*0Sstevel@tonic-gate int ret=0; 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate if ((c != NULL) && (c->session_id_length != 0)) 484*0Sstevel@tonic-gate { 485*0Sstevel@tonic-gate if(lck) CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); 486*0Sstevel@tonic-gate if ((r = (SSL_SESSION *)lh_retrieve(ctx->sessions,c)) == c) 487*0Sstevel@tonic-gate { 488*0Sstevel@tonic-gate ret=1; 489*0Sstevel@tonic-gate r=(SSL_SESSION *)lh_delete(ctx->sessions,c); 490*0Sstevel@tonic-gate SSL_SESSION_list_remove(ctx,c); 491*0Sstevel@tonic-gate } 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate if(lck) CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate if (ret) 496*0Sstevel@tonic-gate { 497*0Sstevel@tonic-gate r->not_resumable=1; 498*0Sstevel@tonic-gate if (ctx->remove_session_cb != NULL) 499*0Sstevel@tonic-gate ctx->remove_session_cb(ctx,r); 500*0Sstevel@tonic-gate SSL_SESSION_free(r); 501*0Sstevel@tonic-gate } 502*0Sstevel@tonic-gate } 503*0Sstevel@tonic-gate else 504*0Sstevel@tonic-gate ret=0; 505*0Sstevel@tonic-gate return(ret); 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate void SSL_SESSION_free(SSL_SESSION *ss) 509*0Sstevel@tonic-gate { 510*0Sstevel@tonic-gate int i; 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate if(ss == NULL) 513*0Sstevel@tonic-gate return; 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate i=CRYPTO_add(&ss->references,-1,CRYPTO_LOCK_SSL_SESSION); 516*0Sstevel@tonic-gate #ifdef REF_PRINT 517*0Sstevel@tonic-gate REF_PRINT("SSL_SESSION",ss); 518*0Sstevel@tonic-gate #endif 519*0Sstevel@tonic-gate if (i > 0) return; 520*0Sstevel@tonic-gate #ifdef REF_CHECK 521*0Sstevel@tonic-gate if (i < 0) 522*0Sstevel@tonic-gate { 523*0Sstevel@tonic-gate fprintf(stderr,"SSL_SESSION_free, bad reference count\n"); 524*0Sstevel@tonic-gate abort(); /* ok */ 525*0Sstevel@tonic-gate } 526*0Sstevel@tonic-gate #endif 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data); 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate OPENSSL_cleanse(ss->key_arg,sizeof ss->key_arg); 531*0Sstevel@tonic-gate OPENSSL_cleanse(ss->master_key,sizeof ss->master_key); 532*0Sstevel@tonic-gate OPENSSL_cleanse(ss->session_id,sizeof ss->session_id); 533*0Sstevel@tonic-gate if (ss->sess_cert != NULL) ssl_sess_cert_free(ss->sess_cert); 534*0Sstevel@tonic-gate if (ss->peer != NULL) X509_free(ss->peer); 535*0Sstevel@tonic-gate if (ss->ciphers != NULL) sk_SSL_CIPHER_free(ss->ciphers); 536*0Sstevel@tonic-gate OPENSSL_cleanse(ss,sizeof(*ss)); 537*0Sstevel@tonic-gate OPENSSL_free(ss); 538*0Sstevel@tonic-gate } 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate int SSL_set_session(SSL *s, SSL_SESSION *session) 541*0Sstevel@tonic-gate { 542*0Sstevel@tonic-gate int ret=0; 543*0Sstevel@tonic-gate SSL_METHOD *meth; 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate if (session != NULL) 546*0Sstevel@tonic-gate { 547*0Sstevel@tonic-gate meth=s->ctx->method->get_ssl_method(session->ssl_version); 548*0Sstevel@tonic-gate if (meth == NULL) 549*0Sstevel@tonic-gate meth=s->method->get_ssl_method(session->ssl_version); 550*0Sstevel@tonic-gate if (meth == NULL) 551*0Sstevel@tonic-gate { 552*0Sstevel@tonic-gate SSLerr(SSL_F_SSL_SET_SESSION,SSL_R_UNABLE_TO_FIND_SSL_METHOD); 553*0Sstevel@tonic-gate return(0); 554*0Sstevel@tonic-gate } 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate if (meth != s->method) 557*0Sstevel@tonic-gate { 558*0Sstevel@tonic-gate if (!SSL_set_ssl_method(s,meth)) 559*0Sstevel@tonic-gate return(0); 560*0Sstevel@tonic-gate if (s->ctx->session_timeout == 0) 561*0Sstevel@tonic-gate session->timeout=SSL_get_default_timeout(s); 562*0Sstevel@tonic-gate else 563*0Sstevel@tonic-gate session->timeout=s->ctx->session_timeout; 564*0Sstevel@tonic-gate } 565*0Sstevel@tonic-gate 566*0Sstevel@tonic-gate #ifndef OPENSSL_NO_KRB5 567*0Sstevel@tonic-gate if (s->kssl_ctx && !s->kssl_ctx->client_princ && 568*0Sstevel@tonic-gate session->krb5_client_princ_len > 0) 569*0Sstevel@tonic-gate { 570*0Sstevel@tonic-gate s->kssl_ctx->client_princ = (char *)malloc(session->krb5_client_princ_len + 1); 571*0Sstevel@tonic-gate memcpy(s->kssl_ctx->client_princ,session->krb5_client_princ, 572*0Sstevel@tonic-gate session->krb5_client_princ_len); 573*0Sstevel@tonic-gate s->kssl_ctx->client_princ[session->krb5_client_princ_len] = '\0'; 574*0Sstevel@tonic-gate } 575*0Sstevel@tonic-gate #endif /* OPENSSL_NO_KRB5 */ 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate /* CRYPTO_w_lock(CRYPTO_LOCK_SSL);*/ 578*0Sstevel@tonic-gate CRYPTO_add(&session->references,1,CRYPTO_LOCK_SSL_SESSION); 579*0Sstevel@tonic-gate if (s->session != NULL) 580*0Sstevel@tonic-gate SSL_SESSION_free(s->session); 581*0Sstevel@tonic-gate s->session=session; 582*0Sstevel@tonic-gate s->verify_result = s->session->verify_result; 583*0Sstevel@tonic-gate /* CRYPTO_w_unlock(CRYPTO_LOCK_SSL);*/ 584*0Sstevel@tonic-gate ret=1; 585*0Sstevel@tonic-gate } 586*0Sstevel@tonic-gate else 587*0Sstevel@tonic-gate { 588*0Sstevel@tonic-gate if (s->session != NULL) 589*0Sstevel@tonic-gate { 590*0Sstevel@tonic-gate SSL_SESSION_free(s->session); 591*0Sstevel@tonic-gate s->session=NULL; 592*0Sstevel@tonic-gate } 593*0Sstevel@tonic-gate 594*0Sstevel@tonic-gate meth=s->ctx->method; 595*0Sstevel@tonic-gate if (meth != s->method) 596*0Sstevel@tonic-gate { 597*0Sstevel@tonic-gate if (!SSL_set_ssl_method(s,meth)) 598*0Sstevel@tonic-gate return(0); 599*0Sstevel@tonic-gate } 600*0Sstevel@tonic-gate ret=1; 601*0Sstevel@tonic-gate } 602*0Sstevel@tonic-gate return(ret); 603*0Sstevel@tonic-gate } 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate long SSL_SESSION_set_timeout(SSL_SESSION *s, long t) 606*0Sstevel@tonic-gate { 607*0Sstevel@tonic-gate if (s == NULL) return(0); 608*0Sstevel@tonic-gate s->timeout=t; 609*0Sstevel@tonic-gate return(1); 610*0Sstevel@tonic-gate } 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate long SSL_SESSION_get_timeout(SSL_SESSION *s) 613*0Sstevel@tonic-gate { 614*0Sstevel@tonic-gate if (s == NULL) return(0); 615*0Sstevel@tonic-gate return(s->timeout); 616*0Sstevel@tonic-gate } 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate long SSL_SESSION_get_time(SSL_SESSION *s) 619*0Sstevel@tonic-gate { 620*0Sstevel@tonic-gate if (s == NULL) return(0); 621*0Sstevel@tonic-gate return(s->time); 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate long SSL_SESSION_set_time(SSL_SESSION *s, long t) 625*0Sstevel@tonic-gate { 626*0Sstevel@tonic-gate if (s == NULL) return(0); 627*0Sstevel@tonic-gate s->time=t; 628*0Sstevel@tonic-gate return(t); 629*0Sstevel@tonic-gate } 630*0Sstevel@tonic-gate 631*0Sstevel@tonic-gate long SSL_CTX_set_timeout(SSL_CTX *s, long t) 632*0Sstevel@tonic-gate { 633*0Sstevel@tonic-gate long l; 634*0Sstevel@tonic-gate if (s == NULL) return(0); 635*0Sstevel@tonic-gate l=s->session_timeout; 636*0Sstevel@tonic-gate s->session_timeout=t; 637*0Sstevel@tonic-gate return(l); 638*0Sstevel@tonic-gate } 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate long SSL_CTX_get_timeout(SSL_CTX *s) 641*0Sstevel@tonic-gate { 642*0Sstevel@tonic-gate if (s == NULL) return(0); 643*0Sstevel@tonic-gate return(s->session_timeout); 644*0Sstevel@tonic-gate } 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate typedef struct timeout_param_st 647*0Sstevel@tonic-gate { 648*0Sstevel@tonic-gate SSL_CTX *ctx; 649*0Sstevel@tonic-gate long time; 650*0Sstevel@tonic-gate LHASH *cache; 651*0Sstevel@tonic-gate } TIMEOUT_PARAM; 652*0Sstevel@tonic-gate 653*0Sstevel@tonic-gate static void timeout(SSL_SESSION *s, TIMEOUT_PARAM *p) 654*0Sstevel@tonic-gate { 655*0Sstevel@tonic-gate if ((p->time == 0) || (p->time > (s->time+s->timeout))) /* timeout */ 656*0Sstevel@tonic-gate { 657*0Sstevel@tonic-gate /* The reason we don't call SSL_CTX_remove_session() is to 658*0Sstevel@tonic-gate * save on locking overhead */ 659*0Sstevel@tonic-gate lh_delete(p->cache,s); 660*0Sstevel@tonic-gate SSL_SESSION_list_remove(p->ctx,s); 661*0Sstevel@tonic-gate s->not_resumable=1; 662*0Sstevel@tonic-gate if (p->ctx->remove_session_cb != NULL) 663*0Sstevel@tonic-gate p->ctx->remove_session_cb(p->ctx,s); 664*0Sstevel@tonic-gate SSL_SESSION_free(s); 665*0Sstevel@tonic-gate } 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate static IMPLEMENT_LHASH_DOALL_ARG_FN(timeout, SSL_SESSION *, TIMEOUT_PARAM *) 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gate void SSL_CTX_flush_sessions(SSL_CTX *s, long t) 671*0Sstevel@tonic-gate { 672*0Sstevel@tonic-gate unsigned long i; 673*0Sstevel@tonic-gate TIMEOUT_PARAM tp; 674*0Sstevel@tonic-gate 675*0Sstevel@tonic-gate tp.ctx=s; 676*0Sstevel@tonic-gate tp.cache=s->sessions; 677*0Sstevel@tonic-gate if (tp.cache == NULL) return; 678*0Sstevel@tonic-gate tp.time=t; 679*0Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); 680*0Sstevel@tonic-gate i=tp.cache->down_load; 681*0Sstevel@tonic-gate tp.cache->down_load=0; 682*0Sstevel@tonic-gate lh_doall_arg(tp.cache, LHASH_DOALL_ARG_FN(timeout), &tp); 683*0Sstevel@tonic-gate tp.cache->down_load=i; 684*0Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); 685*0Sstevel@tonic-gate } 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate int ssl_clear_bad_session(SSL *s) 688*0Sstevel@tonic-gate { 689*0Sstevel@tonic-gate if ( (s->session != NULL) && 690*0Sstevel@tonic-gate !(s->shutdown & SSL_SENT_SHUTDOWN) && 691*0Sstevel@tonic-gate !(SSL_in_init(s) || SSL_in_before(s))) 692*0Sstevel@tonic-gate { 693*0Sstevel@tonic-gate SSL_CTX_remove_session(s->ctx,s->session); 694*0Sstevel@tonic-gate return(1); 695*0Sstevel@tonic-gate } 696*0Sstevel@tonic-gate else 697*0Sstevel@tonic-gate return(0); 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate /* locked by SSL_CTX in the calling function */ 701*0Sstevel@tonic-gate static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s) 702*0Sstevel@tonic-gate { 703*0Sstevel@tonic-gate if ((s->next == NULL) || (s->prev == NULL)) return; 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate if (s->next == (SSL_SESSION *)&(ctx->session_cache_tail)) 706*0Sstevel@tonic-gate { /* last element in list */ 707*0Sstevel@tonic-gate if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head)) 708*0Sstevel@tonic-gate { /* only one element in list */ 709*0Sstevel@tonic-gate ctx->session_cache_head=NULL; 710*0Sstevel@tonic-gate ctx->session_cache_tail=NULL; 711*0Sstevel@tonic-gate } 712*0Sstevel@tonic-gate else 713*0Sstevel@tonic-gate { 714*0Sstevel@tonic-gate ctx->session_cache_tail=s->prev; 715*0Sstevel@tonic-gate s->prev->next=(SSL_SESSION *)&(ctx->session_cache_tail); 716*0Sstevel@tonic-gate } 717*0Sstevel@tonic-gate } 718*0Sstevel@tonic-gate else 719*0Sstevel@tonic-gate { 720*0Sstevel@tonic-gate if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head)) 721*0Sstevel@tonic-gate { /* first element in list */ 722*0Sstevel@tonic-gate ctx->session_cache_head=s->next; 723*0Sstevel@tonic-gate s->next->prev=(SSL_SESSION *)&(ctx->session_cache_head); 724*0Sstevel@tonic-gate } 725*0Sstevel@tonic-gate else 726*0Sstevel@tonic-gate { /* middle of list */ 727*0Sstevel@tonic-gate s->next->prev=s->prev; 728*0Sstevel@tonic-gate s->prev->next=s->next; 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate } 731*0Sstevel@tonic-gate s->prev=s->next=NULL; 732*0Sstevel@tonic-gate } 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s) 735*0Sstevel@tonic-gate { 736*0Sstevel@tonic-gate if ((s->next != NULL) && (s->prev != NULL)) 737*0Sstevel@tonic-gate SSL_SESSION_list_remove(ctx,s); 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate if (ctx->session_cache_head == NULL) 740*0Sstevel@tonic-gate { 741*0Sstevel@tonic-gate ctx->session_cache_head=s; 742*0Sstevel@tonic-gate ctx->session_cache_tail=s; 743*0Sstevel@tonic-gate s->prev=(SSL_SESSION *)&(ctx->session_cache_head); 744*0Sstevel@tonic-gate s->next=(SSL_SESSION *)&(ctx->session_cache_tail); 745*0Sstevel@tonic-gate } 746*0Sstevel@tonic-gate else 747*0Sstevel@tonic-gate { 748*0Sstevel@tonic-gate s->next=ctx->session_cache_head; 749*0Sstevel@tonic-gate s->next->prev=s; 750*0Sstevel@tonic-gate s->prev=(SSL_SESSION *)&(ctx->session_cache_head); 751*0Sstevel@tonic-gate ctx->session_cache_head=s; 752*0Sstevel@tonic-gate } 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate 755