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.
8296465Sdelphij *
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).
15296465Sdelphij *
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.
22296465Sdelphij *
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 :-).
37296465Sdelphij * 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)"
40296465Sdelphij *
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.
52296465Sdelphij *
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>
62194206Ssimon#ifndef OPENSSL_NO_ENGINE
63296465Sdelphij# include <openssl/engine.h>
64194206Ssimon#endif
6555714Skris#include "ssl_locl.h"
6655714Skris
6755714Skrisstatic void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s);
68296465Sdelphijstatic void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s);
6955714Skrisstatic int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck);
7055714Skris
71160814SsimonSSL_SESSION *SSL_get_session(const SSL *ssl)
7259191Skris/* aka SSL_get0_session; gets 0 objects, just returns a copy of the pointer */
73296465Sdelphij{
74296465Sdelphij    return (ssl->session);
75296465Sdelphij}
7655714Skris
7759191SkrisSSL_SESSION *SSL_get1_session(SSL *ssl)
7859191Skris/* variant of SSL_get_session: caller really gets something */
79296465Sdelphij{
80296465Sdelphij    SSL_SESSION *sess;
81296465Sdelphij    /*
82296465Sdelphij     * Need to lock this all up rather than just use CRYPTO_add so that
83296465Sdelphij     * somebody doesn't free ssl->session between when we check it's non-null
84296465Sdelphij     * and when we up the reference count.
85296465Sdelphij     */
86296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_SSL_SESSION);
87296465Sdelphij    sess = ssl->session;
88296465Sdelphij    if (sess)
89296465Sdelphij        sess->references++;
90296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_SSL_SESSION);
91296465Sdelphij    return (sess);
92296465Sdelphij}
9359191Skris
94296465Sdelphijint SSL_SESSION_get_ex_new_index(long argl, void *argp,
95296465Sdelphij                                 CRYPTO_EX_new *new_func,
96296465Sdelphij                                 CRYPTO_EX_dup *dup_func,
97296465Sdelphij                                 CRYPTO_EX_free *free_func)
98296465Sdelphij{
99296465Sdelphij    return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_SESSION, argl, argp,
100296465Sdelphij                                   new_func, dup_func, free_func);
101296465Sdelphij}
10255714Skris
10355714Skrisint SSL_SESSION_set_ex_data(SSL_SESSION *s, int idx, void *arg)
104296465Sdelphij{
105296465Sdelphij    return (CRYPTO_set_ex_data(&s->ex_data, idx, arg));
106296465Sdelphij}
10755714Skris
108160814Ssimonvoid *SSL_SESSION_get_ex_data(const SSL_SESSION *s, int idx)
109296465Sdelphij{
110296465Sdelphij    return (CRYPTO_get_ex_data(&s->ex_data, idx));
111296465Sdelphij}
11255714Skris
11355714SkrisSSL_SESSION *SSL_SESSION_new(void)
114296465Sdelphij{
115296465Sdelphij    SSL_SESSION *ss;
11655714Skris
117296465Sdelphij    ss = (SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION));
118296465Sdelphij    if (ss == NULL) {
119296465Sdelphij        SSLerr(SSL_F_SSL_SESSION_NEW, ERR_R_MALLOC_FAILURE);
120296465Sdelphij        return (0);
121296465Sdelphij    }
122296465Sdelphij    memset(ss, 0, sizeof(SSL_SESSION));
12355714Skris
124296465Sdelphij    ss->verify_result = 1;      /* avoid 0 (= X509_V_OK) just in case */
125296465Sdelphij    ss->references = 1;
126296465Sdelphij    ss->timeout = 60 * 5 + 4;   /* 5 minute timeout by default */
127296465Sdelphij    ss->time = (unsigned long)time(NULL);
128296465Sdelphij    ss->prev = NULL;
129296465Sdelphij    ss->next = NULL;
130296465Sdelphij    ss->compress_meth = 0;
131194206Ssimon#ifndef OPENSSL_NO_TLSEXT
132296465Sdelphij    ss->tlsext_hostname = NULL;
133194206Ssimon#endif
134296465Sdelphij    CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data);
135296465Sdelphij    return (ss);
136296465Sdelphij}
13755714Skris
138284295Sdelphij/*
139284295Sdelphij * Create a new SSL_SESSION and duplicate the contents of |src| into it. If
140284295Sdelphij * ticket == 0 then no ticket information is duplicated, otherwise it is.
141284295Sdelphij */
142284295SdelphijSSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket)
143284295Sdelphij{
144284295Sdelphij    SSL_SESSION *dest;
145284295Sdelphij
146284295Sdelphij    dest = OPENSSL_malloc(sizeof(*src));
147284295Sdelphij    if (dest == NULL) {
148284295Sdelphij        goto err;
149284295Sdelphij    }
150284295Sdelphij    memcpy(dest, src, sizeof(*dest));
151284295Sdelphij
152284295Sdelphij    /*
153284295Sdelphij     * Set the various pointers to NULL so that we can call SSL_SESSION_free in
154284295Sdelphij     * the case of an error whilst halfway through constructing dest
155284295Sdelphij     */
156284295Sdelphij    dest->ciphers = NULL;
157284295Sdelphij#ifndef OPENSSL_NO_TLSEXT
158284295Sdelphij    dest->tlsext_hostname = NULL;
159296465Sdelphij    dest->tlsext_tick = NULL;
160284295Sdelphij#endif
161284295Sdelphij    memset(&dest->ex_data, 0, sizeof(dest->ex_data));
162284295Sdelphij
163284295Sdelphij    /* We deliberately don't copy the prev and next pointers */
164284295Sdelphij    dest->prev = NULL;
165284295Sdelphij    dest->next = NULL;
166284295Sdelphij
167284295Sdelphij    dest->references = 1;
168284295Sdelphij
169284295Sdelphij    if (src->sess_cert != NULL)
170284295Sdelphij        CRYPTO_add(&src->sess_cert->references, 1, CRYPTO_LOCK_SSL_SESS_CERT);
171284295Sdelphij
172284295Sdelphij    if (src->peer != NULL)
173284295Sdelphij        CRYPTO_add(&src->peer->references, 1, CRYPTO_LOCK_X509);
174284295Sdelphij
175284295Sdelphij    if(src->ciphers != NULL) {
176284295Sdelphij        dest->ciphers = sk_SSL_CIPHER_dup(src->ciphers);
177284295Sdelphij        if (dest->ciphers == NULL)
178284295Sdelphij            goto err;
179284295Sdelphij    }
180284295Sdelphij
181284295Sdelphij    if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_SSL_SESSION,
182284295Sdelphij                                            &dest->ex_data, &src->ex_data)) {
183284295Sdelphij        goto err;
184284295Sdelphij    }
185284295Sdelphij
186284295Sdelphij#ifndef OPENSSL_NO_TLSEXT
187284295Sdelphij    if (src->tlsext_hostname) {
188284295Sdelphij        dest->tlsext_hostname = BUF_strdup(src->tlsext_hostname);
189284295Sdelphij        if (dest->tlsext_hostname == NULL) {
190284295Sdelphij            goto err;
191284295Sdelphij        }
192284295Sdelphij    }
193284295Sdelphij
194284295Sdelphij    if (ticket != 0) {
195284295Sdelphij        dest->tlsext_tick = BUF_memdup(src->tlsext_tick, src->tlsext_ticklen);
196284295Sdelphij        if(dest->tlsext_tick == NULL)
197284295Sdelphij            goto err;
198284295Sdelphij    } else {
199284295Sdelphij        dest->tlsext_tick_lifetime_hint = 0;
200284295Sdelphij        dest->tlsext_ticklen = 0;
201284295Sdelphij    }
202296465Sdelphij#endif
203284295Sdelphij
204284295Sdelphij    return dest;
205284295Sdelphijerr:
206284295Sdelphij    SSLerr(SSL_F_SSL_SESSION_DUP, ERR_R_MALLOC_FAILURE);
207284295Sdelphij    SSL_SESSION_free(dest);
208284295Sdelphij    return NULL;
209284295Sdelphij}
210284295Sdelphij
211296465Sdelphijconst unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s,
212296465Sdelphij                                        unsigned int *len)
213296465Sdelphij{
214296465Sdelphij    if (len)
215296465Sdelphij        *len = s->session_id_length;
216296465Sdelphij    return s->session_id;
217296465Sdelphij}
218160814Ssimon
219296465Sdelphij/*
220296465Sdelphij * Even with SSLv2, we have 16 bytes (128 bits) of session ID space.
221296465Sdelphij * SSLv3/TLSv1 has 32 bytes (256 bits). As such, filling the ID with random
222296465Sdelphij * gunk repeatedly until we have no conflict is going to complete in one
223296465Sdelphij * iteration pretty much "most" of the time (btw: understatement). So, if it
224296465Sdelphij * takes us 10 iterations and we still can't avoid a conflict - well that's a
225296465Sdelphij * reasonable point to call it quits. Either the RAND code is broken or
226296465Sdelphij * someone is trying to open roughly very close to 2^128 (or 2^256) SSL
227296465Sdelphij * sessions to our server. How you might store that many sessions is perhaps
228296465Sdelphij * a more interesting question ...
229296465Sdelphij */
230109998Smarkm
231109998Smarkm#define MAX_SESS_ID_ATTEMPTS 10
232109998Smarkmstatic int def_generate_session_id(const SSL *ssl, unsigned char *id,
233296465Sdelphij                                   unsigned int *id_len)
234109998Smarkm{
235296465Sdelphij    unsigned int retry = 0;
236296465Sdelphij    do
237296465Sdelphij        if (RAND_pseudo_bytes(id, *id_len) <= 0)
238296465Sdelphij            return 0;
239296465Sdelphij    while (SSL_has_matching_session_id(ssl, id, *id_len) &&
240296465Sdelphij           (++retry < MAX_SESS_ID_ATTEMPTS)) ;
241296465Sdelphij    if (retry < MAX_SESS_ID_ATTEMPTS)
242296465Sdelphij        return 1;
243296465Sdelphij    /* else - woops a session_id match */
244296465Sdelphij    /*
245296465Sdelphij     * XXX We should also check the external cache -- but the probability of
246296465Sdelphij     * a collision is negligible, and we could not prevent the concurrent
247296465Sdelphij     * creation of sessions with identical IDs since we currently don't have
248296465Sdelphij     * means to atomically check whether a session ID already exists and make
249296465Sdelphij     * a reservation for it if it does not (this problem applies to the
250296465Sdelphij     * internal cache as well).
251296465Sdelphij     */
252296465Sdelphij    return 0;
253109998Smarkm}
254109998Smarkm
25555714Skrisint ssl_get_new_session(SSL *s, int session)
256296465Sdelphij{
257296465Sdelphij    /* This gets used by clients and servers. */
25855714Skris
259296465Sdelphij    unsigned int tmp;
260296465Sdelphij    SSL_SESSION *ss = NULL;
261296465Sdelphij    GEN_SESSION_CB cb = def_generate_session_id;
26255714Skris
263296465Sdelphij    if ((ss = SSL_SESSION_new()) == NULL)
264296465Sdelphij        return (0);
26555714Skris
266296465Sdelphij    /* If the context has a default timeout, use it */
267296465Sdelphij    if (s->ctx->session_timeout == 0)
268296465Sdelphij        ss->timeout = SSL_get_default_timeout(s);
269296465Sdelphij    else
270296465Sdelphij        ss->timeout = s->ctx->session_timeout;
27155714Skris
272296465Sdelphij    if (s->session != NULL) {
273296465Sdelphij        SSL_SESSION_free(s->session);
274296465Sdelphij        s->session = NULL;
275296465Sdelphij    }
27655714Skris
277296465Sdelphij    if (session) {
278296465Sdelphij        if (s->version == SSL2_VERSION) {
279296465Sdelphij            ss->ssl_version = SSL2_VERSION;
280296465Sdelphij            ss->session_id_length = SSL2_SSL_SESSION_ID_LENGTH;
281296465Sdelphij        } else if (s->version == SSL3_VERSION) {
282296465Sdelphij            ss->ssl_version = SSL3_VERSION;
283296465Sdelphij            ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
284296465Sdelphij        } else if (s->version == TLS1_VERSION) {
285296465Sdelphij            ss->ssl_version = TLS1_VERSION;
286296465Sdelphij            ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
287296465Sdelphij        } else if (s->version == DTLS1_BAD_VER) {
288296465Sdelphij            ss->ssl_version = DTLS1_BAD_VER;
289296465Sdelphij            ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
290296465Sdelphij        } else if (s->version == DTLS1_VERSION) {
291296465Sdelphij            ss->ssl_version = DTLS1_VERSION;
292296465Sdelphij            ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
293296465Sdelphij        } else {
294296465Sdelphij            SSLerr(SSL_F_SSL_GET_NEW_SESSION, SSL_R_UNSUPPORTED_SSL_VERSION);
295296465Sdelphij            SSL_SESSION_free(ss);
296296465Sdelphij            return (0);
297296465Sdelphij        }
298194206Ssimon#ifndef OPENSSL_NO_TLSEXT
299296465Sdelphij        /* If RFC4507 ticket use empty session ID */
300296465Sdelphij        if (s->tlsext_ticket_expected) {
301296465Sdelphij            ss->session_id_length = 0;
302296465Sdelphij            goto sess_id_done;
303296465Sdelphij        }
304194206Ssimon#endif
305296465Sdelphij        /* Choose which callback will set the session ID */
306296465Sdelphij        CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
307296465Sdelphij        if (s->generate_session_id)
308296465Sdelphij            cb = s->generate_session_id;
309296465Sdelphij        else if (s->ctx->generate_session_id)
310296465Sdelphij            cb = s->ctx->generate_session_id;
311296465Sdelphij        CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
312296465Sdelphij        /* Choose a session ID */
313296465Sdelphij        tmp = ss->session_id_length;
314296465Sdelphij        if (!cb(s, ss->session_id, &tmp)) {
315296465Sdelphij            /* The callback failed */
316296465Sdelphij            SSLerr(SSL_F_SSL_GET_NEW_SESSION,
317296465Sdelphij                   SSL_R_SSL_SESSION_ID_CALLBACK_FAILED);
318296465Sdelphij            SSL_SESSION_free(ss);
319296465Sdelphij            return (0);
320296465Sdelphij        }
321296465Sdelphij        /*
322296465Sdelphij         * Don't allow the callback to set the session length to zero. nor
323296465Sdelphij         * set it higher than it was.
324296465Sdelphij         */
325296465Sdelphij        if (!tmp || (tmp > ss->session_id_length)) {
326296465Sdelphij            /* The callback set an illegal length */
327296465Sdelphij            SSLerr(SSL_F_SSL_GET_NEW_SESSION,
328296465Sdelphij                   SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH);
329296465Sdelphij            SSL_SESSION_free(ss);
330296465Sdelphij            return (0);
331296465Sdelphij        }
332296465Sdelphij        /* If the session length was shrunk and we're SSLv2, pad it */
333296465Sdelphij        if ((tmp < ss->session_id_length) && (s->version == SSL2_VERSION))
334296465Sdelphij            memset(ss->session_id + tmp, 0, ss->session_id_length - tmp);
335296465Sdelphij        else
336296465Sdelphij            ss->session_id_length = tmp;
337296465Sdelphij        /* Finally, check for a conflict */
338296465Sdelphij        if (SSL_has_matching_session_id(s, ss->session_id,
339296465Sdelphij                                        ss->session_id_length)) {
340296465Sdelphij            SSLerr(SSL_F_SSL_GET_NEW_SESSION, SSL_R_SSL_SESSION_ID_CONFLICT);
341296465Sdelphij            SSL_SESSION_free(ss);
342296465Sdelphij            return (0);
343296465Sdelphij        }
344194206Ssimon#ifndef OPENSSL_NO_TLSEXT
345296465Sdelphij sess_id_done:
346296465Sdelphij        if (s->tlsext_hostname) {
347296465Sdelphij            ss->tlsext_hostname = BUF_strdup(s->tlsext_hostname);
348296465Sdelphij            if (ss->tlsext_hostname == NULL) {
349296465Sdelphij                SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_INTERNAL_ERROR);
350296465Sdelphij                SSL_SESSION_free(ss);
351296465Sdelphij                return 0;
352296465Sdelphij            }
353296465Sdelphij        }
354194206Ssimon#endif
355296465Sdelphij    } else {
356296465Sdelphij        ss->session_id_length = 0;
357296465Sdelphij    }
35855714Skris
359296465Sdelphij    if (s->sid_ctx_length > sizeof ss->sid_ctx) {
360296465Sdelphij        SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_INTERNAL_ERROR);
361296465Sdelphij        SSL_SESSION_free(ss);
362296465Sdelphij        return 0;
363296465Sdelphij    }
364296465Sdelphij    memcpy(ss->sid_ctx, s->sid_ctx, s->sid_ctx_length);
365296465Sdelphij    ss->sid_ctx_length = s->sid_ctx_length;
366296465Sdelphij    s->session = ss;
367296465Sdelphij    ss->ssl_version = s->version;
368296465Sdelphij    ss->verify_result = X509_V_OK;
36955714Skris
370296465Sdelphij    return (1);
371296465Sdelphij}
37255714Skris
373194206Ssimonint ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
374296465Sdelphij                         const unsigned char *limit)
375296465Sdelphij{
376296465Sdelphij    /* This is used only by servers. */
37755714Skris
378296465Sdelphij    SSL_SESSION *ret = NULL;
379296465Sdelphij    int fatal = 0;
380194206Ssimon#ifndef OPENSSL_NO_TLSEXT
381296465Sdelphij    int r;
382194206Ssimon#endif
383296465Sdelphij
384296465Sdelphij    if (len > SSL_MAX_SSL_SESSION_ID_LENGTH)
385296465Sdelphij        goto err;
386296465Sdelphij
387306230Sdelphij    if (limit - session_id < len) {
388296465Sdelphij        fatal = 1;
389296465Sdelphij        goto err;
390296465Sdelphij    }
391296465Sdelphij
392194206Ssimon#ifndef OPENSSL_NO_TLSEXT
393296465Sdelphij    r = tls1_process_ticket(s, session_id, len, limit, &ret);
394296465Sdelphij    if (r == -1) {
395296465Sdelphij        fatal = 1;
396296465Sdelphij        goto err;
397296465Sdelphij    } else if (r == 0 || (!ret && !len))
398296465Sdelphij        goto err;
399296465Sdelphij    else if (!ret
400296465Sdelphij             && !(s->session_ctx->session_cache_mode &
401296465Sdelphij                  SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
402194206Ssimon#else
403296465Sdelphij    if (len == 0)
404296465Sdelphij        goto err;
405296465Sdelphij    if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
406194206Ssimon#endif
407296465Sdelphij    {
408296465Sdelphij        SSL_SESSION data;
409296465Sdelphij        data.ssl_version = s->version;
410296465Sdelphij        data.session_id_length = len;
411296465Sdelphij        if (len == 0)
412296465Sdelphij            return 0;
413296465Sdelphij        memcpy(data.session_id, session_id, len);
414296465Sdelphij        CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
415296465Sdelphij        ret = (SSL_SESSION *)lh_retrieve(s->ctx->sessions, &data);
416296465Sdelphij        if (ret != NULL)
417296465Sdelphij            /* don't allow other threads to steal it: */
418296465Sdelphij            CRYPTO_add(&ret->references, 1, CRYPTO_LOCK_SSL_SESSION);
419296465Sdelphij        CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
420296465Sdelphij    }
42155714Skris
422296465Sdelphij    if (ret == NULL) {
423296465Sdelphij        int copy = 1;
42455714Skris
425296465Sdelphij        s->ctx->stats.sess_miss++;
426296465Sdelphij        ret = NULL;
427296465Sdelphij        if (s->ctx->get_session_cb != NULL
428296465Sdelphij            && (ret = s->ctx->get_session_cb(s, session_id, len, &copy))
429296465Sdelphij            != NULL) {
430296465Sdelphij            s->ctx->stats.sess_cb_hit++;
43155714Skris
432296465Sdelphij            /*
433296465Sdelphij             * Increment reference count now if the session callback asks us
434296465Sdelphij             * to do so (note that if the session structures returned by the
435296465Sdelphij             * callback are shared between threads, it must handle the
436296465Sdelphij             * reference count itself [i.e. copy == 0], or things won't be
437296465Sdelphij             * thread-safe).
438296465Sdelphij             */
439296465Sdelphij            if (copy)
440296465Sdelphij                CRYPTO_add(&ret->references, 1, CRYPTO_LOCK_SSL_SESSION);
44155714Skris
442296465Sdelphij            /*
443296465Sdelphij             * Add the externally cached session to the internal cache as
444296465Sdelphij             * well if and only if we are supposed to.
445296465Sdelphij             */
446296465Sdelphij            if (!
447296465Sdelphij                (s->
448296465Sdelphij                 ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE))
449296465Sdelphij                /*
450296465Sdelphij                 * The following should not return 1, otherwise, things are
451296465Sdelphij                 * very strange
452296465Sdelphij                 */
453296465Sdelphij                SSL_CTX_add_session(s->ctx, ret);
454296465Sdelphij        }
455296465Sdelphij        if (ret == NULL)
456296465Sdelphij            goto err;
457296465Sdelphij    }
45855714Skris
459296465Sdelphij    /* Now ret is non-NULL, and we own one of its reference counts. */
46055714Skris
461296465Sdelphij    if (ret->sid_ctx_length != s->sid_ctx_length
462296465Sdelphij        || memcmp(ret->sid_ctx, s->sid_ctx, ret->sid_ctx_length)) {
463296465Sdelphij        /*
464296465Sdelphij         * We've found the session named by the client, but we don't want to
465296465Sdelphij         * use it in this context.
466296465Sdelphij         */
46755714Skris
468296465Sdelphij#if 0                           /* The client cannot always know when a
469296465Sdelphij                                 * session is not appropriate, so we
470296465Sdelphij                                 * shouldn't generate an error message. */
471296465Sdelphij
472296465Sdelphij        SSLerr(SSL_F_SSL_GET_PREV_SESSION,
473296465Sdelphij               SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
47455714Skris#endif
475296465Sdelphij        goto err;               /* treat like cache miss */
476296465Sdelphij    }
47755714Skris
478296465Sdelphij    if ((s->verify_mode & SSL_VERIFY_PEER) && s->sid_ctx_length == 0) {
479296465Sdelphij        /*
480296465Sdelphij         * We can't be sure if this session is being used out of context,
481296465Sdelphij         * which is especially important for SSL_VERIFY_PEER. The application
482296465Sdelphij         * should have used SSL[_CTX]_set_session_id_context. For this error
483296465Sdelphij         * case, we generate an error instead of treating the event like a
484296465Sdelphij         * cache miss (otherwise it would be easy for applications to
485296465Sdelphij         * effectively disable the session cache by accident without anyone
486296465Sdelphij         * noticing).
487296465Sdelphij         */
48855714Skris
489296465Sdelphij        SSLerr(SSL_F_SSL_GET_PREV_SESSION,
490296465Sdelphij               SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED);
491296465Sdelphij        fatal = 1;
492296465Sdelphij        goto err;
493296465Sdelphij    }
49455714Skris
495296465Sdelphij    if (ret->cipher == NULL) {
496296465Sdelphij        unsigned char buf[5], *p;
497296465Sdelphij        unsigned long l;
49855714Skris
499296465Sdelphij        p = buf;
500296465Sdelphij        l = ret->cipher_id;
501296465Sdelphij        l2n(l, p);
502296465Sdelphij        if ((ret->ssl_version >> 8) >= SSL3_VERSION_MAJOR)
503296465Sdelphij            ret->cipher = ssl_get_cipher_by_char(s, &(buf[2]));
504296465Sdelphij        else
505296465Sdelphij            ret->cipher = ssl_get_cipher_by_char(s, &(buf[1]));
506296465Sdelphij        if (ret->cipher == NULL)
507296465Sdelphij            goto err;
508296465Sdelphij    }
509296465Sdelphij#if 0                           /* This is way too late. */
51055714Skris
511296465Sdelphij    /*
512296465Sdelphij     * If a thread got the session, then 'swaped', and another got it and
513296465Sdelphij     * then due to a time-out decided to 'OPENSSL_free' it we could be in
514296465Sdelphij     * trouble.  So I'll increment it now, then double decrement later - am I
515296465Sdelphij     * speaking rubbish?.
516296465Sdelphij     */
517296465Sdelphij    CRYPTO_add(&ret->references, 1, CRYPTO_LOCK_SSL_SESSION);
51855714Skris#endif
51955714Skris
520296465Sdelphij    if (ret->timeout < (long)(time(NULL) - ret->time)) { /* timeout */
521296465Sdelphij        s->ctx->stats.sess_timeout++;
522296465Sdelphij        /* remove it from the cache */
523296465Sdelphij        SSL_CTX_remove_session(s->ctx, ret);
524296465Sdelphij        goto err;
525296465Sdelphij    }
52655714Skris
527296465Sdelphij    s->ctx->stats.sess_hit++;
52855714Skris
529296465Sdelphij    /*- ret->time=time(NULL); *//*
530296465Sdelphij     * rezero timeout?
531296465Sdelphij     */
532296465Sdelphij    /*
533296465Sdelphij     * again, just leave the session if it is the same session, we have just
534296465Sdelphij     * incremented and then decremented the reference count :-)
535296465Sdelphij     */
536296465Sdelphij    if (s->session != NULL)
537296465Sdelphij        SSL_SESSION_free(s->session);
538296465Sdelphij    s->session = ret;
539296465Sdelphij    s->verify_result = s->session->verify_result;
540296465Sdelphij    return (1);
54155714Skris
54255714Skris err:
543296465Sdelphij    if (ret != NULL)
544296465Sdelphij        SSL_SESSION_free(ret);
545296465Sdelphij    if (fatal)
546296465Sdelphij        return -1;
547296465Sdelphij    else
548296465Sdelphij        return 0;
549296465Sdelphij}
55055714Skris
55155714Skrisint SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c)
552296465Sdelphij{
553296465Sdelphij    int ret = 0;
554296465Sdelphij    SSL_SESSION *s;
55555714Skris
556296465Sdelphij    /*
557296465Sdelphij     * add just 1 reference count for the SSL_CTX's session cache even though
558296465Sdelphij     * it has two ways of access: each session is in a doubly linked list and
559296465Sdelphij     * an lhash
560296465Sdelphij     */
561296465Sdelphij    CRYPTO_add(&c->references, 1, CRYPTO_LOCK_SSL_SESSION);
562296465Sdelphij    /*
563296465Sdelphij     * if session c is in already in cache, we take back the increment later
564296465Sdelphij     */
56555714Skris
566296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
567296465Sdelphij    s = (SSL_SESSION *)lh_insert(ctx->sessions, c);
56859191Skris
569296465Sdelphij    /*
570296465Sdelphij     * s != NULL iff we already had a session with the given PID. In this
571296465Sdelphij     * case, s == c should hold (then we did not really modify
572296465Sdelphij     * ctx->sessions), or we're in trouble.
573296465Sdelphij     */
574296465Sdelphij    if (s != NULL && s != c) {
575296465Sdelphij        /* We *are* in trouble ... */
576296465Sdelphij        SSL_SESSION_list_remove(ctx, s);
577296465Sdelphij        SSL_SESSION_free(s);
578296465Sdelphij        /*
579296465Sdelphij         * ... so pretend the other session did not exist in cache (we cannot
580296465Sdelphij         * handle two SSL_SESSION structures with identical session ID in the
581296465Sdelphij         * same cache, which could happen e.g. when two threads concurrently
582296465Sdelphij         * obtain the same session from an external cache)
583296465Sdelphij         */
584296465Sdelphij        s = NULL;
585296465Sdelphij    }
58655714Skris
587296465Sdelphij    /* Put at the head of the queue unless it is already in the cache */
588296465Sdelphij    if (s == NULL)
589296465Sdelphij        SSL_SESSION_list_add(ctx, c);
59059191Skris
591296465Sdelphij    if (s != NULL) {
592296465Sdelphij        /*
593296465Sdelphij         * existing cache entry -- decrement previously incremented reference
594296465Sdelphij         * count because it already takes into account the cache
595296465Sdelphij         */
59655714Skris
597296465Sdelphij        SSL_SESSION_free(s);    /* s == c */
598296465Sdelphij        ret = 0;
599296465Sdelphij    } else {
600296465Sdelphij        /*
601296465Sdelphij         * new cache entry -- remove old ones if cache has become too large
602296465Sdelphij         */
60355714Skris
604296465Sdelphij        ret = 1;
605296465Sdelphij
606296465Sdelphij        if (SSL_CTX_sess_get_cache_size(ctx) > 0) {
607296465Sdelphij            while (SSL_CTX_sess_number(ctx) >
608296465Sdelphij                   SSL_CTX_sess_get_cache_size(ctx)) {
609296465Sdelphij                if (!remove_session_lock(ctx, ctx->session_cache_tail, 0))
610296465Sdelphij                    break;
611296465Sdelphij                else
612296465Sdelphij                    ctx->stats.sess_cache_full++;
613296465Sdelphij            }
614296465Sdelphij        }
615296465Sdelphij    }
616296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
617296465Sdelphij    return (ret);
618296465Sdelphij}
619296465Sdelphij
62055714Skrisint SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *c)
62155714Skris{
622296465Sdelphij    return remove_session_lock(ctx, c, 1);
62355714Skris}
62455714Skris
62555714Skrisstatic int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck)
626296465Sdelphij{
627296465Sdelphij    SSL_SESSION *r;
628296465Sdelphij    int ret = 0;
62955714Skris
630296465Sdelphij    if ((c != NULL) && (c->session_id_length != 0)) {
631296465Sdelphij        if (lck)
632296465Sdelphij            CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
633296465Sdelphij        if ((r = (SSL_SESSION *)lh_retrieve(ctx->sessions, c)) == c) {
634296465Sdelphij            ret = 1;
635296465Sdelphij            r = (SSL_SESSION *)lh_delete(ctx->sessions, c);
636296465Sdelphij            SSL_SESSION_list_remove(ctx, c);
637296465Sdelphij        }
63855714Skris
639296465Sdelphij        if (lck)
640296465Sdelphij            CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
64155714Skris
642296465Sdelphij        if (ret) {
643296465Sdelphij            r->not_resumable = 1;
644296465Sdelphij            if (ctx->remove_session_cb != NULL)
645296465Sdelphij                ctx->remove_session_cb(ctx, r);
646296465Sdelphij            SSL_SESSION_free(r);
647296465Sdelphij        }
648296465Sdelphij    } else
649296465Sdelphij        ret = 0;
650296465Sdelphij    return (ret);
651296465Sdelphij}
65255714Skris
65355714Skrisvoid SSL_SESSION_free(SSL_SESSION *ss)
654296465Sdelphij{
655296465Sdelphij    int i;
65655714Skris
657296465Sdelphij    if (ss == NULL)
658296465Sdelphij        return;
65955714Skris
660296465Sdelphij    i = CRYPTO_add(&ss->references, -1, CRYPTO_LOCK_SSL_SESSION);
66155714Skris#ifdef REF_PRINT
662296465Sdelphij    REF_PRINT("SSL_SESSION", ss);
66355714Skris#endif
664296465Sdelphij    if (i > 0)
665296465Sdelphij        return;
66655714Skris#ifdef REF_CHECK
667296465Sdelphij    if (i < 0) {
668296465Sdelphij        fprintf(stderr, "SSL_SESSION_free, bad reference count\n");
669296465Sdelphij        abort();                /* ok */
670296465Sdelphij    }
67155714Skris#endif
67255714Skris
673296465Sdelphij    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data);
67455714Skris
675296465Sdelphij    OPENSSL_cleanse(ss->key_arg, sizeof ss->key_arg);
676296465Sdelphij    OPENSSL_cleanse(ss->master_key, sizeof ss->master_key);
677296465Sdelphij    OPENSSL_cleanse(ss->session_id, sizeof ss->session_id);
678296465Sdelphij    if (ss->sess_cert != NULL)
679296465Sdelphij        ssl_sess_cert_free(ss->sess_cert);
680296465Sdelphij    if (ss->peer != NULL)
681296465Sdelphij        X509_free(ss->peer);
682296465Sdelphij    if (ss->ciphers != NULL)
683296465Sdelphij        sk_SSL_CIPHER_free(ss->ciphers);
684194206Ssimon#ifndef OPENSSL_NO_TLSEXT
685296465Sdelphij    if (ss->tlsext_hostname != NULL)
686296465Sdelphij        OPENSSL_free(ss->tlsext_hostname);
687296465Sdelphij    if (ss->tlsext_tick != NULL)
688296465Sdelphij        OPENSSL_free(ss->tlsext_tick);
689194206Ssimon#endif
690296465Sdelphij    OPENSSL_cleanse(ss, sizeof(*ss));
691296465Sdelphij    OPENSSL_free(ss);
692296465Sdelphij}
69355714Skris
69455714Skrisint SSL_set_session(SSL *s, SSL_SESSION *session)
695296465Sdelphij{
696296465Sdelphij    int ret = 0;
697296465Sdelphij    SSL_METHOD *meth;
69855714Skris
699296465Sdelphij    if (session != NULL) {
700296465Sdelphij        meth = s->ctx->method->get_ssl_method(session->ssl_version);
701296465Sdelphij        if (meth == NULL)
702296465Sdelphij            meth = s->method->get_ssl_method(session->ssl_version);
703296465Sdelphij        if (meth == NULL) {
704296465Sdelphij            SSLerr(SSL_F_SSL_SET_SESSION, SSL_R_UNABLE_TO_FIND_SSL_METHOD);
705296465Sdelphij            return (0);
706296465Sdelphij        }
70755714Skris
708296465Sdelphij        if (meth != s->method) {
709296465Sdelphij            if (!SSL_set_ssl_method(s, meth))
710296465Sdelphij                return (0);
711296465Sdelphij            if (s->ctx->session_timeout == 0)
712296465Sdelphij                session->timeout = SSL_get_default_timeout(s);
713296465Sdelphij            else
714296465Sdelphij                session->timeout = s->ctx->session_timeout;
715296465Sdelphij        }
716109998Smarkm#ifndef OPENSSL_NO_KRB5
717296465Sdelphij        if (s->kssl_ctx && !s->kssl_ctx->client_princ &&
718296465Sdelphij            session->krb5_client_princ_len > 0) {
719296465Sdelphij            s->kssl_ctx->client_princ =
720296465Sdelphij                (char *)OPENSSL_malloc(session->krb5_client_princ_len + 1);
721296465Sdelphij            memcpy(s->kssl_ctx->client_princ, session->krb5_client_princ,
722296465Sdelphij                   session->krb5_client_princ_len);
723296465Sdelphij            s->kssl_ctx->client_princ[session->krb5_client_princ_len] = '\0';
724296465Sdelphij        }
725296465Sdelphij#endif                          /* OPENSSL_NO_KRB5 */
726109998Smarkm
727296465Sdelphij        /* CRYPTO_w_lock(CRYPTO_LOCK_SSL); */
728296465Sdelphij        CRYPTO_add(&session->references, 1, CRYPTO_LOCK_SSL_SESSION);
729296465Sdelphij        if (s->session != NULL)
730296465Sdelphij            SSL_SESSION_free(s->session);
731296465Sdelphij        s->session = session;
732296465Sdelphij        s->verify_result = s->session->verify_result;
733296465Sdelphij        /* CRYPTO_w_unlock(CRYPTO_LOCK_SSL); */
734296465Sdelphij        ret = 1;
735296465Sdelphij    } else {
736296465Sdelphij        if (s->session != NULL) {
737296465Sdelphij            SSL_SESSION_free(s->session);
738296465Sdelphij            s->session = NULL;
739296465Sdelphij        }
74055714Skris
741296465Sdelphij        meth = s->ctx->method;
742296465Sdelphij        if (meth != s->method) {
743296465Sdelphij            if (!SSL_set_ssl_method(s, meth))
744296465Sdelphij                return (0);
745296465Sdelphij        }
746296465Sdelphij        ret = 1;
747296465Sdelphij    }
748296465Sdelphij    return (ret);
749296465Sdelphij}
75055714Skris
75155714Skrislong SSL_SESSION_set_timeout(SSL_SESSION *s, long t)
752296465Sdelphij{
753296465Sdelphij    if (s == NULL)
754296465Sdelphij        return (0);
755296465Sdelphij    s->timeout = t;
756296465Sdelphij    return (1);
757296465Sdelphij}
75855714Skris
759160814Ssimonlong SSL_SESSION_get_timeout(const SSL_SESSION *s)
760296465Sdelphij{
761296465Sdelphij    if (s == NULL)
762296465Sdelphij        return (0);
763296465Sdelphij    return (s->timeout);
764296465Sdelphij}
76555714Skris
766160814Ssimonlong SSL_SESSION_get_time(const SSL_SESSION *s)
767296465Sdelphij{
768296465Sdelphij    if (s == NULL)
769296465Sdelphij        return (0);
770296465Sdelphij    return (s->time);
771296465Sdelphij}
77255714Skris
77355714Skrislong SSL_SESSION_set_time(SSL_SESSION *s, long t)
774296465Sdelphij{
775296465Sdelphij    if (s == NULL)
776296465Sdelphij        return (0);
777296465Sdelphij    s->time = t;
778296465Sdelphij    return (t);
779296465Sdelphij}
78055714Skris
78155714Skrislong SSL_CTX_set_timeout(SSL_CTX *s, long t)
782296465Sdelphij{
783296465Sdelphij    long l;
784296465Sdelphij    if (s == NULL)
785296465Sdelphij        return (0);
786296465Sdelphij    l = s->session_timeout;
787296465Sdelphij    s->session_timeout = t;
788296465Sdelphij    return (l);
789296465Sdelphij}
79055714Skris
791160814Ssimonlong SSL_CTX_get_timeout(const SSL_CTX *s)
792296465Sdelphij{
793296465Sdelphij    if (s == NULL)
794296465Sdelphij        return (0);
795296465Sdelphij    return (s->session_timeout);
796296465Sdelphij}
79755714Skris
798296465Sdelphijtypedef struct timeout_param_st {
799296465Sdelphij    SSL_CTX *ctx;
800296465Sdelphij    long time;
801296465Sdelphij    LHASH *cache;
802296465Sdelphij} TIMEOUT_PARAM;
80355714Skris
80455714Skrisstatic void timeout(SSL_SESSION *s, TIMEOUT_PARAM *p)
805296465Sdelphij{
806296465Sdelphij    if ((p->time == 0) || (p->time > (s->time + s->timeout))) { /* timeout */
807296465Sdelphij        /*
808296465Sdelphij         * The reason we don't call SSL_CTX_remove_session() is to save on
809296465Sdelphij         * locking overhead
810296465Sdelphij         */
811296465Sdelphij        lh_delete(p->cache, s);
812296465Sdelphij        SSL_SESSION_list_remove(p->ctx, s);
813296465Sdelphij        s->not_resumable = 1;
814296465Sdelphij        if (p->ctx->remove_session_cb != NULL)
815296465Sdelphij            p->ctx->remove_session_cb(p->ctx, s);
816296465Sdelphij        SSL_SESSION_free(s);
817296465Sdelphij    }
818296465Sdelphij}
81955714Skris
820109998Smarkmstatic IMPLEMENT_LHASH_DOALL_ARG_FN(timeout, SSL_SESSION *, TIMEOUT_PARAM *)
821109998Smarkm
82255714Skrisvoid SSL_CTX_flush_sessions(SSL_CTX *s, long t)
823296465Sdelphij{
824296465Sdelphij    unsigned long i;
825296465Sdelphij    TIMEOUT_PARAM tp;
82655714Skris
827296465Sdelphij    tp.ctx = s;
828296465Sdelphij    tp.cache = s->sessions;
829296465Sdelphij    if (tp.cache == NULL)
830296465Sdelphij        return;
831296465Sdelphij    tp.time = t;
832296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
833296465Sdelphij    i = tp.cache->down_load;
834296465Sdelphij    tp.cache->down_load = 0;
835296465Sdelphij    lh_doall_arg(tp.cache, LHASH_DOALL_ARG_FN(timeout), &tp);
836296465Sdelphij    tp.cache->down_load = i;
837296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
838296465Sdelphij}
83955714Skris
84055714Skrisint ssl_clear_bad_session(SSL *s)
841296465Sdelphij{
842296465Sdelphij    if ((s->session != NULL) &&
843296465Sdelphij        !(s->shutdown & SSL_SENT_SHUTDOWN) &&
844296465Sdelphij        !(SSL_in_init(s) || SSL_in_before(s))) {
845296465Sdelphij        SSL_CTX_remove_session(s->ctx, s->session);
846296465Sdelphij        return (1);
847296465Sdelphij    } else
848296465Sdelphij        return (0);
849296465Sdelphij}
85055714Skris
85155714Skris/* locked by SSL_CTX in the calling function */
85255714Skrisstatic void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s)
853296465Sdelphij{
854296465Sdelphij    if ((s->next == NULL) || (s->prev == NULL))
855296465Sdelphij        return;
85655714Skris
857296465Sdelphij    if (s->next == (SSL_SESSION *)&(ctx->session_cache_tail)) {
858296465Sdelphij        /* last element in list */
859296465Sdelphij        if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head)) {
860296465Sdelphij            /* only one element in list */
861296465Sdelphij            ctx->session_cache_head = NULL;
862296465Sdelphij            ctx->session_cache_tail = NULL;
863296465Sdelphij        } else {
864296465Sdelphij            ctx->session_cache_tail = s->prev;
865296465Sdelphij            s->prev->next = (SSL_SESSION *)&(ctx->session_cache_tail);
866296465Sdelphij        }
867296465Sdelphij    } else {
868296465Sdelphij        if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head)) {
869296465Sdelphij            /* first element in list */
870296465Sdelphij            ctx->session_cache_head = s->next;
871296465Sdelphij            s->next->prev = (SSL_SESSION *)&(ctx->session_cache_head);
872296465Sdelphij        } else {
873296465Sdelphij            /* middle of list */
874296465Sdelphij            s->next->prev = s->prev;
875296465Sdelphij            s->prev->next = s->next;
876296465Sdelphij        }
877296465Sdelphij    }
878296465Sdelphij    s->prev = s->next = NULL;
879296465Sdelphij}
88055714Skris
88155714Skrisstatic void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s)
882296465Sdelphij{
883296465Sdelphij    if ((s->next != NULL) && (s->prev != NULL))
884296465Sdelphij        SSL_SESSION_list_remove(ctx, s);
88555714Skris
886296465Sdelphij    if (ctx->session_cache_head == NULL) {
887296465Sdelphij        ctx->session_cache_head = s;
888296465Sdelphij        ctx->session_cache_tail = s;
889296465Sdelphij        s->prev = (SSL_SESSION *)&(ctx->session_cache_head);
890296465Sdelphij        s->next = (SSL_SESSION *)&(ctx->session_cache_tail);
891296465Sdelphij    } else {
892296465Sdelphij        s->next = ctx->session_cache_head;
893296465Sdelphij        s->next->prev = s;
894296465Sdelphij        s->prev = (SSL_SESSION *)&(ctx->session_cache_head);
895296465Sdelphij        ctx->session_cache_head = s;
896296465Sdelphij    }
897296465Sdelphij}
89855714Skris
899167612Ssimonvoid SSL_CTX_sess_set_new_cb(SSL_CTX *ctx,
900296465Sdelphij                             int (*cb) (struct ssl_st *ssl,
901296465Sdelphij                                        SSL_SESSION *sess))
902296465Sdelphij{
903296465Sdelphij    ctx->new_session_cb = cb;
904296465Sdelphij}
905167612Ssimon
906296465Sdelphijint (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx)) (SSL *ssl, SSL_SESSION *sess) {
907296465Sdelphij    return ctx->new_session_cb;
908296465Sdelphij}
909167612Ssimon
910167612Ssimonvoid SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx,
911296465Sdelphij                                void (*cb) (SSL_CTX *ctx, SSL_SESSION *sess))
912296465Sdelphij{
913296465Sdelphij    ctx->remove_session_cb = cb;
914296465Sdelphij}
915167612Ssimon
916296465Sdelphijvoid (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx)) (SSL_CTX *ctx,
917296465Sdelphij                                                  SSL_SESSION *sess) {
918296465Sdelphij    return ctx->remove_session_cb;
919296465Sdelphij}
920167612Ssimon
921167612Ssimonvoid SSL_CTX_sess_set_get_cb(SSL_CTX *ctx,
922296465Sdelphij                             SSL_SESSION *(*cb) (struct ssl_st *ssl,
923296465Sdelphij                                                 unsigned char *data, int len,
924296465Sdelphij                                                 int *copy))
925296465Sdelphij{
926296465Sdelphij    ctx->get_session_cb = cb;
927296465Sdelphij}
928167612Ssimon
929296465SdelphijSSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx)) (SSL *ssl,
930296465Sdelphij                                                       unsigned char *data,
931296465Sdelphij                                                       int len, int *copy) {
932296465Sdelphij    return ctx->get_session_cb;
933296465Sdelphij}
934167612Ssimon
935296465Sdelphijvoid SSL_CTX_set_info_callback(SSL_CTX *ctx,
936296465Sdelphij                               void (*cb) (const SSL *ssl, int type, int val))
937296465Sdelphij{
938296465Sdelphij    ctx->info_callback = cb;
939296465Sdelphij}
940167612Ssimon
941296465Sdelphijvoid (*SSL_CTX_get_info_callback(SSL_CTX *ctx)) (const SSL *ssl, int type,
942296465Sdelphij                                                 int val) {
943296465Sdelphij    return ctx->info_callback;
944296465Sdelphij}
945167612Ssimon
946167612Ssimonvoid SSL_CTX_set_client_cert_cb(SSL_CTX *ctx,
947296465Sdelphij                                int (*cb) (SSL *ssl, X509 **x509,
948296465Sdelphij                                           EVP_PKEY **pkey))
949296465Sdelphij{
950296465Sdelphij    ctx->client_cert_cb = cb;
951296465Sdelphij}
952167612Ssimon
953296465Sdelphijint (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx)) (SSL *ssl, X509 **x509,
954296465Sdelphij                                                 EVP_PKEY **pkey) {
955296465Sdelphij    return ctx->client_cert_cb;
956296465Sdelphij}
957167612Ssimon
958194206Ssimon#ifndef OPENSSL_NO_ENGINE
959194206Ssimonint SSL_CTX_set_client_cert_engine(SSL_CTX *ctx, ENGINE *e)
960296465Sdelphij{
961296465Sdelphij    if (!ENGINE_init(e)) {
962296465Sdelphij        SSLerr(SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE, ERR_R_ENGINE_LIB);
963296465Sdelphij        return 0;
964296465Sdelphij    }
965296465Sdelphij    if (!ENGINE_get_ssl_client_cert_function(e)) {
966296465Sdelphij        SSLerr(SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE,
967296465Sdelphij               SSL_R_NO_CLIENT_CERT_METHOD);
968296465Sdelphij        ENGINE_finish(e);
969296465Sdelphij        return 0;
970296465Sdelphij    }
971296465Sdelphij    ctx->client_cert_engine = e;
972296465Sdelphij    return 1;
973296465Sdelphij}
974194206Ssimon#endif
975194206Ssimon
976167612Ssimonvoid SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx,
977296465Sdelphij                                    int (*cb) (SSL *ssl,
978296465Sdelphij                                               unsigned char *cookie,
979296465Sdelphij                                               unsigned int *cookie_len))
980296465Sdelphij{
981296465Sdelphij    ctx->app_gen_cookie_cb = cb;
982296465Sdelphij}
983167612Ssimon
984167612Ssimonvoid SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx,
985296465Sdelphij                                  int (*cb) (SSL *ssl, unsigned char *cookie,
986296465Sdelphij                                             unsigned int cookie_len))
987296465Sdelphij{
988296465Sdelphij    ctx->app_verify_cookie_cb = cb;
989296465Sdelphij}
990