int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) { int ret = 0; SSL_SESSION *s; /* add just 1 reference count for the SSL_CTX's session cache even though it * has two ways of access: each session is in a doubly linked list and an * lhash */ SSL_SESSION_up_ref(c); /* if session c is in already in cache, we take back the increment later */ CRYPTO_MUTEX_lock_write(&ctx->lock); if (!lh_SSL_SESSION_insert(ctx->sessions, &s, c)) { CRYPTO_MUTEX_unlock(&ctx->lock); return 0; } /* s != NULL iff we already had a session with the given PID. In this case, s * == c should hold (then we did not really modify ctx->sessions), or we're * in trouble. */ if (s != NULL && s != c) { /* We *are* in trouble ... */ SSL_SESSION_list_remove(ctx, s); SSL_SESSION_free(s); /* ... so pretend the other session did not exist in cache (we cannot * handle two SSL_SESSION structures with identical session ID in the same * cache, which could happen e.g. when two threads concurrently obtain the * same session from an external cache) */ s = NULL; } /* Put at the head of the queue unless it is already in the cache */ if (s == NULL) { SSL_SESSION_list_add(ctx, c); } if (s != NULL) { /* existing cache entry -- decrement previously incremented reference count * because it already takes into account the cache */ SSL_SESSION_free(s); /* s == c */ ret = 0; } else { /* new cache entry -- remove old ones if cache has become too large */ ret = 1; if (SSL_CTX_sess_get_cache_size(ctx) > 0) { while (SSL_CTX_sess_number(ctx) > SSL_CTX_sess_get_cache_size(ctx)) { if (!remove_session_lock(ctx, ctx->session_cache_tail, 0)) { break; } } } } CRYPTO_MUTEX_unlock(&ctx->lock); return ret; }
void logsslstats(SSL *reference) { char sglobal[1024]; p_log(LOG_INFO,-1, lngtxt(613)); if(reference==NULL) p_log(LOG_INFO,-1,lngtxt(614)); else { if(SSL_get_shared_ciphers(reference,sglobal,1023)==NULL) strmncpy(sglobal,lngtxt(615),sizeof(sglobal)); p_log(LOG_INFO,-1,lngtxt(616),sglobal); } p_log(LOG_INFO,-1, lngtxt(617), SSL_CTX_sess_number(srvctx)+SSL_CTX_sess_number(clnctx)); p_log(LOG_INFO,-1, lngtxt(618), SSL_CTX_sess_connect(srvctx)+SSL_CTX_sess_connect(clnctx)); p_log(LOG_INFO,-1, lngtxt(619), SSL_CTX_sess_connect_good(srvctx)+SSL_CTX_sess_connect_good(clnctx)); #if SSLEAY_VERSION_NUMBER >= 0x0922 p_log(LOG_INFO,-1, lngtxt(620), SSL_CTX_sess_connect_renegotiate(srvctx)+SSL_CTX_sess_connect_renegotiate(clnctx)); #endif p_log(LOG_INFO,-1, lngtxt(621), SSL_CTX_sess_accept(srvctx)+SSL_CTX_sess_accept(clnctx)); p_log(LOG_INFO,-1, lngtxt(622), SSL_CTX_sess_accept_good(srvctx)+SSL_CTX_sess_accept_good(clnctx)); #if SSLEAY_VERSION_NUMBER >= 0x0922 p_log(LOG_INFO,-1, lngtxt(623), SSL_CTX_sess_accept_renegotiate(srvctx)+SSL_CTX_sess_accept_renegotiate(clnctx)); #endif p_log(LOG_INFO,-1, lngtxt(624), SSL_CTX_sess_hits(srvctx)+SSL_CTX_sess_hits(clnctx)); p_log(LOG_INFO,-1, lngtxt(625), SSL_CTX_sess_misses(srvctx)+SSL_CTX_sess_misses(clnctx)); p_log(LOG_INFO,-1, lngtxt(626), SSL_CTX_sess_timeouts(srvctx)+SSL_CTX_sess_timeouts(clnctx)); p_log(LOG_INFO,-1, lngtxt(627)); return; }
static void print_stats(FILE *fp, SSL_CTX *ctx) { fprintf(fp, "%4ld items in the session cache\n", SSL_CTX_sess_number(ctx)); fprintf(fp, "%4d client connects (SSL_connect())\n", SSL_CTX_sess_connect(ctx)); fprintf(fp, "%4d client connects that finished\n", SSL_CTX_sess_connect_good(ctx)); fprintf(fp, "%4d server connects (SSL_accept())\n", SSL_CTX_sess_accept(ctx)); fprintf(fp, "%4d server connects that finished\n", SSL_CTX_sess_accept_good(ctx)); fprintf(fp, "%4d session cache hits\n", SSL_CTX_sess_hits(ctx)); fprintf(fp, "%4d session cache misses\n", SSL_CTX_sess_misses(ctx)); fprintf(fp, "%4d session cache timeouts\n", SSL_CTX_sess_timeouts(ctx)); }
int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *session) { /* Although |session| is inserted into two structures (a doubly-linked list * and the hash table), |ctx| only takes one reference. */ SSL_SESSION_up_ref(session); SSL_SESSION *old_session; CRYPTO_MUTEX_lock_write(&ctx->lock); if (!lh_SSL_SESSION_insert(ctx->sessions, &old_session, session)) { CRYPTO_MUTEX_unlock(&ctx->lock); SSL_SESSION_free(session); return 0; } if (old_session != NULL) { if (old_session == session) { /* |session| was already in the cache. */ CRYPTO_MUTEX_unlock(&ctx->lock); SSL_SESSION_free(old_session); return 0; } /* There was a session ID collision. |old_session| must be removed from * the linked list and released. */ SSL_SESSION_list_remove(ctx, old_session); SSL_SESSION_free(old_session); } SSL_SESSION_list_add(ctx, session); /* Enforce any cache size limits. */ if (SSL_CTX_sess_get_cache_size(ctx) > 0) { while (SSL_CTX_sess_number(ctx) > SSL_CTX_sess_get_cache_size(ctx)) { if (!remove_session_lock(ctx, ctx->session_cache_tail, 0)) { break; } } } CRYPTO_MUTEX_unlock(&ctx->lock); return 1; }
static void print_stats(void) { /* print statistics */ printf("%4ld items in the session cache\r\n", SSL_CTX_sess_number(pSSLSrvCtx)); printf("%4ld client connects (SSL_connect())\r\n", SSL_CTX_sess_connect(pSSLSrvCtx)); printf("%4ld client connects that finished\r\n", SSL_CTX_sess_connect_good(pSSLSrvCtx)); #if SSLEAY_VERSION_NUMBER >= 0x0922 printf("%4ld client renegotiatations requested\r\n", SSL_CTX_sess_connect_renegotiate(pSSLSrvCtx)); #endif printf("%4ld server connects (SSL_accept())\r\n", SSL_CTX_sess_accept(pSSLSrvCtx)); printf("%4ld server connects that finished\r\n", SSL_CTX_sess_accept_good(pSSLSrvCtx)); #if SSLEAY_VERSION_NUMBER >= 0x0922 printf("%4ld server renegotiatiations requested\r\n", SSL_CTX_sess_accept_renegotiate(pSSLSrvCtx)); #endif printf("%4ld session cache hits\r\n", SSL_CTX_sess_hits(pSSLSrvCtx)); printf("%4ld session cache misses\r\n", SSL_CTX_sess_misses(pSSLSrvCtx)); printf("%4ld session cache timeouts\r\n", SSL_CTX_sess_timeouts(pSSLSrvCtx)); }
/* * call-seq: * ctx.session_cache_stats -> Hash * */ static VALUE ossl_sslctx_get_session_cache_stats(VALUE self) { SSL_CTX *ctx; VALUE hash; Data_Get_Struct(self, SSL_CTX, ctx); hash = rb_hash_new(); rb_hash_aset(hash, ID2SYM(rb_intern("cache_num")), LONG2NUM(SSL_CTX_sess_number(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("connect")), LONG2NUM(SSL_CTX_sess_connect(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("connect_good")), LONG2NUM(SSL_CTX_sess_connect_good(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("connect_renegotiate")), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("accept")), LONG2NUM(SSL_CTX_sess_accept(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("accept_good")), LONG2NUM(SSL_CTX_sess_accept_good(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("accept_renegotiate")), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("cache_hits")), LONG2NUM(SSL_CTX_sess_hits(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("cb_hits")), LONG2NUM(SSL_CTX_sess_cb_hits(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("cache_misses")), LONG2NUM(SSL_CTX_sess_misses(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("cache_full")), LONG2NUM(SSL_CTX_sess_cache_full(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("timeouts")), LONG2NUM(SSL_CTX_sess_timeouts(ctx))); return hash; }
static void print_stats(BIO *bio, SSL_CTX *ssl_ctx) { BIO_printf(bio,"%4ld items in the session cache\n", SSL_CTX_sess_number(ssl_ctx)); BIO_printf(bio,"%4ld client connects (SSL_connect())\n", SSL_CTX_sess_connect(ssl_ctx)); BIO_printf(bio,"%4ld client renegotiates (SSL_connect())\n", SSL_CTX_sess_connect_renegotiate(ssl_ctx)); BIO_printf(bio,"%4ld client connects that finished\n", SSL_CTX_sess_connect_good(ssl_ctx)); BIO_printf(bio,"%4ld server accepts (SSL_accept())\n", SSL_CTX_sess_accept(ssl_ctx)); BIO_printf(bio,"%4ld server renegotiates (SSL_accept())\n", SSL_CTX_sess_accept_renegotiate(ssl_ctx)); BIO_printf(bio,"%4ld server accepts that finished\n", SSL_CTX_sess_accept_good(ssl_ctx)); BIO_printf(bio,"%4ld session cache hits\n",SSL_CTX_sess_hits(ssl_ctx)); BIO_printf(bio,"%4ld session cache misses\n",SSL_CTX_sess_misses(ssl_ctx)); BIO_printf(bio,"%4ld session cache timeouts\n",SSL_CTX_sess_timeouts(ssl_ctx)); BIO_printf(bio,"%4ld callback cache hits\n",SSL_CTX_sess_cb_hits(ssl_ctx)); BIO_printf(bio,"%4ld cache full overflows (%ld allowed)\n", SSL_CTX_sess_cache_full(ssl_ctx), SSL_CTX_sess_get_cache_size(ssl_ctx)); }
NOEXPORT void info_callback(const SSL *ssl, int where, int ret) { CLI *c; SSL_CTX *ctx; const char *state_string; c=SSL_get_ex_data((SSL *)ssl, index_cli); if(c) { int state=SSL_get_state((SSL *)ssl); #if 0 s_log(LOG_DEBUG, "state = %x", state); #endif /* log the client certificate request (if received) */ #ifndef SSL3_ST_CR_CERT_REQ_A if(state==TLS_ST_CR_CERT_REQ) #else if(state==SSL3_ST_CR_CERT_REQ_A) #endif print_client_CA_list(SSL_get_client_CA_list(ssl)); #ifndef SSL3_ST_CR_SRVR_DONE_A if(state==TLS_ST_CR_SRVR_DONE) #else if(state==SSL3_ST_CR_SRVR_DONE_A) #endif if(!SSL_get_client_CA_list(ssl)) s_log(LOG_INFO, "Client certificate not requested"); /* prevent renegotiation DoS attack */ if((where&SSL_CB_HANDSHAKE_DONE) && c->reneg_state==RENEG_INIT) { /* first (initial) handshake was completed, remember this, * so that further renegotiation attempts can be detected */ c->reneg_state=RENEG_ESTABLISHED; } else if((where&SSL_CB_ACCEPT_LOOP) && c->reneg_state==RENEG_ESTABLISHED) { #ifndef SSL3_ST_SR_CLNT_HELLO_A if(state==TLS_ST_SR_CLNT_HELLO || state==TLS_ST_SR_CLNT_HELLO) { #else if(state==SSL3_ST_SR_CLNT_HELLO_A || state==SSL23_ST_SR_CLNT_HELLO_A) { #endif /* client hello received after initial handshake, * this means renegotiation -> mark it */ c->reneg_state=RENEG_DETECTED; } } if(c->opt->log_level<LOG_DEBUG) /* performance optimization */ return; } if(where & SSL_CB_LOOP) { state_string=SSL_state_string_long(ssl); if(strcmp(state_string, "unknown state")) s_log(LOG_DEBUG, "SSL state (%s): %s", where & SSL_ST_CONNECT ? "connect" : where & SSL_ST_ACCEPT ? "accept" : "undefined", state_string); } else if(where & SSL_CB_ALERT) { s_log(LOG_DEBUG, "SSL alert (%s): %s: %s", where & SSL_CB_READ ? "read" : "write", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); } else if(where==SSL_CB_HANDSHAKE_DONE) { ctx=SSL_get_SSL_CTX((SSL *)ssl); if(c->opt->option.client) { s_log(LOG_DEBUG, "%6ld client connect(s) requested", SSL_CTX_sess_connect(ctx)); s_log(LOG_DEBUG, "%6ld client connect(s) succeeded", SSL_CTX_sess_connect_good(ctx)); s_log(LOG_DEBUG, "%6ld client renegotiation(s) requested", SSL_CTX_sess_connect_renegotiate(ctx)); } else { s_log(LOG_DEBUG, "%6ld server accept(s) requested", SSL_CTX_sess_accept(ctx)); s_log(LOG_DEBUG, "%6ld server accept(s) succeeded", SSL_CTX_sess_accept_good(ctx)); s_log(LOG_DEBUG, "%6ld server renegotiation(s) requested", SSL_CTX_sess_accept_renegotiate(ctx)); } /* according to the source it not only includes internal and external session caches, but also session tickets */ s_log(LOG_DEBUG, "%6ld session reuse(s)", SSL_CTX_sess_hits(ctx)); if(!c->opt->option.client) { /* server session cache stats */ s_log(LOG_DEBUG, "%6ld internal session cache item(s)", SSL_CTX_sess_number(ctx)); s_log(LOG_DEBUG, "%6ld internal session cache fill-up(s)", SSL_CTX_sess_cache_full(ctx)); s_log(LOG_DEBUG, "%6ld internal session cache miss(es)", SSL_CTX_sess_misses(ctx)); s_log(LOG_DEBUG, "%6ld external session cache hit(s)", SSL_CTX_sess_cb_hits(ctx)); s_log(LOG_DEBUG, "%6ld expired session(s) retrieved", SSL_CTX_sess_timeouts(ctx)); } } } /**************************************** SSL error reporting */ void sslerror(char *txt) { /* OpenSSL error handler */ unsigned long err; err=ERR_get_error(); if(err) { sslerror_queue(); sslerror_log(err, txt); } else { s_log(LOG_ERR, "%s: Peer suddenly disconnected", txt); } }
/* * Send an initial eap-tls request to the peer. * * Frame eap reply packet. * len = header + type + tls_typedata * tls_typedata = flags(Start (S) bit set, and no data) * * Once having received the peer's Identity, the EAP server MUST * respond with an EAP-TLS/Start packet, which is an * EAP-Request packet with EAP-Type=EAP-TLS, the Start (S) bit * set, and no data. The EAP-TLS conversation will then begin, * with the peer sending an EAP-Response packet with * EAP-Type = EAP-TLS. The data field of that packet will * be the TLS data. * * Fragment length is Framed-MTU - 4. * * http://mail.frascone.com/pipermail/public/eap/2003-July/001426.html */ static int eaptls_initiate(void *type_arg, EAP_HANDLER *handler) { int status; tls_session_t *ssn; eap_tls_t *inst; VALUE_PAIR *vp; int client_cert = TRUE; int verify_mode = 0; REQUEST *request = handler->request; inst = (eap_tls_t *)type_arg; handler->tls = TRUE; handler->finished = FALSE; /* * Manually flush the sessions every so often. If HALF * of the session lifetime has passed since we last * flushed, then flush it again. * * FIXME: Also do it every N sessions? */ if (inst->conf->session_cache_enable && ((inst->conf->session_last_flushed + (inst->conf->session_timeout * 1800)) <= request->timestamp)) { RDEBUG2("Flushing SSL sessions (of #%ld)", SSL_CTX_sess_number(inst->ctx)); SSL_CTX_flush_sessions(inst->ctx, request->timestamp); inst->conf->session_last_flushed = request->timestamp; } /* * If we're TTLS or PEAP, then do NOT require a client * certificate. * * FIXME: This should be more configurable. */ if (handler->eap_type != PW_EAP_TLS) { vp = pairfind(handler->request->config_items, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0); if (!vp) { client_cert = FALSE; } else { client_cert = vp->vp_integer; } } /* * Every new session is started only from EAP-TLS-START. * Before Sending EAP-TLS-START, open a new SSL session. * Create all the required data structures & store them * in Opaque. So that we can use these data structures * when we get the response */ ssn = eaptls_new_session(inst->ctx, client_cert); if (!ssn) { return 0; } /* * Verify the peer certificate, if asked. */ if (client_cert) { RDEBUG2("Requiring client certificate"); verify_mode = SSL_VERIFY_PEER; verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; verify_mode |= SSL_VERIFY_CLIENT_ONCE; } SSL_set_verify(ssn->ssl, verify_mode, cbtls_verify); /* * Create a structure for all the items required to be * verified for each client and set that as opaque data * structure. * * NOTE: If we want to set each item sepearately then * this index should be global. */ SSL_set_ex_data(ssn->ssl, 0, (void *)handler); SSL_set_ex_data(ssn->ssl, 1, (void *)inst->conf); #ifdef HAVE_OPENSSL_OCSP_H SSL_set_ex_data(ssn->ssl, 2, (void *)inst->store); #endif ssn->length_flag = inst->conf->include_length; /* * We use default fragment size, unless the Framed-MTU * tells us it's too big. Note that we do NOT account * for the EAP-TLS headers if conf->fragment_size is * large, because that config item looks to be confusing. * * i.e. it should REALLY be called MTU, and the code here * should figure out what that means for TLS fragment size. * asking the administrator to know the internal details * of EAP-TLS in order to calculate fragment sizes is * just too much. */ ssn->offset = inst->conf->fragment_size; vp = pairfind(handler->request->packet->vps, PW_FRAMED_MTU, 0); if (vp && ((vp->vp_integer - 14) < ssn->offset)) { /* * Discount the Framed-MTU by: * 4 : EAPOL header * 4 : EAP header (code + id + length) * 1 : EAP type == EAP-TLS * 1 : EAP-TLS Flags * 4 : EAP-TLS Message length * (even if conf->include_length == 0, * just to be lazy). * --- * 14 */ ssn->offset = vp->vp_integer - 14; } handler->opaque = ((void *)ssn); handler->free_opaque = session_free; RDEBUG2("Initiate"); /* * Set up type-specific information. */ switch (handler->eap_type) { case PW_EAP_TLS: default: ssn->prf_label = "client EAP encryption"; break; case PW_EAP_TTLS: ssn->prf_label = "ttls keying material"; break; /* * PEAP-specific breakage. */ case PW_EAP_PEAP: /* * As it is a poorly designed protocol, PEAP uses * bits in the TLS header to indicate PEAP * version numbers. For now, we only support * PEAP version 0, so it doesn't matter too much. * However, if we support later versions of PEAP, * we will need this flag to indicate which * version we're currently dealing with. */ ssn->peap_flag = 0x00; /* * PEAP version 0 requires 'include_length = no', * so rather than hoping the user figures it out, * we force it here. */ ssn->length_flag = 0; ssn->prf_label = "client EAP encryption"; break; } if (inst->conf->session_cache_enable) { ssn->allow_session_resumption = 1; /* otherwise it's zero */ } /* * TLS session initialization is over. Now handle TLS * related handshaking or application data. */ status = eaptls_start(handler->eap_ds, ssn->peap_flag); RDEBUG2("Start returned %d", status); if (status == 0) return 0; /* * The next stage to process the packet. */ handler->stage = AUTHENTICATE; return 1; }
NOEXPORT void info_callback( #if OPENSSL_VERSION_NUMBER>=0x0090700fL const #endif SSL *ssl, int where, int ret) { CLI *c; c=SSL_get_ex_data(ssl, cli_index); if(c) { if((where&SSL_CB_HANDSHAKE_DONE) && c->reneg_state==RENEG_INIT) { /* first (initial) handshake was completed, remember this, * so that further renegotiation attempts can be detected */ c->reneg_state=RENEG_ESTABLISHED; } else if((where&SSL_CB_ACCEPT_LOOP) && c->reneg_state==RENEG_ESTABLISHED) { int state=SSL_get_state(ssl); if(state==SSL3_ST_SR_CLNT_HELLO_A || state==SSL23_ST_SR_CLNT_HELLO_A) { /* client hello received after initial handshake, * this means renegotiation -> mark it */ c->reneg_state=RENEG_DETECTED; } } } if(global_options.debug_level<LOG_DEBUG) return; /* performance optimization */ if(where & SSL_CB_LOOP) { s_log(LOG_DEBUG, "SSL state (%s): %s", where & SSL_ST_CONNECT ? "connect" : where & SSL_ST_ACCEPT ? "accept" : "undefined", SSL_state_string_long(ssl)); } else if(where & SSL_CB_ALERT) { s_log(LOG_DEBUG, "SSL alert (%s): %s: %s", where & SSL_CB_READ ? "read" : "write", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); } else if(where==SSL_CB_HANDSHAKE_DONE) { s_log(LOG_DEBUG, "%4ld items in the session cache", SSL_CTX_sess_number(ssl->ctx)); s_log(LOG_DEBUG, "%4ld client connects (SSL_connect())", SSL_CTX_sess_connect(ssl->ctx)); s_log(LOG_DEBUG, "%4ld client connects that finished", SSL_CTX_sess_connect_good(ssl->ctx)); s_log(LOG_DEBUG, "%4ld client renegotiations requested", SSL_CTX_sess_connect_renegotiate(ssl->ctx)); s_log(LOG_DEBUG, "%4ld server connects (SSL_accept())", SSL_CTX_sess_accept(ssl->ctx)); s_log(LOG_DEBUG, "%4ld server connects that finished", SSL_CTX_sess_accept_good(ssl->ctx)); s_log(LOG_DEBUG, "%4ld server renegotiations requested", SSL_CTX_sess_accept_renegotiate(ssl->ctx)); s_log(LOG_DEBUG, "%4ld session cache hits", SSL_CTX_sess_hits(ssl->ctx)); s_log(LOG_DEBUG, "%4ld external session cache hits", SSL_CTX_sess_cb_hits(ssl->ctx)); s_log(LOG_DEBUG, "%4ld session cache misses", SSL_CTX_sess_misses(ssl->ctx)); s_log(LOG_DEBUG, "%4ld session cache timeouts", SSL_CTX_sess_timeouts(ssl->ctx)); } }
int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) { int ret = 0; SSL_SESSION *s; /* * add just 1 reference count for the SSL_CTX's session cache even though * it has two ways of access: each session is in a doubly linked list and * an lhash */ SSL_SESSION_up_ref(c); /* * if session c is in already in cache, we take back the increment later */ CRYPTO_THREAD_write_lock(ctx->lock); s = lh_SSL_SESSION_insert(ctx->sessions, c); /* * s != NULL iff we already had a session with the given PID. In this * case, s == c should hold (then we did not really modify * ctx->sessions), or we're in trouble. */ if (s != NULL && s != c) { /* We *are* in trouble ... */ SSL_SESSION_list_remove(ctx, s); SSL_SESSION_free(s); /* * ... so pretend the other session did not exist in cache (we cannot * handle two SSL_SESSION structures with identical session ID in the * same cache, which could happen e.g. when two threads concurrently * obtain the same session from an external cache) */ s = NULL; } else if (s == NULL && lh_SSL_SESSION_retrieve(ctx->sessions, c) == NULL) { /* s == NULL can also mean OOM error in lh_SSL_SESSION_insert ... */ /* * ... so take back the extra reference and also don't add * the session to the SSL_SESSION_list at this time */ s = c; } /* Put at the head of the queue unless it is already in the cache */ if (s == NULL) SSL_SESSION_list_add(ctx, c); if (s != NULL) { /* * existing cache entry -- decrement previously incremented reference * count because it already takes into account the cache */ SSL_SESSION_free(s); /* s == c */ ret = 0; } else { /* * new cache entry -- remove old ones if cache has become too large */ ret = 1; if (SSL_CTX_sess_get_cache_size(ctx) > 0) { while (SSL_CTX_sess_number(ctx) > SSL_CTX_sess_get_cache_size(ctx)) { if (!remove_session_lock(ctx, ctx->session_cache_tail, 0)) break; else ctx->stats.sess_cache_full++; } } } CRYPTO_THREAD_unlock(ctx->lock); return ret; }
NOEXPORT void info_callback(const SSL *ssl, int where, int ret) { CLI *c; SSL_CTX *ctx; c=SSL_get_ex_data((SSL *)ssl, index_cli); if(c) { if((where&SSL_CB_HANDSHAKE_DONE) && c->reneg_state==RENEG_INIT) { /* first (initial) handshake was completed, remember this, * so that further renegotiation attempts can be detected */ c->reneg_state=RENEG_ESTABLISHED; } else if((where&SSL_CB_ACCEPT_LOOP) && c->reneg_state==RENEG_ESTABLISHED) { int state=SSL_get_state((SSL *)ssl); if(state==SSL3_ST_SR_CLNT_HELLO_A || state==SSL23_ST_SR_CLNT_HELLO_A) { /* client hello received after initial handshake, * this means renegotiation -> mark it */ c->reneg_state=RENEG_DETECTED; } } if(c->opt->log_level<LOG_DEBUG) return; /* performance optimization */ } if(where & SSL_CB_LOOP) { s_log(LOG_DEBUG, "SSL state (%s): %s", where & SSL_ST_CONNECT ? "connect" : where & SSL_ST_ACCEPT ? "accept" : "undefined", SSL_state_string_long(ssl)); } else if(where & SSL_CB_ALERT) { s_log(LOG_DEBUG, "SSL alert (%s): %s: %s", where & SSL_CB_READ ? "read" : "write", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); } else if(where==SSL_CB_HANDSHAKE_DONE) { ctx=SSL_get_SSL_CTX((SSL *)ssl); if(c->opt->option.client) { s_log(LOG_DEBUG, "%4ld client connect(s) requested", SSL_CTX_sess_connect(ctx)); s_log(LOG_DEBUG, "%4ld client connect(s) succeeded", SSL_CTX_sess_connect_good(ctx)); s_log(LOG_DEBUG, "%4ld client renegotiation(s) requested", SSL_CTX_sess_connect_renegotiate(ctx)); } else { s_log(LOG_DEBUG, "%4ld server accept(s) requested", SSL_CTX_sess_accept(ctx)); s_log(LOG_DEBUG, "%4ld server accept(s) succeeded", SSL_CTX_sess_accept_good(ctx)); s_log(LOG_DEBUG, "%4ld server renegotiation(s) requested", SSL_CTX_sess_accept_renegotiate(ctx)); } /* according to the source it not only includes internal and external session caches, but also session tickets */ s_log(LOG_DEBUG, "%4ld session reuse(s)", SSL_CTX_sess_hits(ctx)); if(!c->opt->option.client) { /* server session cache stats */ s_log(LOG_DEBUG, "%4ld internal session cache item(s)", SSL_CTX_sess_number(ctx)); s_log(LOG_DEBUG, "%4ld internal session cache fill-up(s)", SSL_CTX_sess_cache_full(ctx)); s_log(LOG_DEBUG, "%4ld internal session cache miss(es)", SSL_CTX_sess_misses(ctx)); s_log(LOG_DEBUG, "%4ld external session cache hit(s)", SSL_CTX_sess_cb_hits(ctx)); s_log(LOG_DEBUG, "%4ld expired session(s) retrieved", SSL_CTX_sess_timeouts(ctx)); } } }
int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) { int ret = 0; SSL_SESSION *s; /* * Add just 1 reference count for the SSL_CTX's session cache * even though it has two ways of access: each session is in a * doubly linked list and an lhash. */ CRYPTO_add(&c->references, 1, CRYPTO_LOCK_SSL_SESSION); /* * If session c is in already in cache, we take back the increment * later. */ CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); s = lh_SSL_SESSION_insert(ctx->internal->sessions, c); /* * s != NULL iff we already had a session with the given PID. * In this case, s == c should hold (then we did not really modify * ctx->internal->sessions), or we're in trouble. */ if (s != NULL && s != c) { /* We *are* in trouble ... */ SSL_SESSION_list_remove(ctx, s); SSL_SESSION_free(s); /* * ... so pretend the other session did not exist in cache * (we cannot handle two SSL_SESSION structures with identical * session ID in the same cache, which could happen e.g. when * two threads concurrently obtain the same session from an * external cache). */ s = NULL; } /* Put at the head of the queue unless it is already in the cache */ if (s == NULL) SSL_SESSION_list_add(ctx, c); if (s != NULL) { /* * existing cache entry -- decrement previously incremented * reference count because it already takes into account the * cache. */ SSL_SESSION_free(s); /* s == c */ ret = 0; } else { /* * New cache entry -- remove old ones if cache has become * too large. */ ret = 1; if (SSL_CTX_sess_get_cache_size(ctx) > 0) { while (SSL_CTX_sess_number(ctx) > SSL_CTX_sess_get_cache_size(ctx)) { if (!remove_session_lock(ctx, ctx->internal->session_cache_tail, 0)) break; else ctx->internal->stats.sess_cache_full++; } } } CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); return (ret); }