xref: /onnv-gate/usr/src/common/openssl/ssl/ssl_sess.c (revision 0:68f95e015346)
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,&copy))
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