1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/ssl/libssl/src/ssl_sess.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,844 @@
1.4 +/* ssl/ssl_sess.c */
1.5 +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
1.6 + * All rights reserved.
1.7 + *
1.8 + * This package is an SSL implementation written
1.9 + * by Eric Young (eay@cryptsoft.com).
1.10 + * The implementation was written so as to conform with Netscapes SSL.
1.11 + *
1.12 + * This library is free for commercial and non-commercial use as long as
1.13 + * the following conditions are aheared to. The following conditions
1.14 + * apply to all code found in this distribution, be it the RC4, RSA,
1.15 + * lhash, DES, etc., code; not just the SSL code. The SSL documentation
1.16 + * included with this distribution is covered by the same copyright terms
1.17 + * except that the holder is Tim Hudson (tjh@cryptsoft.com).
1.18 + *
1.19 + * Copyright remains Eric Young's, and as such any Copyright notices in
1.20 + * the code are not to be removed.
1.21 + * If this package is used in a product, Eric Young should be given attribution
1.22 + * as the author of the parts of the library used.
1.23 + * This can be in the form of a textual message at program startup or
1.24 + * in documentation (online or textual) provided with the package.
1.25 + *
1.26 + * Redistribution and use in source and binary forms, with or without
1.27 + * modification, are permitted provided that the following conditions
1.28 + * are met:
1.29 + * 1. Redistributions of source code must retain the copyright
1.30 + * notice, this list of conditions and the following disclaimer.
1.31 + * 2. Redistributions in binary form must reproduce the above copyright
1.32 + * notice, this list of conditions and the following disclaimer in the
1.33 + * documentation and/or other materials provided with the distribution.
1.34 + * 3. All advertising materials mentioning features or use of this software
1.35 + * must display the following acknowledgement:
1.36 + * "This product includes cryptographic software written by
1.37 + * Eric Young (eay@cryptsoft.com)"
1.38 + * The word 'cryptographic' can be left out if the rouines from the library
1.39 + * being used are not cryptographic related :-).
1.40 + * 4. If you include any Windows specific code (or a derivative thereof) from
1.41 + * the apps directory (application code) you must include an acknowledgement:
1.42 + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
1.43 + *
1.44 + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
1.45 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1.46 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1.47 + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1.48 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1.49 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1.50 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1.51 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1.52 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1.53 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1.54 + * SUCH DAMAGE.
1.55 + *
1.56 + * The licence and distribution terms for any publically available version or
1.57 + * derivative of this code cannot be changed. i.e. this code cannot simply be
1.58 + * copied and put under another distribution licence
1.59 + * [including the GNU Public Licence.]
1.60 + */
1.61 +
1.62 +#include <stdio.h>
1.63 +#include <openssl/lhash.h>
1.64 +#include <openssl/rand.h>
1.65 +#include "ssl_locl.h"
1.66 +
1.67 +static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s);
1.68 +static void SSL_SESSION_list_add(SSL_CTX *ctx,SSL_SESSION *s);
1.69 +static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck);
1.70 +
1.71 +EXPORT_C SSL_SESSION *SSL_get_session(const SSL *ssl)
1.72 +/* aka SSL_get0_session; gets 0 objects, just returns a copy of the pointer */
1.73 + {
1.74 + return(ssl->session);
1.75 + }
1.76 +
1.77 +EXPORT_C SSL_SESSION *SSL_get1_session(SSL *ssl)
1.78 +/* variant of SSL_get_session: caller really gets something */
1.79 + {
1.80 + SSL_SESSION *sess;
1.81 + /* Need to lock this all up rather than just use CRYPTO_add so that
1.82 + * somebody doesn't free ssl->session between when we check it's
1.83 + * non-null and when we up the reference count. */
1.84 + CRYPTO_w_lock(CRYPTO_LOCK_SSL_SESSION);
1.85 + sess = ssl->session;
1.86 + if(sess)
1.87 + sess->references++;
1.88 + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_SESSION);
1.89 + return(sess);
1.90 + }
1.91 +
1.92 +EXPORT_C int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
1.93 + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
1.94 + {
1.95 + return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_SESSION, argl, argp,
1.96 + new_func, dup_func, free_func);
1.97 + }
1.98 +
1.99 +EXPORT_C int SSL_SESSION_set_ex_data(SSL_SESSION *s, int idx, void *arg)
1.100 + {
1.101 + return(CRYPTO_set_ex_data(&s->ex_data,idx,arg));
1.102 + }
1.103 +
1.104 +EXPORT_C void *SSL_SESSION_get_ex_data(const SSL_SESSION *s, int idx)
1.105 + {
1.106 + return(CRYPTO_get_ex_data(&s->ex_data,idx));
1.107 + }
1.108 +
1.109 +EXPORT_C SSL_SESSION *SSL_SESSION_new(void)
1.110 + {
1.111 + SSL_SESSION *ss;
1.112 +
1.113 + ss=(SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION));
1.114 + if (ss == NULL)
1.115 + {
1.116 + SSLerr(SSL_F_SSL_SESSION_NEW,ERR_R_MALLOC_FAILURE);
1.117 + return(0);
1.118 + }
1.119 + memset(ss,0,sizeof(SSL_SESSION));
1.120 +
1.121 + ss->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */
1.122 + ss->references=1;
1.123 + ss->timeout=60*5+4; /* 5 minute timeout by default */
1.124 + ss->time=(unsigned long)time(NULL);
1.125 + ss->prev=NULL;
1.126 + ss->next=NULL;
1.127 + ss->compress_meth=0;
1.128 + CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data);
1.129 + return(ss);
1.130 + }
1.131 +
1.132 +EXPORT_C const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len)
1.133 + {
1.134 + if(len)
1.135 + *len = s->session_id_length;
1.136 + return s->session_id;
1.137 + }
1.138 +
1.139 +/* Even with SSLv2, we have 16 bytes (128 bits) of session ID space. SSLv3/TLSv1
1.140 + * has 32 bytes (256 bits). As such, filling the ID with random gunk repeatedly
1.141 + * until we have no conflict is going to complete in one iteration pretty much
1.142 + * "most" of the time (btw: understatement). So, if it takes us 10 iterations
1.143 + * and we still can't avoid a conflict - well that's a reasonable point to call
1.144 + * it quits. Either the RAND code is broken or someone is trying to open roughly
1.145 + * very close to 2^128 (or 2^256) SSL sessions to our server. How you might
1.146 + * store that many sessions is perhaps a more interesting question ... */
1.147 +
1.148 +#define MAX_SESS_ID_ATTEMPTS 10
1.149 +static int def_generate_session_id(const SSL *ssl, unsigned char *id,
1.150 + unsigned int *id_len)
1.151 +{
1.152 + unsigned int retry = 0;
1.153 + do
1.154 + if (RAND_pseudo_bytes(id, *id_len) <= 0)
1.155 + return 0;
1.156 + while(SSL_has_matching_session_id(ssl, id, *id_len) &&
1.157 + (++retry < MAX_SESS_ID_ATTEMPTS));
1.158 + if(retry < MAX_SESS_ID_ATTEMPTS)
1.159 + return 1;
1.160 + /* else - woops a session_id match */
1.161 + /* XXX We should also check the external cache --
1.162 + * but the probability of a collision is negligible, and
1.163 + * we could not prevent the concurrent creation of sessions
1.164 + * with identical IDs since we currently don't have means
1.165 + * to atomically check whether a session ID already exists
1.166 + * and make a reservation for it if it does not
1.167 + * (this problem applies to the internal cache as well).
1.168 + */
1.169 + return 0;
1.170 +}
1.171 +
1.172 +int ssl_get_new_session(SSL *s, int session)
1.173 + {
1.174 + /* This gets used by clients and servers. */
1.175 +
1.176 + unsigned int tmp;
1.177 + SSL_SESSION *ss=NULL;
1.178 + GEN_SESSION_CB cb = def_generate_session_id;
1.179 +
1.180 + if ((ss=SSL_SESSION_new()) == NULL) return(0);
1.181 +
1.182 + /* If the context has a default timeout, use it */
1.183 + if (s->ctx->session_timeout == 0)
1.184 + ss->timeout=SSL_get_default_timeout(s);
1.185 + else
1.186 + ss->timeout=s->ctx->session_timeout;
1.187 +
1.188 + if (s->session != NULL)
1.189 + {
1.190 + SSL_SESSION_free(s->session);
1.191 + s->session=NULL;
1.192 + }
1.193 +
1.194 + if (session)
1.195 + {
1.196 + if (s->version == SSL2_VERSION)
1.197 + {
1.198 + ss->ssl_version=SSL2_VERSION;
1.199 + ss->session_id_length=SSL2_SSL_SESSION_ID_LENGTH;
1.200 + }
1.201 + else if (s->version == SSL3_VERSION)
1.202 + {
1.203 + ss->ssl_version=SSL3_VERSION;
1.204 + ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
1.205 + }
1.206 + else if (s->version == TLS1_VERSION)
1.207 + {
1.208 + ss->ssl_version=TLS1_VERSION;
1.209 + ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
1.210 + }
1.211 + else if (s->version == DTLS1_VERSION)
1.212 + {
1.213 + ss->ssl_version=DTLS1_VERSION;
1.214 + ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
1.215 + }
1.216 + else
1.217 + {
1.218 + SSLerr(SSL_F_SSL_GET_NEW_SESSION,SSL_R_UNSUPPORTED_SSL_VERSION);
1.219 + SSL_SESSION_free(ss);
1.220 + return(0);
1.221 + }
1.222 + /* Choose which callback will set the session ID */
1.223 + CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
1.224 + if(s->generate_session_id)
1.225 + cb = s->generate_session_id;
1.226 + else if(s->ctx->generate_session_id)
1.227 + cb = s->ctx->generate_session_id;
1.228 + CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
1.229 + /* Choose a session ID */
1.230 + tmp = ss->session_id_length;
1.231 + if(!cb(s, ss->session_id, &tmp))
1.232 + {
1.233 + /* The callback failed */
1.234 + SSLerr(SSL_F_SSL_GET_NEW_SESSION,
1.235 + SSL_R_SSL_SESSION_ID_CALLBACK_FAILED);
1.236 + SSL_SESSION_free(ss);
1.237 + return(0);
1.238 + }
1.239 + /* Don't allow the callback to set the session length to zero.
1.240 + * nor set it higher than it was. */
1.241 + if(!tmp || (tmp > ss->session_id_length))
1.242 + {
1.243 + /* The callback set an illegal length */
1.244 + SSLerr(SSL_F_SSL_GET_NEW_SESSION,
1.245 + SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH);
1.246 + SSL_SESSION_free(ss);
1.247 + return(0);
1.248 + }
1.249 + /* If the session length was shrunk and we're SSLv2, pad it */
1.250 + if((tmp < ss->session_id_length) && (s->version == SSL2_VERSION))
1.251 + memset(ss->session_id + tmp, 0, ss->session_id_length - tmp);
1.252 + else
1.253 + ss->session_id_length = tmp;
1.254 + /* Finally, check for a conflict */
1.255 + if(SSL_has_matching_session_id(s, ss->session_id,
1.256 + ss->session_id_length))
1.257 + {
1.258 + SSLerr(SSL_F_SSL_GET_NEW_SESSION,
1.259 + SSL_R_SSL_SESSION_ID_CONFLICT);
1.260 + SSL_SESSION_free(ss);
1.261 + return(0);
1.262 + }
1.263 + }
1.264 + else
1.265 + {
1.266 + ss->session_id_length=0;
1.267 + }
1.268 +
1.269 + if (s->sid_ctx_length > sizeof ss->sid_ctx)
1.270 + {
1.271 + SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_INTERNAL_ERROR);
1.272 + SSL_SESSION_free(ss);
1.273 + return 0;
1.274 + }
1.275 + memcpy(ss->sid_ctx,s->sid_ctx,s->sid_ctx_length);
1.276 + ss->sid_ctx_length=s->sid_ctx_length;
1.277 + s->session=ss;
1.278 + ss->ssl_version=s->version;
1.279 + ss->verify_result = X509_V_OK;
1.280 +
1.281 + return(1);
1.282 + }
1.283 +
1.284 +int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
1.285 + const unsigned char *limit)
1.286 + {
1.287 + /* This is used only by servers. */
1.288 +
1.289 + SSL_SESSION *ret=NULL;
1.290 + int fatal = 0;
1.291 +
1.292 + if (len > SSL_MAX_SSL_SESSION_ID_LENGTH)
1.293 + goto err;
1.294 +
1.295 + if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
1.296 +
1.297 + {
1.298 + SSL_SESSION data;
1.299 + data.ssl_version=s->version;
1.300 + data.session_id_length=len;
1.301 + if (len == 0)
1.302 + return 0;
1.303 + memcpy(data.session_id,session_id,len);
1.304 + CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
1.305 + ret=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,&data);
1.306 + if (ret != NULL)
1.307 + /* don't allow other threads to steal it: */
1.308 + CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION);
1.309 + CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
1.310 + }
1.311 +
1.312 + if (ret == NULL)
1.313 + {
1.314 + int copy=1;
1.315 +
1.316 + s->ctx->stats.sess_miss++;
1.317 + ret=NULL;
1.318 + if (s->ctx->get_session_cb != NULL
1.319 + && (ret=s->ctx->get_session_cb(s,session_id,len,©))
1.320 + != NULL)
1.321 + {
1.322 + s->ctx->stats.sess_cb_hit++;
1.323 +
1.324 + /* Increment reference count now if the session callback
1.325 + * asks us to do so (note that if the session structures
1.326 + * returned by the callback are shared between threads,
1.327 + * it must handle the reference count itself [i.e. copy == 0],
1.328 + * or things won't be thread-safe). */
1.329 + if (copy)
1.330 + CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION);
1.331 +
1.332 + /* Add the externally cached session to the internal
1.333 + * cache as well if and only if we are supposed to. */
1.334 + if(!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE))
1.335 + /* The following should not return 1, otherwise,
1.336 + * things are very strange */
1.337 + SSL_CTX_add_session(s->ctx,ret);
1.338 + }
1.339 + if (ret == NULL)
1.340 + goto err;
1.341 + }
1.342 +
1.343 + /* Now ret is non-NULL, and we own one of its reference counts. */
1.344 +
1.345 + if (ret->sid_ctx_length != s->sid_ctx_length
1.346 + || memcmp(ret->sid_ctx,s->sid_ctx,ret->sid_ctx_length))
1.347 + {
1.348 + /* We've found the session named by the client, but we don't
1.349 + * want to use it in this context. */
1.350 +
1.351 +#if 0 /* The client cannot always know when a session is not appropriate,
1.352 + * so we shouldn't generate an error message. */
1.353 +
1.354 + SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
1.355 +#endif
1.356 + goto err; /* treat like cache miss */
1.357 + }
1.358 +
1.359 + if((s->verify_mode & SSL_VERIFY_PEER) && s->sid_ctx_length == 0)
1.360 + {
1.361 + /* We can't be sure if this session is being used out of
1.362 + * context, which is especially important for SSL_VERIFY_PEER.
1.363 + * The application should have used SSL[_CTX]_set_session_id_context.
1.364 + *
1.365 + * For this error case, we generate an error instead of treating
1.366 + * the event like a cache miss (otherwise it would be easy for
1.367 + * applications to effectively disable the session cache by
1.368 + * accident without anyone noticing).
1.369 + */
1.370 +
1.371 + SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED);
1.372 + fatal = 1;
1.373 + goto err;
1.374 + }
1.375 +
1.376 + if (ret->cipher == NULL)
1.377 + {
1.378 + unsigned char buf[5],*p;
1.379 + unsigned long l;
1.380 +
1.381 + p=buf;
1.382 + l=ret->cipher_id;
1.383 + l2n(l,p);
1.384 + if ((ret->ssl_version>>8) == SSL3_VERSION_MAJOR)
1.385 + ret->cipher=ssl_get_cipher_by_char(s,&(buf[2]));
1.386 + else
1.387 + ret->cipher=ssl_get_cipher_by_char(s,&(buf[1]));
1.388 + if (ret->cipher == NULL)
1.389 + goto err;
1.390 + }
1.391 +
1.392 +
1.393 +#if 0 /* This is way too late. */
1.394 +
1.395 + /* If a thread got the session, then 'swaped', and another got
1.396 + * it and then due to a time-out decided to 'OPENSSL_free' it we could
1.397 + * be in trouble. So I'll increment it now, then double decrement
1.398 + * later - am I speaking rubbish?. */
1.399 + CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION);
1.400 +#endif
1.401 +
1.402 + if (ret->timeout < (long)(time(NULL) - ret->time)) /* timeout */
1.403 + {
1.404 + s->ctx->stats.sess_timeout++;
1.405 + /* remove it from the cache */
1.406 + SSL_CTX_remove_session(s->ctx,ret);
1.407 + goto err;
1.408 + }
1.409 +
1.410 + s->ctx->stats.sess_hit++;
1.411 +
1.412 + /* ret->time=time(NULL); */ /* rezero timeout? */
1.413 + /* again, just leave the session
1.414 + * if it is the same session, we have just incremented and
1.415 + * then decremented the reference count :-) */
1.416 + if (s->session != NULL)
1.417 + SSL_SESSION_free(s->session);
1.418 + s->session=ret;
1.419 + s->verify_result = s->session->verify_result;
1.420 + return(1);
1.421 +
1.422 + err:
1.423 + if (ret != NULL)
1.424 + SSL_SESSION_free(ret);
1.425 + if (fatal)
1.426 + return -1;
1.427 + else
1.428 + return 0;
1.429 + }
1.430 +
1.431 +EXPORT_C int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c)
1.432 + {
1.433 + int ret=0;
1.434 + SSL_SESSION *s;
1.435 +
1.436 + /* add just 1 reference count for the SSL_CTX's session cache
1.437 + * even though it has two ways of access: each session is in a
1.438 + * doubly linked list and an lhash */
1.439 + CRYPTO_add(&c->references,1,CRYPTO_LOCK_SSL_SESSION);
1.440 + /* if session c is in already in cache, we take back the increment later */
1.441 +
1.442 + CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
1.443 + s=(SSL_SESSION *)lh_insert(ctx->sessions,c);
1.444 +
1.445 + /* s != NULL iff we already had a session with the given PID.
1.446 + * In this case, s == c should hold (then we did not really modify
1.447 + * ctx->sessions), or we're in trouble. */
1.448 + if (s != NULL && s != c)
1.449 + {
1.450 + /* We *are* in trouble ... */
1.451 + SSL_SESSION_list_remove(ctx,s);
1.452 + SSL_SESSION_free(s);
1.453 + /* ... so pretend the other session did not exist in cache
1.454 + * (we cannot handle two SSL_SESSION structures with identical
1.455 + * session ID in the same cache, which could happen e.g. when
1.456 + * two threads concurrently obtain the same session from an external
1.457 + * cache) */
1.458 + s = NULL;
1.459 + }
1.460 +
1.461 + /* Put at the head of the queue unless it is already in the cache */
1.462 + if (s == NULL)
1.463 + SSL_SESSION_list_add(ctx,c);
1.464 +
1.465 + if (s != NULL)
1.466 + {
1.467 + /* existing cache entry -- decrement previously incremented reference
1.468 + * count because it already takes into account the cache */
1.469 +
1.470 + SSL_SESSION_free(s); /* s == c */
1.471 + ret=0;
1.472 + }
1.473 + else
1.474 + {
1.475 + /* new cache entry -- remove old ones if cache has become too large */
1.476 +
1.477 + ret=1;
1.478 +
1.479 + if (SSL_CTX_sess_get_cache_size(ctx) > 0)
1.480 + {
1.481 + while (SSL_CTX_sess_number(ctx) >
1.482 + SSL_CTX_sess_get_cache_size(ctx))
1.483 + {
1.484 + if (!remove_session_lock(ctx,
1.485 + ctx->session_cache_tail, 0))
1.486 + break;
1.487 + else
1.488 + ctx->stats.sess_cache_full++;
1.489 + }
1.490 + }
1.491 + }
1.492 + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
1.493 + return(ret);
1.494 + }
1.495 +
1.496 +EXPORT_C int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *c)
1.497 +{
1.498 + return remove_session_lock(ctx, c, 1);
1.499 +}
1.500 +
1.501 +static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck)
1.502 + {
1.503 + SSL_SESSION *r;
1.504 + int ret=0;
1.505 +
1.506 + if ((c != NULL) && (c->session_id_length != 0))
1.507 + {
1.508 + if(lck) CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
1.509 + if ((r = (SSL_SESSION *)lh_retrieve(ctx->sessions,c)) == c)
1.510 + {
1.511 + ret=1;
1.512 + r=(SSL_SESSION *)lh_delete(ctx->sessions,c);
1.513 + SSL_SESSION_list_remove(ctx,c);
1.514 + }
1.515 +
1.516 + if(lck) CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
1.517 +
1.518 + if (ret)
1.519 + {
1.520 + r->not_resumable=1;
1.521 + if (ctx->remove_session_cb != NULL)
1.522 + ctx->remove_session_cb(ctx,r);
1.523 + SSL_SESSION_free(r);
1.524 + }
1.525 + }
1.526 + else
1.527 + ret=0;
1.528 + return(ret);
1.529 + }
1.530 +
1.531 +EXPORT_C void SSL_SESSION_free(SSL_SESSION *ss)
1.532 + {
1.533 + int i;
1.534 +
1.535 + if(ss == NULL)
1.536 + return;
1.537 +
1.538 + i=CRYPTO_add(&ss->references,-1,CRYPTO_LOCK_SSL_SESSION);
1.539 +#ifdef REF_PRINT
1.540 + REF_PRINT("SSL_SESSION",ss);
1.541 +#endif
1.542 + if (i > 0) return;
1.543 +#ifdef REF_CHECK
1.544 + if (i < 0)
1.545 + {
1.546 + fprintf(stderr,"SSL_SESSION_free, bad reference count\n");
1.547 + abort(); /* ok */
1.548 + }
1.549 +#endif
1.550 +
1.551 + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data);
1.552 +
1.553 + OPENSSL_cleanse(ss->key_arg,sizeof ss->key_arg);
1.554 + OPENSSL_cleanse(ss->master_key,sizeof ss->master_key);
1.555 + OPENSSL_cleanse(ss->session_id,sizeof ss->session_id);
1.556 + if (ss->sess_cert != NULL) ssl_sess_cert_free(ss->sess_cert);
1.557 + if (ss->peer != NULL) X509_free(ss->peer);
1.558 + if (ss->ciphers != NULL) sk_SSL_CIPHER_free(ss->ciphers);
1.559 +
1.560 + OPENSSL_cleanse(ss,sizeof(*ss));
1.561 + OPENSSL_free(ss);
1.562 + }
1.563 +
1.564 +EXPORT_C int SSL_set_session(SSL *s, SSL_SESSION *session)
1.565 + {
1.566 + int ret=0;
1.567 + SSL_METHOD *meth;
1.568 +
1.569 + if (session != NULL)
1.570 + {
1.571 + meth=s->ctx->method->get_ssl_method(session->ssl_version);
1.572 + if (meth == NULL)
1.573 + meth=s->method->get_ssl_method(session->ssl_version);
1.574 + if (meth == NULL)
1.575 + {
1.576 + SSLerr(SSL_F_SSL_SET_SESSION,SSL_R_UNABLE_TO_FIND_SSL_METHOD);
1.577 + return(0);
1.578 + }
1.579 +
1.580 + if (meth != s->method)
1.581 + {
1.582 + if (!SSL_set_ssl_method(s,meth))
1.583 + return(0);
1.584 + if (s->ctx->session_timeout == 0)
1.585 + session->timeout=SSL_get_default_timeout(s);
1.586 + else
1.587 + session->timeout=s->ctx->session_timeout;
1.588 + }
1.589 +
1.590 +#ifndef OPENSSL_NO_KRB5
1.591 + if (s->kssl_ctx && !s->kssl_ctx->client_princ &&
1.592 + session->krb5_client_princ_len > 0)
1.593 + {
1.594 + s->kssl_ctx->client_princ = (char *)OPENSSL_malloc(session->krb5_client_princ_len + 1);
1.595 + memcpy(s->kssl_ctx->client_princ,session->krb5_client_princ,
1.596 + session->krb5_client_princ_len);
1.597 + s->kssl_ctx->client_princ[session->krb5_client_princ_len] = '\0';
1.598 + }
1.599 +#endif /* OPENSSL_NO_KRB5 */
1.600 +
1.601 + /* CRYPTO_w_lock(CRYPTO_LOCK_SSL);*/
1.602 + CRYPTO_add(&session->references,1,CRYPTO_LOCK_SSL_SESSION);
1.603 + if (s->session != NULL)
1.604 + SSL_SESSION_free(s->session);
1.605 + s->session=session;
1.606 + s->verify_result = s->session->verify_result;
1.607 + /* CRYPTO_w_unlock(CRYPTO_LOCK_SSL);*/
1.608 + ret=1;
1.609 + }
1.610 + else
1.611 + {
1.612 + if (s->session != NULL)
1.613 + {
1.614 + SSL_SESSION_free(s->session);
1.615 + s->session=NULL;
1.616 + }
1.617 +
1.618 + meth=s->ctx->method;
1.619 + if (meth != s->method)
1.620 + {
1.621 + if (!SSL_set_ssl_method(s,meth))
1.622 + return(0);
1.623 + }
1.624 + ret=1;
1.625 + }
1.626 + return(ret);
1.627 + }
1.628 +
1.629 +EXPORT_C long SSL_SESSION_set_timeout(SSL_SESSION *s, long t)
1.630 + {
1.631 + if (s == NULL) return(0);
1.632 + s->timeout=t;
1.633 + return(1);
1.634 + }
1.635 +
1.636 +EXPORT_C long SSL_SESSION_get_timeout(const SSL_SESSION *s)
1.637 + {
1.638 + if (s == NULL) return(0);
1.639 + return(s->timeout);
1.640 + }
1.641 +
1.642 +EXPORT_C long SSL_SESSION_get_time(const SSL_SESSION *s)
1.643 + {
1.644 + if (s == NULL) return(0);
1.645 + return(s->time);
1.646 + }
1.647 +
1.648 +EXPORT_C long SSL_SESSION_set_time(SSL_SESSION *s, long t)
1.649 + {
1.650 + if (s == NULL) return(0);
1.651 + s->time=t;
1.652 + return(t);
1.653 + }
1.654 +
1.655 +EXPORT_C long SSL_CTX_set_timeout(SSL_CTX *s, long t)
1.656 + {
1.657 + long l;
1.658 + if (s == NULL) return(0);
1.659 + l=s->session_timeout;
1.660 + s->session_timeout=t;
1.661 + return(l);
1.662 + }
1.663 +
1.664 +EXPORT_C long SSL_CTX_get_timeout(const SSL_CTX *s)
1.665 + {
1.666 + if (s == NULL) return(0);
1.667 + return(s->session_timeout);
1.668 + }
1.669 +
1.670 +typedef struct timeout_param_st
1.671 + {
1.672 + SSL_CTX *ctx;
1.673 + long time;
1.674 + LHASH *cache;
1.675 + } TIMEOUT_PARAM;
1.676 +
1.677 +static void timeout(SSL_SESSION *s, TIMEOUT_PARAM *p)
1.678 + {
1.679 + if ((p->time == 0) || (p->time > (s->time+s->timeout))) /* timeout */
1.680 + {
1.681 + /* The reason we don't call SSL_CTX_remove_session() is to
1.682 + * save on locking overhead */
1.683 + lh_delete(p->cache,s);
1.684 + SSL_SESSION_list_remove(p->ctx,s);
1.685 + s->not_resumable=1;
1.686 + if (p->ctx->remove_session_cb != NULL)
1.687 + p->ctx->remove_session_cb(p->ctx,s);
1.688 + SSL_SESSION_free(s);
1.689 + }
1.690 + }
1.691 +
1.692 +static IMPLEMENT_LHASH_DOALL_ARG_FN(timeout, SSL_SESSION *, TIMEOUT_PARAM *)
1.693 +
1.694 +EXPORT_C void SSL_CTX_flush_sessions(SSL_CTX *s, long t)
1.695 + {
1.696 + unsigned long i;
1.697 + TIMEOUT_PARAM tp;
1.698 +
1.699 + tp.ctx=s;
1.700 + tp.cache=s->sessions;
1.701 + if (tp.cache == NULL) return;
1.702 + tp.time=t;
1.703 + CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
1.704 + i=tp.cache->down_load;
1.705 + tp.cache->down_load=0;
1.706 + lh_doall_arg(tp.cache, LHASH_DOALL_ARG_FN(timeout), &tp);
1.707 + tp.cache->down_load=i;
1.708 + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
1.709 + }
1.710 +
1.711 +int ssl_clear_bad_session(SSL *s)
1.712 + {
1.713 + if ( (s->session != NULL) &&
1.714 + !(s->shutdown & SSL_SENT_SHUTDOWN) &&
1.715 + !(SSL_in_init(s) || SSL_in_before(s)))
1.716 + {
1.717 + SSL_CTX_remove_session(s->ctx,s->session);
1.718 + return(1);
1.719 + }
1.720 + else
1.721 + return(0);
1.722 + }
1.723 +
1.724 +/* locked by SSL_CTX in the calling function */
1.725 +static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s)
1.726 + {
1.727 + if ((s->next == NULL) || (s->prev == NULL)) return;
1.728 +
1.729 + if (s->next == (SSL_SESSION *)&(ctx->session_cache_tail))
1.730 + { /* last element in list */
1.731 + if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head))
1.732 + { /* only one element in list */
1.733 + ctx->session_cache_head=NULL;
1.734 + ctx->session_cache_tail=NULL;
1.735 + }
1.736 + else
1.737 + {
1.738 + ctx->session_cache_tail=s->prev;
1.739 + s->prev->next=(SSL_SESSION *)&(ctx->session_cache_tail);
1.740 + }
1.741 + }
1.742 + else
1.743 + {
1.744 + if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head))
1.745 + { /* first element in list */
1.746 + ctx->session_cache_head=s->next;
1.747 + s->next->prev=(SSL_SESSION *)&(ctx->session_cache_head);
1.748 + }
1.749 + else
1.750 + { /* middle of list */
1.751 + s->next->prev=s->prev;
1.752 + s->prev->next=s->next;
1.753 + }
1.754 + }
1.755 + s->prev=s->next=NULL;
1.756 + }
1.757 +
1.758 +static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s)
1.759 + {
1.760 + if ((s->next != NULL) && (s->prev != NULL))
1.761 + SSL_SESSION_list_remove(ctx,s);
1.762 +
1.763 + if (ctx->session_cache_head == NULL)
1.764 + {
1.765 + ctx->session_cache_head=s;
1.766 + ctx->session_cache_tail=s;
1.767 + s->prev=(SSL_SESSION *)&(ctx->session_cache_head);
1.768 + s->next=(SSL_SESSION *)&(ctx->session_cache_tail);
1.769 + }
1.770 + else
1.771 + {
1.772 + s->next=ctx->session_cache_head;
1.773 + s->next->prev=s;
1.774 + s->prev=(SSL_SESSION *)&(ctx->session_cache_head);
1.775 + ctx->session_cache_head=s;
1.776 + }
1.777 + }
1.778 +
1.779 +EXPORT_C void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx,
1.780 + int (*cb)(struct ssl_st *ssl,SSL_SESSION *sess))
1.781 + {
1.782 + ctx->new_session_cb=cb;
1.783 + }
1.784 +
1.785 +EXPORT_C int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(SSL *ssl, SSL_SESSION *sess)
1.786 + {
1.787 + return ctx->new_session_cb;
1.788 + }
1.789 +
1.790 +EXPORT_C void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx,
1.791 + void (*cb)(SSL_CTX *ctx,SSL_SESSION *sess))
1.792 + {
1.793 + ctx->remove_session_cb=cb;
1.794 + }
1.795 +
1.796 +EXPORT_C void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))(SSL_CTX * ctx,SSL_SESSION *sess)
1.797 + {
1.798 + return ctx->remove_session_cb;
1.799 + }
1.800 +
1.801 +EXPORT_C void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx,
1.802 + SSL_SESSION *(*cb)(struct ssl_st *ssl,
1.803 + unsigned char *data,int len,int *copy))
1.804 + {
1.805 + ctx->get_session_cb=cb;
1.806 + }
1.807 +
1.808 +EXPORT_C SSL_SESSION * (*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))(SSL *ssl,
1.809 + unsigned char *data,int len,int *copy)
1.810 + {
1.811 + return ctx->get_session_cb;
1.812 + }
1.813 +
1.814 +EXPORT_C void SSL_CTX_set_info_callback(SSL_CTX *ctx,
1.815 + void (*cb)(const SSL *ssl,int type,int val))
1.816 + {
1.817 + ctx->info_callback=cb;
1.818 + }
1.819 +
1.820 +EXPORT_C void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl,int type,int val)
1.821 + {
1.822 + return ctx->info_callback;
1.823 + }
1.824 +
1.825 +EXPORT_C void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx,
1.826 + int (*cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey))
1.827 + {
1.828 + ctx->client_cert_cb=cb;
1.829 + }
1.830 +
1.831 +EXPORT_C int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))(SSL * ssl, X509 ** x509 , EVP_PKEY **pkey)
1.832 + {
1.833 + return ctx->client_cert_cb;
1.834 + }
1.835 +
1.836 +EXPORT_C void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx,
1.837 + int (*cb)(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len))
1.838 + {
1.839 + ctx->app_gen_cookie_cb=cb;
1.840 + }
1.841 +
1.842 +EXPORT_C void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx,
1.843 + int (*cb)(SSL *ssl, unsigned char *cookie, unsigned int cookie_len))
1.844 + {
1.845 + ctx->app_verify_cookie_cb=cb;
1.846 + }
1.847 +