Import of old SSLeay release: SSLeay 0.8.1b
[openssl.git] / ssl / ssl_sess.c
1 /* ssl/ssl_sess.c */
2 /* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@cryptsoft.com).
7  * The implementation was written so as to conform with Netscapes SSL.
8  * 
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15  * 
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  * 
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@cryptsoft.com)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from 
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  * 
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  * 
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58
59 #include <stdio.h>
60 #include "lhash.h"
61 #include "rand.h"
62 #include "ssl_locl.h"
63
64 SSL_SESSION *SSL_SESSION_new()
65         {
66         SSL_SESSION *ss;
67
68         ss=(SSL_SESSION *)Malloc(sizeof(SSL_SESSION));
69         if (ss == NULL)
70                 {
71                 SSLerr(SSL_F_SSL_SESSION_NEW,ERR_R_MALLOC_FAILURE);
72                 return(0);
73                 }
74         memset(ss,0,sizeof(SSL_SESSION));
75
76         ss->references=1;
77         ss->timeout=60*5+4; /* 5 minute timeout by default */
78         ss->time=time(NULL);
79         return(ss);
80         }
81
82 int ssl_get_new_session(s, session)
83 SSL *s;
84 int session;
85         {
86         SSL_SESSION *ss=NULL;
87
88         if ((ss=SSL_SESSION_new()) == NULL) return(0);
89
90         /* If the context has a default timeout, use it */
91         if (s->ctx->session_timeout != 0)
92                 ss->timeout=SSL_get_default_timeout(s);
93
94         if (s->session != NULL)
95                 {
96                 SSL_SESSION_free(s->session);
97                 s->session=NULL;
98                 }
99
100         if (session)
101                 {
102                 if (s->version == SSL2_CLIENT_VERSION)
103                         {
104                         ss->ssl_version=2;
105                         ss->session_id_length=SSL2_SSL_SESSION_ID_LENGTH;
106                         }
107                 else if (s->version == SSL3_VERSION_MAJOR)
108                         {
109                         ss->ssl_version=3;
110                         ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
111                         }
112                 else
113                         {
114                         SSLerr(SSL_F_SSL_GET_NEW_SESSION,SSL_R_UNSUPPORTED_SSL_VERSION);
115                         SSL_SESSION_free(ss);
116                         return(0);
117                         }
118
119                 for (;;)
120                         {
121                         SSL_SESSION *r;
122
123                         RAND_bytes(ss->session_id,ss->session_id_length);
124                         CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
125                         r=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,
126                                 (char *)ss);
127                         CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
128                         if (r == NULL) break;
129                         /* else - woops a session_id match */
130                         }
131                 }
132         else
133                 {
134                 ss->session_id_length=0;
135                 }
136
137         s->session=ss;
138         ss->ssl_version=s->version;
139
140         return(1);
141         }
142
143 int ssl_get_prev_session(s, len, session)
144 SSL *s;
145 int len;
146 unsigned char *session;
147         {
148         SSL_SESSION *ret,data;
149
150         /* conn_init();*/
151         data.ssl_version=s->version;
152         data.session_id_length=len;
153         if (len > SSL_MAX_SSL_SESSION_ID_LENGTH)
154                 return(0);
155         memcpy(data.session_id,session,len);;
156
157         CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
158         ret=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,(char *)&data);
159         CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
160
161         if (ret == NULL)
162                 {
163                 int copy=1;
164
165                 s->ctx->sess_miss++;
166                 ret=NULL;
167                 if ((s->ctx->get_session_cb != NULL) &&
168                         ((ret=s->ctx->get_session_cb(s,session,len,&copy))
169                                 != NULL))
170                         {
171                         s->ctx->sess_cb_hit++;
172
173                         /* The following should not return 1, otherwise,
174                          * things are very strange */
175                         SSL_CTX_add_session(s->ctx,ret);
176                         /* auto free it */
177                         if (!copy)
178                                 SSL_SESSION_free(ret);
179                         }
180                 if (ret == NULL) return(0);
181                 }
182
183         if (ret->cipher == NULL)
184                 {
185                 char buf[5],*p;
186                 unsigned long l;
187
188                 p=buf;
189                 l=ret->cipher_id;
190                 l2n(l,p);
191                 if (ret->ssl_version == 3)
192                         ret->cipher=ssl_get_cipher_by_char(s,&(buf[2]));
193                 else 
194                         ret->cipher=ssl_get_cipher_by_char(s,&(buf[1]));
195                 if (ret->cipher == NULL)
196                         return(0);
197                 }
198
199         /* If a thread got the session, then 'swaped', and another got
200          * it and then due to a time-out decided to 'Free' it we could
201          * be in trouble.  So I'll increment it now, then double decrement
202          * later - am I speaking rubbish?. */
203         CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION);
204
205         if ((long)(ret->time+ret->timeout) < (long)time(NULL)) /* timeout */
206                 {
207                 s->ctx->sess_timeout++;
208                 /* remove it from the cache */
209                 SSL_CTX_remove_session(s->ctx,ret);
210                 SSL_SESSION_free(ret);          /* again to actually Free it */
211                 return(0);
212                 }
213
214         s->ctx->sess_hit++;
215
216         /* ret->time=time(NULL); */ /* rezero timeout? */
217         /* again, just leave the session 
218          * if it is the same session, we have just incremented and
219          * then decremented the reference count :-) */
220         if (s->session != NULL)
221                 SSL_SESSION_free(s->session);
222         s->session=ret;
223         return(1);
224         }
225
226 int SSL_CTX_add_session(ctx,c)
227 SSL_CTX *ctx;
228 SSL_SESSION *c;
229         {
230         SSL_SESSION *s;
231
232         /* conn_init(); */
233         CRYPTO_add(&c->references,1,CRYPTO_LOCK_SSL_SESSION);
234
235         CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
236         s=(SSL_SESSION *)lh_insert(ctx->sessions,(char *)c);
237         CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
238
239         /* If the same session if is being 're-added', Free the old
240          * one when the last person stops using it.
241          * This will also work if it is alread in the cache.
242          * The references will go up and then down :-) */
243         if (s != NULL)
244                 {
245                 SSL_SESSION_free(s);
246                 return(0);
247                 }
248         else
249                 return(1);
250         }
251
252 int SSL_CTX_remove_session(ctx,c)
253 SSL_CTX *ctx;
254 SSL_SESSION *c;
255         {
256         SSL_SESSION *r;
257         int ret=0;
258
259         if ((c->session_id_length != 0) && (c != NULL))
260                 {
261                 CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
262                 r=(SSL_SESSION *)lh_delete(ctx->sessions,(char *)c);
263                 if (r != NULL) ret=1;
264
265                 CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
266
267                 if (ret)
268                         {
269                         r->not_resumable=1;
270                         if (ctx->remove_session_cb != NULL)
271                                 ctx->remove_session_cb(ctx,c);
272                         SSL_SESSION_free(r);
273                         }
274                 }
275         else
276                 ret=0;
277         return(ret);
278         }
279
280 void SSL_SESSION_free(ss)
281 SSL_SESSION *ss;
282         {
283         int i;
284
285         i=CRYPTO_add(&ss->references,-1,CRYPTO_LOCK_SSL_SESSION);
286         if (i > 0) return;
287 #ifdef REF_CHECK
288         if (i < 0)
289                 {
290                 fprintf(stderr,"SSL_SESSION_free, bad reference count\n");
291                 abort(); /* ok */
292                 }
293 #endif
294
295         memset(ss->key_arg,0,SSL_MAX_KEY_ARG_LENGTH);
296         memset(ss->master_key,0,SSL_MAX_MASTER_KEY_LENGTH);
297         memset(ss->session_id,0,SSL_MAX_SSL_SESSION_ID_LENGTH);
298         if (ss->cert != NULL) ssl_cert_free(ss->cert);
299         if (ss->peer != NULL) X509_free(ss->peer);
300         if (ss->ciphers != NULL) sk_free(ss->ciphers);
301         memset(ss,0,sizeof(*ss));
302         Free(ss);
303         }
304
305 int SSL_set_session(s, session)
306 SSL *s;
307 SSL_SESSION *session;
308         {
309         int ret=0;
310         SSL_METHOD *meth;
311
312         if (session != NULL)
313                 {
314                 meth=s->ctx->method->get_ssl_method(session->ssl_version);
315                 if (meth == NULL)
316                         meth=s->method->get_ssl_method(session->ssl_version);
317                 if (meth == NULL)
318                         {
319                         SSLerr(SSL_F_SSL_SET_SESSION,SSL_R_UNABLE_TO_FIND_SSL_METHOD);
320                         return(0);
321                         }
322
323                 if (meth != s->method)
324                         {
325                         if (!SSL_set_ssl_method(s,meth))
326                                 return(0);
327                         session->timeout=SSL_get_default_timeout(s);
328                         }
329
330                 /* CRYPTO_w_lock(CRYPTO_LOCK_SSL);*/
331                 CRYPTO_add(&session->references,1,CRYPTO_LOCK_SSL_SESSION);
332                 if (s->session != NULL)
333                         SSL_SESSION_free(s->session);
334                 s->session=session;
335                 /* CRYPTO_w_unlock(CRYPTO_LOCK_SSL);*/
336                 ret=1;
337                 }
338         return(ret);
339         }
340
341 long SSL_set_timeout(s,t)
342 SSL_SESSION *s;
343 long t;
344         {
345         if (s == NULL) return(0);
346         s->timeout=t;
347         return(1);
348         }
349
350 long SSL_get_timeout(s)
351 SSL_SESSION *s;
352         {
353         if (s == NULL) return(0);
354         return(s->timeout);
355         }
356
357 long SSL_get_time(s)
358 SSL_SESSION *s;
359         {
360         if (s == NULL) return(0);
361         return(s->time);
362         }
363
364 long SSL_set_time(s,t)
365 SSL_SESSION *s;
366 long t;
367         {
368         if (s == NULL) return(0);
369         s->time=t;
370         return(t);
371         }
372
373 typedef struct timeout_param_st
374         {
375         SSL_CTX *ctx;
376         long time;
377         LHASH *cache;
378         } TIMEOUT_PARAM;
379
380 static void timeout(s,p)
381 SSL_SESSION *s;
382 TIMEOUT_PARAM *p;
383         {
384         if ((p->time == 0) || (p->time > (s->time+s->timeout))) /* timeout */
385                 {
386                 lh_delete(p->cache,(char *)s);
387                 s->not_resumable=1;
388                 if (p->ctx->remove_session_cb != NULL)
389                         p->ctx->remove_session_cb(p->ctx,s);
390                 SSL_SESSION_free(s);
391                 }
392         }
393
394 void SSL_CTX_flush_sessions(s,t)
395 SSL_CTX *s;
396 long t;
397         {
398         unsigned long i;
399         TIMEOUT_PARAM tp;
400
401         tp.ctx=s;
402         tp.cache=SSL_CTX_sessions(s);
403         if (tp.cache == NULL) return;
404         tp.time=t;
405         CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
406         i=tp.cache->down_load;
407         tp.cache->down_load=0;
408         lh_doall_arg(tp.cache,(void (*)())timeout,(char *)&tp);
409         tp.cache->down_load=i;
410         CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
411         }
412
413 int ssl_clear_bad_session(s)
414 SSL *s;
415         {
416         if (    (s->session != NULL) &&
417                 !(s->shutdown & SSL_SENT_SHUTDOWN) &&
418                 !(SSL_in_init(s) || SSL_in_before(s)))
419                 {
420                 SSL_CTX_remove_session(s->ctx,s->session);
421                 return(1);
422                 }
423         else
424                 return(0);
425         }