ssl_sess.c revision 160814
155714Skris/* ssl/ssl_sess.c */ 255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 355714Skris * All rights reserved. 455714Skris * 555714Skris * This package is an SSL implementation written 655714Skris * by Eric Young (eay@cryptsoft.com). 755714Skris * The implementation was written so as to conform with Netscapes SSL. 855714Skris * 955714Skris * This library is free for commercial and non-commercial use as long as 1055714Skris * the following conditions are aheared to. The following conditions 1155714Skris * apply to all code found in this distribution, be it the RC4, RSA, 1255714Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1355714Skris * included with this distribution is covered by the same copyright terms 1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 1555714Skris * 1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in 1755714Skris * the code are not to be removed. 1855714Skris * If this package is used in a product, Eric Young should be given attribution 1955714Skris * as the author of the parts of the library used. 2055714Skris * This can be in the form of a textual message at program startup or 2155714Skris * in documentation (online or textual) provided with the package. 2255714Skris * 2355714Skris * Redistribution and use in source and binary forms, with or without 2455714Skris * modification, are permitted provided that the following conditions 2555714Skris * are met: 2655714Skris * 1. Redistributions of source code must retain the copyright 2755714Skris * notice, this list of conditions and the following disclaimer. 2855714Skris * 2. Redistributions in binary form must reproduce the above copyright 2955714Skris * notice, this list of conditions and the following disclaimer in the 3055714Skris * documentation and/or other materials provided with the distribution. 3155714Skris * 3. All advertising materials mentioning features or use of this software 3255714Skris * must display the following acknowledgement: 3355714Skris * "This product includes cryptographic software written by 3455714Skris * Eric Young (eay@cryptsoft.com)" 3555714Skris * The word 'cryptographic' can be left out if the rouines from the library 3655714Skris * being used are not cryptographic related :-). 3755714Skris * 4. If you include any Windows specific code (or a derivative thereof) from 3855714Skris * the apps directory (application code) you must include an acknowledgement: 3955714Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 4055714Skris * 4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4455714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5155714Skris * SUCH DAMAGE. 5255714Skris * 5355714Skris * The licence and distribution terms for any publically available version or 5455714Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 5555714Skris * copied and put under another distribution licence 5655714Skris * [including the GNU Public Licence.] 5755714Skris */ 5855714Skris 5955714Skris#include <stdio.h> 6055714Skris#include <openssl/lhash.h> 6155714Skris#include <openssl/rand.h> 6255714Skris#include "ssl_locl.h" 6355714Skris 6455714Skrisstatic void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s); 6555714Skrisstatic void SSL_SESSION_list_add(SSL_CTX *ctx,SSL_SESSION *s); 6655714Skrisstatic int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck); 6755714Skris 68160814SsimonSSL_SESSION *SSL_get_session(const SSL *ssl) 6959191Skris/* aka SSL_get0_session; gets 0 objects, just returns a copy of the pointer */ 7055714Skris { 7155714Skris return(ssl->session); 7255714Skris } 7355714Skris 7459191SkrisSSL_SESSION *SSL_get1_session(SSL *ssl) 7559191Skris/* variant of SSL_get_session: caller really gets something */ 7655714Skris { 7759191Skris SSL_SESSION *sess; 7859191Skris /* Need to lock this all up rather than just use CRYPTO_add so that 7959191Skris * somebody doesn't free ssl->session between when we check it's 8059191Skris * non-null and when we up the reference count. */ 81120631Snectar CRYPTO_w_lock(CRYPTO_LOCK_SSL_SESSION); 8259191Skris sess = ssl->session; 8359191Skris if(sess) 8459191Skris sess->references++; 85120631Snectar CRYPTO_w_unlock(CRYPTO_LOCK_SSL_SESSION); 8659191Skris return(sess); 8759191Skris } 8859191Skris 8959191Skrisint SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, 9059191Skris CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) 9159191Skris { 92109998Smarkm return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_SESSION, argl, argp, 93109998Smarkm new_func, dup_func, free_func); 9455714Skris } 9555714Skris 9655714Skrisint SSL_SESSION_set_ex_data(SSL_SESSION *s, int idx, void *arg) 9755714Skris { 9855714Skris return(CRYPTO_set_ex_data(&s->ex_data,idx,arg)); 9955714Skris } 10055714Skris 101160814Ssimonvoid *SSL_SESSION_get_ex_data(const SSL_SESSION *s, int idx) 10255714Skris { 10355714Skris return(CRYPTO_get_ex_data(&s->ex_data,idx)); 10455714Skris } 10555714Skris 10655714SkrisSSL_SESSION *SSL_SESSION_new(void) 10755714Skris { 10855714Skris SSL_SESSION *ss; 10955714Skris 11068651Skris ss=(SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION)); 11155714Skris if (ss == NULL) 11255714Skris { 11355714Skris SSLerr(SSL_F_SSL_SESSION_NEW,ERR_R_MALLOC_FAILURE); 11455714Skris return(0); 11555714Skris } 11655714Skris memset(ss,0,sizeof(SSL_SESSION)); 11755714Skris 11859191Skris ss->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */ 11955714Skris ss->references=1; 12055714Skris ss->timeout=60*5+4; /* 5 minute timeout by default */ 121160814Ssimon ss->time=(unsigned long)time(NULL); 12255714Skris ss->prev=NULL; 12355714Skris ss->next=NULL; 12455714Skris ss->compress_meth=0; 125109998Smarkm CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data); 12655714Skris return(ss); 12755714Skris } 12855714Skris 129160814Ssimonconst unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len) 130160814Ssimon { 131160814Ssimon if(len) 132160814Ssimon *len = s->session_id_length; 133160814Ssimon return s->session_id; 134160814Ssimon } 135160814Ssimon 136109998Smarkm/* Even with SSLv2, we have 16 bytes (128 bits) of session ID space. SSLv3/TLSv1 137109998Smarkm * has 32 bytes (256 bits). As such, filling the ID with random gunk repeatedly 138109998Smarkm * until we have no conflict is going to complete in one iteration pretty much 139109998Smarkm * "most" of the time (btw: understatement). So, if it takes us 10 iterations 140109998Smarkm * and we still can't avoid a conflict - well that's a reasonable point to call 141109998Smarkm * it quits. Either the RAND code is broken or someone is trying to open roughly 142109998Smarkm * very close to 2^128 (or 2^256) SSL sessions to our server. How you might 143109998Smarkm * store that many sessions is perhaps a more interesting question ... */ 144109998Smarkm 145109998Smarkm#define MAX_SESS_ID_ATTEMPTS 10 146109998Smarkmstatic int def_generate_session_id(const SSL *ssl, unsigned char *id, 147109998Smarkm unsigned int *id_len) 148109998Smarkm{ 149109998Smarkm unsigned int retry = 0; 150109998Smarkm do 151160814Ssimon if (RAND_pseudo_bytes(id, *id_len) <= 0) 152142425Snectar return 0; 153109998Smarkm while(SSL_has_matching_session_id(ssl, id, *id_len) && 154109998Smarkm (++retry < MAX_SESS_ID_ATTEMPTS)); 155109998Smarkm if(retry < MAX_SESS_ID_ATTEMPTS) 156109998Smarkm return 1; 157109998Smarkm /* else - woops a session_id match */ 158109998Smarkm /* XXX We should also check the external cache -- 159109998Smarkm * but the probability of a collision is negligible, and 160109998Smarkm * we could not prevent the concurrent creation of sessions 161109998Smarkm * with identical IDs since we currently don't have means 162109998Smarkm * to atomically check whether a session ID already exists 163109998Smarkm * and make a reservation for it if it does not 164109998Smarkm * (this problem applies to the internal cache as well). 165109998Smarkm */ 166109998Smarkm return 0; 167109998Smarkm} 168109998Smarkm 16955714Skrisint ssl_get_new_session(SSL *s, int session) 17055714Skris { 17155714Skris /* This gets used by clients and servers. */ 17255714Skris 173109998Smarkm unsigned int tmp; 17455714Skris SSL_SESSION *ss=NULL; 175109998Smarkm GEN_SESSION_CB cb = def_generate_session_id; 17655714Skris 17755714Skris if ((ss=SSL_SESSION_new()) == NULL) return(0); 17855714Skris 17955714Skris /* If the context has a default timeout, use it */ 18055714Skris if (s->ctx->session_timeout == 0) 18155714Skris ss->timeout=SSL_get_default_timeout(s); 18255714Skris else 18355714Skris ss->timeout=s->ctx->session_timeout; 18455714Skris 18555714Skris if (s->session != NULL) 18655714Skris { 18755714Skris SSL_SESSION_free(s->session); 18855714Skris s->session=NULL; 18955714Skris } 19055714Skris 19155714Skris if (session) 19255714Skris { 19355714Skris if (s->version == SSL2_VERSION) 19455714Skris { 19555714Skris ss->ssl_version=SSL2_VERSION; 19655714Skris ss->session_id_length=SSL2_SSL_SESSION_ID_LENGTH; 19755714Skris } 19855714Skris else if (s->version == SSL3_VERSION) 19955714Skris { 20055714Skris ss->ssl_version=SSL3_VERSION; 20155714Skris ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH; 20255714Skris } 20355714Skris else if (s->version == TLS1_VERSION) 20455714Skris { 20555714Skris ss->ssl_version=TLS1_VERSION; 20655714Skris ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH; 20755714Skris } 208160814Ssimon else if (s->version == DTLS1_VERSION) 209160814Ssimon { 210160814Ssimon ss->ssl_version=DTLS1_VERSION; 211160814Ssimon ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH; 212160814Ssimon } 21355714Skris else 21455714Skris { 21555714Skris SSLerr(SSL_F_SSL_GET_NEW_SESSION,SSL_R_UNSUPPORTED_SSL_VERSION); 21655714Skris SSL_SESSION_free(ss); 21755714Skris return(0); 21855714Skris } 219109998Smarkm /* Choose which callback will set the session ID */ 220109998Smarkm CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); 221109998Smarkm if(s->generate_session_id) 222109998Smarkm cb = s->generate_session_id; 223109998Smarkm else if(s->ctx->generate_session_id) 224109998Smarkm cb = s->ctx->generate_session_id; 225109998Smarkm CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); 226109998Smarkm /* Choose a session ID */ 227109998Smarkm tmp = ss->session_id_length; 228109998Smarkm if(!cb(s, ss->session_id, &tmp)) 22955714Skris { 230109998Smarkm /* The callback failed */ 231109998Smarkm SSLerr(SSL_F_SSL_GET_NEW_SESSION, 232109998Smarkm SSL_R_SSL_SESSION_ID_CALLBACK_FAILED); 233109998Smarkm SSL_SESSION_free(ss); 234109998Smarkm return(0); 23555714Skris } 236109998Smarkm /* Don't allow the callback to set the session length to zero. 237109998Smarkm * nor set it higher than it was. */ 238109998Smarkm if(!tmp || (tmp > ss->session_id_length)) 239109998Smarkm { 240109998Smarkm /* The callback set an illegal length */ 241109998Smarkm SSLerr(SSL_F_SSL_GET_NEW_SESSION, 242109998Smarkm SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH); 243109998Smarkm SSL_SESSION_free(ss); 244109998Smarkm return(0); 245109998Smarkm } 246109998Smarkm /* If the session length was shrunk and we're SSLv2, pad it */ 247109998Smarkm if((tmp < ss->session_id_length) && (s->version == SSL2_VERSION)) 248109998Smarkm memset(ss->session_id + tmp, 0, ss->session_id_length - tmp); 249109998Smarkm else 250109998Smarkm ss->session_id_length = tmp; 251109998Smarkm /* Finally, check for a conflict */ 252109998Smarkm if(SSL_has_matching_session_id(s, ss->session_id, 253109998Smarkm ss->session_id_length)) 254109998Smarkm { 255109998Smarkm SSLerr(SSL_F_SSL_GET_NEW_SESSION, 256109998Smarkm SSL_R_SSL_SESSION_ID_CONFLICT); 257109998Smarkm SSL_SESSION_free(ss); 258109998Smarkm return(0); 259109998Smarkm } 26055714Skris } 26155714Skris else 26255714Skris { 26355714Skris ss->session_id_length=0; 26455714Skris } 26555714Skris 266101615Snectar if (s->sid_ctx_length > sizeof ss->sid_ctx) 267101615Snectar { 268109998Smarkm SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_INTERNAL_ERROR); 269101615Snectar SSL_SESSION_free(ss); 270101615Snectar return 0; 271101615Snectar } 27255714Skris memcpy(ss->sid_ctx,s->sid_ctx,s->sid_ctx_length); 27355714Skris ss->sid_ctx_length=s->sid_ctx_length; 27455714Skris s->session=ss; 27555714Skris ss->ssl_version=s->version; 27659191Skris ss->verify_result = X509_V_OK; 27755714Skris 27855714Skris return(1); 27955714Skris } 28055714Skris 28155714Skrisint ssl_get_prev_session(SSL *s, unsigned char *session_id, int len) 28255714Skris { 28355714Skris /* This is used only by servers. */ 28455714Skris 28555714Skris SSL_SESSION *ret=NULL,data; 28655714Skris int fatal = 0; 28755714Skris 28855714Skris data.ssl_version=s->version; 28955714Skris data.session_id_length=len; 29055714Skris if (len > SSL_MAX_SSL_SESSION_ID_LENGTH) 29155714Skris goto err; 29255714Skris memcpy(data.session_id,session_id,len); 29355714Skris 29455714Skris if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) 29555714Skris { 29655714Skris CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); 29759191Skris ret=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,&data); 29855714Skris if (ret != NULL) 29955714Skris /* don't allow other threads to steal it: */ 30055714Skris CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); 30155714Skris CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); 30255714Skris } 30355714Skris 30455714Skris if (ret == NULL) 30555714Skris { 30655714Skris int copy=1; 30755714Skris 30855714Skris s->ctx->stats.sess_miss++; 30955714Skris ret=NULL; 31055714Skris if (s->ctx->get_session_cb != NULL 31155714Skris && (ret=s->ctx->get_session_cb(s,session_id,len,©)) 31255714Skris != NULL) 31355714Skris { 31455714Skris s->ctx->stats.sess_cb_hit++; 31555714Skris 31655714Skris /* Increment reference count now if the session callback 31755714Skris * asks us to do so (note that if the session structures 31855714Skris * returned by the callback are shared between threads, 31955714Skris * it must handle the reference count itself [i.e. copy == 0], 32055714Skris * or things won't be thread-safe). */ 32155714Skris if (copy) 32255714Skris CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); 32355714Skris 324109998Smarkm /* Add the externally cached session to the internal 325109998Smarkm * cache as well if and only if we are supposed to. */ 326109998Smarkm if(!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE)) 327109998Smarkm /* The following should not return 1, otherwise, 328109998Smarkm * things are very strange */ 329109998Smarkm SSL_CTX_add_session(s->ctx,ret); 33055714Skris } 33155714Skris if (ret == NULL) 33255714Skris goto err; 33355714Skris } 33455714Skris 33555714Skris /* Now ret is non-NULL, and we own one of its reference counts. */ 33655714Skris 33755714Skris if((s->verify_mode&SSL_VERIFY_PEER) 33855714Skris && (!s->sid_ctx_length || ret->sid_ctx_length != s->sid_ctx_length 33955714Skris || memcmp(ret->sid_ctx,s->sid_ctx,ret->sid_ctx_length))) 34055714Skris { 34155714Skris /* We've found the session named by the client, but we don't 34255714Skris * want to use it in this context. */ 34355714Skris 34455714Skris if (s->sid_ctx_length == 0) 34555714Skris { 34655714Skris /* application should have used SSL[_CTX]_set_session_id_context 34755714Skris * -- we could tolerate this and just pretend we never heard 34855714Skris * of this session, but then applications could effectively 34955714Skris * disable the session cache by accident without anyone noticing */ 35055714Skris 35155714Skris SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED); 35255714Skris fatal = 1; 35355714Skris goto err; 35455714Skris } 35555714Skris else 35655714Skris { 35755714Skris#if 0 /* The client cannot always know when a session is not appropriate, 35855714Skris * so we shouldn't generate an error message. */ 35955714Skris 36055714Skris SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT); 36155714Skris#endif 36255714Skris goto err; /* treat like cache miss */ 36355714Skris } 36455714Skris } 36555714Skris 36655714Skris if (ret->cipher == NULL) 36755714Skris { 36855714Skris unsigned char buf[5],*p; 36955714Skris unsigned long l; 37055714Skris 37155714Skris p=buf; 37255714Skris l=ret->cipher_id; 37355714Skris l2n(l,p); 37455714Skris if ((ret->ssl_version>>8) == SSL3_VERSION_MAJOR) 37555714Skris ret->cipher=ssl_get_cipher_by_char(s,&(buf[2])); 37655714Skris else 37755714Skris ret->cipher=ssl_get_cipher_by_char(s,&(buf[1])); 37855714Skris if (ret->cipher == NULL) 37955714Skris goto err; 38055714Skris } 38155714Skris 38255714Skris 38355714Skris#if 0 /* This is way too late. */ 38455714Skris 38555714Skris /* If a thread got the session, then 'swaped', and another got 38668651Skris * it and then due to a time-out decided to 'OPENSSL_free' it we could 38755714Skris * be in trouble. So I'll increment it now, then double decrement 38855714Skris * later - am I speaking rubbish?. */ 38955714Skris CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); 39055714Skris#endif 39155714Skris 392160814Ssimon if (ret->timeout < (long)(time(NULL) - ret->time)) /* timeout */ 39355714Skris { 39455714Skris s->ctx->stats.sess_timeout++; 39555714Skris /* remove it from the cache */ 39655714Skris SSL_CTX_remove_session(s->ctx,ret); 39755714Skris goto err; 39855714Skris } 39955714Skris 40055714Skris s->ctx->stats.sess_hit++; 40155714Skris 40255714Skris /* ret->time=time(NULL); */ /* rezero timeout? */ 40355714Skris /* again, just leave the session 40455714Skris * if it is the same session, we have just incremented and 40555714Skris * then decremented the reference count :-) */ 40655714Skris if (s->session != NULL) 40755714Skris SSL_SESSION_free(s->session); 40855714Skris s->session=ret; 40959191Skris s->verify_result = s->session->verify_result; 41055714Skris return(1); 41155714Skris 41255714Skris err: 41355714Skris if (ret != NULL) 41455714Skris SSL_SESSION_free(ret); 41555714Skris if (fatal) 41655714Skris return -1; 41755714Skris else 41855714Skris return 0; 41955714Skris } 42055714Skris 42155714Skrisint SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) 42255714Skris { 42355714Skris int ret=0; 42455714Skris SSL_SESSION *s; 42555714Skris 42659191Skris /* add just 1 reference count for the SSL_CTX's session cache 42759191Skris * even though it has two ways of access: each session is in a 42859191Skris * doubly linked list and an lhash */ 42955714Skris CRYPTO_add(&c->references,1,CRYPTO_LOCK_SSL_SESSION); 43059191Skris /* if session c is in already in cache, we take back the increment later */ 43155714Skris 43255714Skris CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); 43359191Skris s=(SSL_SESSION *)lh_insert(ctx->sessions,c); 43455714Skris 43559191Skris /* s != NULL iff we already had a session with the given PID. 43659191Skris * In this case, s == c should hold (then we did not really modify 43759191Skris * ctx->sessions), or we're in trouble. */ 43859191Skris if (s != NULL && s != c) 43959191Skris { 44059191Skris /* We *are* in trouble ... */ 44159191Skris SSL_SESSION_list_remove(ctx,s); 44259191Skris SSL_SESSION_free(s); 44359191Skris /* ... so pretend the other session did not exist in cache 44459191Skris * (we cannot handle two SSL_SESSION structures with identical 44559191Skris * session ID in the same cache, which could happen e.g. when 44659191Skris * two threads concurrently obtain the same session from an external 44759191Skris * cache) */ 44859191Skris s = NULL; 44959191Skris } 45059191Skris 45159191Skris /* Put at the head of the queue unless it is already in the cache */ 45255714Skris if (s == NULL) 45355714Skris SSL_SESSION_list_add(ctx,c); 45455714Skris 45555714Skris if (s != NULL) 45655714Skris { 45759191Skris /* existing cache entry -- decrement previously incremented reference 45859191Skris * count because it already takes into account the cache */ 45959191Skris 46059191Skris SSL_SESSION_free(s); /* s == c */ 46155714Skris ret=0; 46255714Skris } 46355714Skris else 46455714Skris { 46559191Skris /* new cache entry -- remove old ones if cache has become too large */ 46659191Skris 46755714Skris ret=1; 46855714Skris 46955714Skris if (SSL_CTX_sess_get_cache_size(ctx) > 0) 47055714Skris { 47155714Skris while (SSL_CTX_sess_number(ctx) > 47255714Skris SSL_CTX_sess_get_cache_size(ctx)) 47355714Skris { 47455714Skris if (!remove_session_lock(ctx, 47555714Skris ctx->session_cache_tail, 0)) 47655714Skris break; 47755714Skris else 47855714Skris ctx->stats.sess_cache_full++; 47955714Skris } 48055714Skris } 48155714Skris } 48255714Skris CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); 48355714Skris return(ret); 48455714Skris } 48555714Skris 48655714Skrisint SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *c) 48755714Skris{ 48855714Skris return remove_session_lock(ctx, c, 1); 48955714Skris} 49055714Skris 49155714Skrisstatic int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck) 49255714Skris { 49355714Skris SSL_SESSION *r; 49455714Skris int ret=0; 49555714Skris 49655714Skris if ((c != NULL) && (c->session_id_length != 0)) 49755714Skris { 49855714Skris if(lck) CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); 499100928Snectar if ((r = (SSL_SESSION *)lh_retrieve(ctx->sessions,c)) == c) 50055714Skris { 50155714Skris ret=1; 502100928Snectar r=(SSL_SESSION *)lh_delete(ctx->sessions,c); 50355714Skris SSL_SESSION_list_remove(ctx,c); 50455714Skris } 50555714Skris 50655714Skris if(lck) CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); 50755714Skris 50855714Skris if (ret) 50955714Skris { 51055714Skris r->not_resumable=1; 51155714Skris if (ctx->remove_session_cb != NULL) 51255714Skris ctx->remove_session_cb(ctx,r); 51355714Skris SSL_SESSION_free(r); 51455714Skris } 51555714Skris } 51655714Skris else 51755714Skris ret=0; 51855714Skris return(ret); 51955714Skris } 52055714Skris 52155714Skrisvoid SSL_SESSION_free(SSL_SESSION *ss) 52255714Skris { 52355714Skris int i; 52455714Skris 52555714Skris if(ss == NULL) 52655714Skris return; 52755714Skris 52855714Skris i=CRYPTO_add(&ss->references,-1,CRYPTO_LOCK_SSL_SESSION); 52955714Skris#ifdef REF_PRINT 53055714Skris REF_PRINT("SSL_SESSION",ss); 53155714Skris#endif 53255714Skris if (i > 0) return; 53355714Skris#ifdef REF_CHECK 53455714Skris if (i < 0) 53555714Skris { 53655714Skris fprintf(stderr,"SSL_SESSION_free, bad reference count\n"); 53755714Skris abort(); /* ok */ 53855714Skris } 53955714Skris#endif 54055714Skris 541109998Smarkm CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data); 54255714Skris 543109998Smarkm OPENSSL_cleanse(ss->key_arg,sizeof ss->key_arg); 544109998Smarkm OPENSSL_cleanse(ss->master_key,sizeof ss->master_key); 545109998Smarkm OPENSSL_cleanse(ss->session_id,sizeof ss->session_id); 54655714Skris if (ss->sess_cert != NULL) ssl_sess_cert_free(ss->sess_cert); 54755714Skris if (ss->peer != NULL) X509_free(ss->peer); 54855714Skris if (ss->ciphers != NULL) sk_SSL_CIPHER_free(ss->ciphers); 549109998Smarkm OPENSSL_cleanse(ss,sizeof(*ss)); 55068651Skris OPENSSL_free(ss); 55155714Skris } 55255714Skris 55355714Skrisint SSL_set_session(SSL *s, SSL_SESSION *session) 55455714Skris { 55555714Skris int ret=0; 55655714Skris SSL_METHOD *meth; 55755714Skris 55855714Skris if (session != NULL) 55955714Skris { 56055714Skris meth=s->ctx->method->get_ssl_method(session->ssl_version); 56155714Skris if (meth == NULL) 56255714Skris meth=s->method->get_ssl_method(session->ssl_version); 56355714Skris if (meth == NULL) 56455714Skris { 56555714Skris SSLerr(SSL_F_SSL_SET_SESSION,SSL_R_UNABLE_TO_FIND_SSL_METHOD); 56655714Skris return(0); 56755714Skris } 56855714Skris 56955714Skris if (meth != s->method) 57055714Skris { 57155714Skris if (!SSL_set_ssl_method(s,meth)) 57255714Skris return(0); 57355714Skris if (s->ctx->session_timeout == 0) 57455714Skris session->timeout=SSL_get_default_timeout(s); 57555714Skris else 57655714Skris session->timeout=s->ctx->session_timeout; 57755714Skris } 57855714Skris 579109998Smarkm#ifndef OPENSSL_NO_KRB5 580109998Smarkm if (s->kssl_ctx && !s->kssl_ctx->client_princ && 581109998Smarkm session->krb5_client_princ_len > 0) 582109998Smarkm { 583109998Smarkm s->kssl_ctx->client_princ = (char *)malloc(session->krb5_client_princ_len + 1); 584109998Smarkm memcpy(s->kssl_ctx->client_princ,session->krb5_client_princ, 585109998Smarkm session->krb5_client_princ_len); 586109998Smarkm s->kssl_ctx->client_princ[session->krb5_client_princ_len] = '\0'; 587109998Smarkm } 588109998Smarkm#endif /* OPENSSL_NO_KRB5 */ 589109998Smarkm 59055714Skris /* CRYPTO_w_lock(CRYPTO_LOCK_SSL);*/ 59155714Skris CRYPTO_add(&session->references,1,CRYPTO_LOCK_SSL_SESSION); 59255714Skris if (s->session != NULL) 59355714Skris SSL_SESSION_free(s->session); 59455714Skris s->session=session; 59572613Skris s->verify_result = s->session->verify_result; 59655714Skris /* CRYPTO_w_unlock(CRYPTO_LOCK_SSL);*/ 59755714Skris ret=1; 59855714Skris } 59955714Skris else 60055714Skris { 60155714Skris if (s->session != NULL) 60255714Skris { 60355714Skris SSL_SESSION_free(s->session); 60455714Skris s->session=NULL; 60555714Skris } 60655714Skris 60755714Skris meth=s->ctx->method; 60855714Skris if (meth != s->method) 60955714Skris { 61055714Skris if (!SSL_set_ssl_method(s,meth)) 61155714Skris return(0); 61255714Skris } 61355714Skris ret=1; 61455714Skris } 61555714Skris return(ret); 61655714Skris } 61755714Skris 61855714Skrislong SSL_SESSION_set_timeout(SSL_SESSION *s, long t) 61955714Skris { 62055714Skris if (s == NULL) return(0); 62155714Skris s->timeout=t; 62255714Skris return(1); 62355714Skris } 62455714Skris 625160814Ssimonlong SSL_SESSION_get_timeout(const SSL_SESSION *s) 62655714Skris { 62755714Skris if (s == NULL) return(0); 62855714Skris return(s->timeout); 62955714Skris } 63055714Skris 631160814Ssimonlong SSL_SESSION_get_time(const SSL_SESSION *s) 63255714Skris { 63355714Skris if (s == NULL) return(0); 63455714Skris return(s->time); 63555714Skris } 63655714Skris 63755714Skrislong SSL_SESSION_set_time(SSL_SESSION *s, long t) 63855714Skris { 63955714Skris if (s == NULL) return(0); 64055714Skris s->time=t; 64155714Skris return(t); 64255714Skris } 64355714Skris 64455714Skrislong SSL_CTX_set_timeout(SSL_CTX *s, long t) 64555714Skris { 64655714Skris long l; 64755714Skris if (s == NULL) return(0); 64855714Skris l=s->session_timeout; 64955714Skris s->session_timeout=t; 65055714Skris return(l); 65155714Skris } 65255714Skris 653160814Ssimonlong SSL_CTX_get_timeout(const SSL_CTX *s) 65455714Skris { 65555714Skris if (s == NULL) return(0); 65655714Skris return(s->session_timeout); 65755714Skris } 65855714Skris 65955714Skristypedef struct timeout_param_st 66055714Skris { 66155714Skris SSL_CTX *ctx; 66255714Skris long time; 66355714Skris LHASH *cache; 66455714Skris } TIMEOUT_PARAM; 66555714Skris 66655714Skrisstatic void timeout(SSL_SESSION *s, TIMEOUT_PARAM *p) 66755714Skris { 66855714Skris if ((p->time == 0) || (p->time > (s->time+s->timeout))) /* timeout */ 66955714Skris { 67055714Skris /* The reason we don't call SSL_CTX_remove_session() is to 67155714Skris * save on locking overhead */ 67259191Skris lh_delete(p->cache,s); 67355714Skris SSL_SESSION_list_remove(p->ctx,s); 67455714Skris s->not_resumable=1; 67555714Skris if (p->ctx->remove_session_cb != NULL) 67655714Skris p->ctx->remove_session_cb(p->ctx,s); 67755714Skris SSL_SESSION_free(s); 67855714Skris } 67955714Skris } 68055714Skris 681109998Smarkmstatic IMPLEMENT_LHASH_DOALL_ARG_FN(timeout, SSL_SESSION *, TIMEOUT_PARAM *) 682109998Smarkm 68355714Skrisvoid SSL_CTX_flush_sessions(SSL_CTX *s, long t) 68455714Skris { 68555714Skris unsigned long i; 68655714Skris TIMEOUT_PARAM tp; 68755714Skris 68855714Skris tp.ctx=s; 68955714Skris tp.cache=s->sessions; 69055714Skris if (tp.cache == NULL) return; 69155714Skris tp.time=t; 69255714Skris CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); 69355714Skris i=tp.cache->down_load; 69455714Skris tp.cache->down_load=0; 695109998Smarkm lh_doall_arg(tp.cache, LHASH_DOALL_ARG_FN(timeout), &tp); 69655714Skris tp.cache->down_load=i; 69755714Skris CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); 69855714Skris } 69955714Skris 70055714Skrisint ssl_clear_bad_session(SSL *s) 70155714Skris { 70255714Skris if ( (s->session != NULL) && 70355714Skris !(s->shutdown & SSL_SENT_SHUTDOWN) && 70455714Skris !(SSL_in_init(s) || SSL_in_before(s))) 70555714Skris { 70655714Skris SSL_CTX_remove_session(s->ctx,s->session); 70755714Skris return(1); 70855714Skris } 70955714Skris else 71055714Skris return(0); 71155714Skris } 71255714Skris 71355714Skris/* locked by SSL_CTX in the calling function */ 71455714Skrisstatic void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s) 71555714Skris { 71655714Skris if ((s->next == NULL) || (s->prev == NULL)) return; 71755714Skris 71855714Skris if (s->next == (SSL_SESSION *)&(ctx->session_cache_tail)) 71955714Skris { /* last element in list */ 72055714Skris if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head)) 72155714Skris { /* only one element in list */ 72255714Skris ctx->session_cache_head=NULL; 72355714Skris ctx->session_cache_tail=NULL; 72455714Skris } 72555714Skris else 72655714Skris { 72755714Skris ctx->session_cache_tail=s->prev; 72855714Skris s->prev->next=(SSL_SESSION *)&(ctx->session_cache_tail); 72955714Skris } 73055714Skris } 73155714Skris else 73255714Skris { 73355714Skris if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head)) 73455714Skris { /* first element in list */ 73555714Skris ctx->session_cache_head=s->next; 73655714Skris s->next->prev=(SSL_SESSION *)&(ctx->session_cache_head); 73755714Skris } 73855714Skris else 73955714Skris { /* middle of list */ 74055714Skris s->next->prev=s->prev; 74155714Skris s->prev->next=s->next; 74255714Skris } 74355714Skris } 74455714Skris s->prev=s->next=NULL; 74555714Skris } 74655714Skris 74755714Skrisstatic void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s) 74855714Skris { 74955714Skris if ((s->next != NULL) && (s->prev != NULL)) 75055714Skris SSL_SESSION_list_remove(ctx,s); 75155714Skris 75255714Skris if (ctx->session_cache_head == NULL) 75355714Skris { 75455714Skris ctx->session_cache_head=s; 75555714Skris ctx->session_cache_tail=s; 75655714Skris s->prev=(SSL_SESSION *)&(ctx->session_cache_head); 75755714Skris s->next=(SSL_SESSION *)&(ctx->session_cache_tail); 75855714Skris } 75955714Skris else 76055714Skris { 76155714Skris s->next=ctx->session_cache_head; 76255714Skris s->next->prev=s; 76355714Skris s->prev=(SSL_SESSION *)&(ctx->session_cache_head); 76455714Skris ctx->session_cache_head=s; 76555714Skris } 76655714Skris } 76755714Skris 768