diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h index f4163e915..c54884b52 100644 --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -64,11 +64,11 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); #include #include #include +#include +#include #if (NGX_OPENSSL) #include #endif -#include -#include #include #include #include diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index c5389e3e1..ba83e7f02 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -22,6 +22,16 @@ static void ngx_ssl_read_handler(ngx_event_t *rev); static void ngx_ssl_shutdown_handler(ngx_event_t *ev); static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, char *text); + +static ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone); +static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, + ngx_ssl_session_t *sess); +static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, + u_char *id, int len, int *copy); +static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess); +static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, + ngx_slab_pool_t *shpool, ngx_uint_t n); + static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf); static void ngx_openssl_exit(ngx_cycle_t *cycle); @@ -86,6 +96,7 @@ static long ngx_ssl_protocols[] = { int ngx_ssl_connection_index; int ngx_ssl_server_conf_index; +int ngx_ssl_session_cache_index; ngx_int_t @@ -117,6 +128,14 @@ ngx_ssl_init(ngx_log_t *log) return NGX_ERROR; } + ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, + NULL); + if (ngx_ssl_session_cache_index == -1) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, + "SSL_CTX_get_ex_new_index() failed"); + return NGX_ERROR; + } + return NGX_OK; } @@ -279,7 +298,7 @@ ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) name = X509_get_issuer_name(cert); issuer = name ? X509_NAME_oneline(name, NULL, 0) : "(none)"; - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, + ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, "verify:%d, error:%d, depth:%d, " "subject:\"%s\",issuer: \"%s\"", ok, err, depth, subject, issuer); @@ -1033,7 +1052,7 @@ ngx_ssl_shutdown_handler(ngx_event_t *ev) c->timedout = 1; } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, "SSL shutdown handler"); + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "SSL shutdown handler"); if (ngx_ssl_shutdown(c) == NGX_AGAIN) { return; @@ -1119,6 +1138,428 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...) } +ngx_int_t +ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, + ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout) +{ + long cache_mode; + + cache_mode = SSL_SESS_CACHE_SERVER; + + if (shm_zone && builtin_session_cache == NGX_SSL_NO_BUILTIN_SCACHE) { + cache_mode |= SSL_SESS_CACHE_NO_INTERNAL; + } + + SSL_CTX_set_session_cache_mode(ssl->ctx, cache_mode); + + SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len); + + if (builtin_session_cache != NGX_SSL_NO_BUILTIN_SCACHE) { + + if (builtin_session_cache != NGX_SSL_DFLT_BUILTIN_SCACHE) { + SSL_CTX_sess_set_cache_size(ssl->ctx, builtin_session_cache); + } + + SSL_CTX_set_timeout(ssl->ctx, timeout); + } + + if (shm_zone) { + shm_zone->init = ngx_ssl_session_cache_init; + + SSL_CTX_sess_set_new_cb(ssl->ctx, ngx_ssl_new_session); + SSL_CTX_sess_set_get_cb(ssl->ctx, ngx_ssl_get_cached_session); + SSL_CTX_sess_set_remove_cb(ssl->ctx, ngx_ssl_remove_session); + + if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_cache_index, shm_zone) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set_ex_data() failed"); + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone) +{ + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *sentinel; + ngx_ssl_session_cache_t *cache; + + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t)); + if (cache == NULL) { + return NGX_ERROR; + } + + cache->session_cache_head.prev = NULL; + cache->session_cache_head.next = &cache->session_cache_tail; + + cache->session_cache_tail.prev = &cache->session_cache_head; + cache->session_cache_tail.next = NULL; + + cache->session_rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); + if (cache->session_rbtree == NULL) { + return NGX_ERROR; + } + + sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); + if (sentinel == NULL) { + return NGX_ERROR; + } + + ngx_rbtree_sentinel_init(sentinel); + + cache->session_rbtree->root = sentinel; + cache->session_rbtree->sentinel = sentinel; + cache->session_rbtree->insert = ngx_rbtree_insert_value; + + shm_zone->data = cache; + + return NGX_OK; +} + + +/* + * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow, + * so they are outside the code locked by shared pool mutex + */ + +static int +ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) +{ + int len; + u_char *p, *id; + uint32_t hash; + SSL_CTX *ssl_ctx; + ngx_time_t *tp; + ngx_shm_zone_t *shm_zone; + ngx_connection_t *c; + ngx_slab_pool_t *shpool; + ngx_ssl_sess_id_t *sess_id; + ngx_ssl_cached_sess_t *cached_sess; + ngx_ssl_session_cache_t *cache; + u_char buf[NGX_SSL_MAX_SESSION_SIZE]; + + len = i2d_SSL_SESSION(sess, NULL); + + /* do not cache too big session */ + + if (len > (int) NGX_SSL_MAX_SESSION_SIZE) { + return 0; + } + + p = buf; + i2d_SSL_SESSION(sess, &p); + + c = ngx_ssl_get_connection(ssl_conn); + + ssl_ctx = SSL_get_SSL_CTX(ssl_conn); + shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index); + + cache = shm_zone->data; + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + ngx_shmtx_lock(&shpool->mutex); + + /* drop one or two expired sessions */ + ngx_ssl_expire_sessions(cache, shpool, 1); + + cached_sess = ngx_slab_alloc_locked(shpool, + offsetof(ngx_ssl_cached_sess_t, asn1) + len); + + if (cached_sess == NULL) { + + /* drop the oldest non-expired session and try once more */ + + ngx_ssl_expire_sessions(cache, shpool, 0); + + cached_sess = ngx_slab_alloc_locked(shpool, + offsetof(ngx_ssl_cached_sess_t, asn1) + len); + + if (cached_sess == NULL) { + id = NULL; + goto failed; + } + } + + id = ngx_slab_alloc_locked(shpool, sess->session_id_length); + if (id == NULL) { + goto failed; + } + + sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t)); + if (sess_id == NULL) { + goto failed; + } + + ngx_memcpy(&cached_sess->asn1[0], buf, len); + + ngx_memcpy(id, sess->session_id, sess->session_id_length); + + hash = ngx_crc32_short(sess->session_id, sess->session_id_length); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "http ssl new session: %08XD:%d:%d", + hash, sess->session_id_length, len); + + sess_id->node.key = hash; + sess_id->node.data = (u_char) sess->session_id_length; + sess_id->id = id; + sess_id->len = len; + sess_id->session = cached_sess; + + tp = ngx_timeofday(); + + cached_sess->expire = tp->sec + SSL_CTX_get_timeout(ssl_ctx); + cached_sess->sess_id = sess_id; + + cached_sess->next = cache->session_cache_head.next; + cached_sess->next->prev = cached_sess; + cached_sess->prev = &cache->session_cache_head; + cache->session_cache_head.next = cached_sess; + + ngx_rbtree_insert(cache->session_rbtree, &sess_id->node); + + ngx_shmtx_unlock(&shpool->mutex); + + return 0; + +failed: + + if (cached_sess) { + ngx_slab_free_locked(shpool, cached_sess); + } + + if (id) { + ngx_slab_free_locked(shpool, id); + } + + ngx_shmtx_unlock(&shpool->mutex); + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "could not add new SSL session to the session cache"); + + return 0; +} + + +static ngx_ssl_session_t * +ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len, + int *copy) +{ +#if OPENSSL_VERSION_NUMBER >= 0x00908000 + const +#endif + u_char *p; + uint32_t hash; + ngx_time_t *tp; + ngx_shm_zone_t *shm_zone; + ngx_slab_pool_t *shpool; + ngx_connection_t *c; + ngx_rbtree_node_t *node, *sentinel; + ngx_ssl_session_t *sess; + ngx_ssl_sess_id_t *sess_id; + ngx_ssl_cached_sess_t *cached_sess; + ngx_ssl_session_cache_t *cache; + u_char buf[NGX_SSL_MAX_SESSION_SIZE]; + + c = ngx_ssl_get_connection(ssl_conn); + + hash = ngx_crc32_short(id, len); + *copy = 0; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "http ssl get session: %08XD:%d", hash, len); + + shm_zone = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl_conn), + ngx_ssl_session_cache_index); + + cache = shm_zone->data; + + if (cache->session_rbtree == NULL) { + return NULL; + } + + sess = NULL; + + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + ngx_shmtx_lock(&shpool->mutex); + + node = cache->session_rbtree->root; + sentinel = cache->session_rbtree->sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + if (hash == node->key && (u_char) len == node->data) { + sess_id = (ngx_ssl_sess_id_t *) node; + + if (ngx_strncmp(id, sess_id->id, len) == 0) { + + cached_sess = sess_id->session; + + tp = ngx_timeofday(); + + if (cached_sess->expire > tp->sec) { + ngx_memcpy(buf, &cached_sess->asn1[0], sess_id->len); + + ngx_shmtx_unlock(&shpool->mutex); + + p = buf; + sess = d2i_SSL_SESSION(NULL, &p, sess_id->len); + + return sess; + } + + cached_sess->next->prev = cached_sess->prev; + cached_sess->prev->next = cached_sess->next; + + ngx_rbtree_delete(cache->session_rbtree, node); + + ngx_slab_free_locked(shpool, cached_sess); + ngx_slab_free_locked(shpool, sess_id->id); + ngx_slab_free_locked(shpool, sess_id); + + sess = NULL; + + break; + } + } + + node = node->right; + } + + ngx_shmtx_unlock(&shpool->mutex); + + return sess; +} + + +static void +ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess) +{ + u_char *id, len; + uint32_t hash; + ngx_shm_zone_t *shm_zone; + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node, *sentinel; + ngx_ssl_sess_id_t *sess_id; + ngx_ssl_cached_sess_t *cached_sess; + ngx_ssl_session_cache_t *cache; + + shm_zone = SSL_CTX_get_ex_data(ssl, ngx_ssl_session_cache_index); + + cache = shm_zone->data; + + id = sess->session_id; + len = (u_char) sess->session_id_length; + + hash = ngx_crc32_short(id, (size_t) len); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, + "http ssl remove session: %08XD:%d", hash, len); + + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + ngx_shmtx_lock(&shpool->mutex); + + node = cache->session_rbtree->root; + sentinel = cache->session_rbtree->sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + if (hash == node->key && len == node->data) { + sess_id = (ngx_ssl_sess_id_t *) node; + + if (ngx_strncmp(id, sess_id->id, (size_t) len) == 0) { + + cached_sess = sess_id->session; + + cached_sess->next->prev = cached_sess->prev; + cached_sess->prev->next = cached_sess->next; + + ngx_rbtree_delete(cache->session_rbtree, node); + + ngx_slab_free_locked(shpool, cached_sess); + ngx_slab_free_locked(shpool, sess_id->id); + ngx_slab_free_locked(shpool, sess_id); + + break; + } + } + + node = node->right; + } + + ngx_shmtx_unlock(&shpool->mutex); +} + + +static void +ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, + ngx_slab_pool_t *shpool, ngx_uint_t n) +{ + ngx_time_t *tp; + ngx_ssl_sess_id_t *sess_id; + ngx_ssl_cached_sess_t *sess; + + tp = ngx_timeofday(); + + while (n < 3) { + + sess = cache->session_cache_tail.prev; + + if (sess == &cache->session_cache_head) { + return; + } + + if (n++ != 0 && sess->expire > tp->sec) { + break; + } + + sess->next->prev = sess->prev; + sess->prev->next = sess->next; + + sess_id = sess->sess_id; + + ngx_rbtree_delete(cache->session_rbtree, &sess_id->node); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, + "expire session: %08Xi", sess_id->node.key); + + ngx_slab_free_locked(shpool, sess); + ngx_slab_free_locked(shpool, sess_id->id); + ngx_slab_free_locked(shpool, sess_id); + } +} + + void ngx_ssl_cleanup_ctx(void *data) { diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 758f57954..078b2bab0 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -51,6 +51,41 @@ typedef struct { } ngx_ssl_connection_t; +#define NGX_SSL_DFLT_BUILTIN_SCACHE -2 +#define NGX_SSL_NO_BUILTIN_SCACHE -3 + + +typedef struct ngx_ssl_cached_sess_s ngx_ssl_cached_sess_t; + + +#define NGX_SSL_MAX_SESSION_SIZE (4096 - offsetof(ngx_ssl_cached_sess_t, asn1)) + + +typedef struct { + ngx_rbtree_node_t node; + u_char *id; + size_t len; + ngx_ssl_cached_sess_t *session; +} ngx_ssl_sess_id_t; + + +struct ngx_ssl_cached_sess_s { + ngx_ssl_cached_sess_t *prev; + ngx_ssl_cached_sess_t *next; + time_t expire; + ngx_ssl_sess_id_t *sess_id; + u_char asn1[1]; +}; + + +typedef struct { + ngx_rbtree_t *session_rbtree; + ngx_ssl_cached_sess_t session_cache_head; + ngx_ssl_cached_sess_t session_cache_tail; +} ngx_ssl_session_cache_t; + + + #define NGX_SSL_SSLv2 2 #define NGX_SSL_SSLv3 4 #define NGX_SSL_TLSv1 8 @@ -69,6 +104,8 @@ ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth); ngx_int_t ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl); +ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, + ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout); ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags); @@ -93,8 +130,6 @@ ngx_int_t ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); - - ngx_int_t ngx_ssl_handshake(ngx_connection_t *c); ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size); ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size); @@ -109,6 +144,7 @@ void ngx_ssl_cleanup_ctx(void *data); extern int ngx_ssl_connection_index; extern int ngx_ssl_server_conf_index; +extern int ngx_ssl_session_cache_index; #endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */ diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 412aa47fb..e77e767ec 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -18,17 +18,6 @@ typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c, #define NGX_DEFLAUT_CIPHERS "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" -#define NGX_HTTP_SSL_MAX_SESSION_SIZE \ - (4096 - offsetof(ngx_http_ssl_cached_sess_t, asn1)) - - -#define NGX_HTTP_SSL_DFLT_BUILTIN_SCACHE -2 -#define NGX_HTTP_SSL_NO_BUILTIN_SCACHE -3 - - -static void ngx_http_ssl_expire_sessions(ngx_http_ssl_sesssion_cache_t *cache, - ngx_slab_pool_t *shpool, ngx_uint_t expire); - static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_ssl_variable(ngx_http_request_t *r, @@ -199,385 +188,7 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { }; -static u_char ngx_http_session_id_ctx[] = "HTTP"; - - -static ngx_int_t -ngx_http_ssl_session_cache_init(ngx_shm_zone_t *shm_zone) -{ - ngx_slab_pool_t *shpool; - ngx_rbtree_node_t *sentinel; - ngx_http_ssl_sesssion_cache_t *cache; - - shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; - - cache = ngx_slab_alloc(shpool, sizeof(ngx_http_ssl_sesssion_cache_t)); - if (cache == NULL) { - return NGX_ERROR; - } - - cache->session_cache_head.prev = NULL; - cache->session_cache_head.next = &cache->session_cache_tail; - - cache->session_cache_tail.prev = &cache->session_cache_head; - cache->session_cache_tail.next = NULL; - - cache->session_rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); - if (cache->session_rbtree == NULL) { - return NGX_ERROR; - } - - sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); - if (sentinel == NULL) { - return NGX_ERROR; - } - - ngx_rbtree_sentinel_init(sentinel); - - cache->session_rbtree->root = sentinel; - cache->session_rbtree->sentinel = sentinel; - cache->session_rbtree->insert = ngx_rbtree_insert_value; - - shm_zone->data = cache; - - return NGX_OK; -} - - -/* - * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow, - * so they are outside the code locked by shared pool mutex - */ - -static int -ngx_http_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) -{ - int len; - u_char *p, *id; - uint32_t hash; - ngx_time_t *tp; - ngx_slab_pool_t *shpool; - ngx_connection_t *c; - ngx_http_request_t *r; - ngx_http_ssl_sess_id_t *sess_id; - ngx_http_ssl_srv_conf_t *sscf; - ngx_http_ssl_cached_sess_t *cached_sess; - ngx_http_ssl_sesssion_cache_t *cache; - u_char buf[NGX_HTTP_SSL_MAX_SESSION_SIZE]; - - len = i2d_SSL_SESSION(sess, NULL); - - /* do not cache too big session */ - - if (len > (int) NGX_HTTP_SSL_MAX_SESSION_SIZE) { - return 0; - } - - c = ngx_ssl_get_connection(ssl_conn); - r = c->data; - - p = buf; - i2d_SSL_SESSION(sess, &p); - - sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); - - cache = sscf->shm_zone->data; - shpool = (ngx_slab_pool_t *) sscf->shm_zone->shm.addr; - - ngx_shmtx_lock(&shpool->mutex); - - /* drop one or two expired sessions */ - ngx_http_ssl_expire_sessions(cache, shpool, 1); - - cached_sess = ngx_slab_alloc_locked(shpool, - offsetof(ngx_http_ssl_cached_sess_t, asn1) + len); - - if (cached_sess == NULL) { - - /* drop the oldest non-expired session and try once more */ - - ngx_http_ssl_expire_sessions(cache, shpool, 0); - - cached_sess = ngx_slab_alloc_locked(shpool, - offsetof(ngx_http_ssl_cached_sess_t, asn1) + len); - - if (cached_sess == NULL) { - id = NULL; - goto failed; - } - } - - id = ngx_slab_alloc_locked(shpool, sess->session_id_length); - if (id == NULL) { - goto failed; - } - - sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_http_ssl_sess_id_t)); - if (sess_id == NULL) { - goto failed; - } - - ngx_memcpy(&cached_sess->asn1[0], buf, len); - - ngx_memcpy(id, sess->session_id, sess->session_id_length); - - hash = ngx_crc32_short(sess->session_id, sess->session_id_length); - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http ssl new session: %08XD:%d:%d", - hash, sess->session_id_length, len); - - sess_id->node.key = hash; - sess_id->node.data = (u_char) sess->session_id_length; - sess_id->id = id; - sess_id->len = len; - sess_id->session = cached_sess; - - tp = ngx_timeofday(); - - cached_sess->expire = tp->sec + sscf->session_timeout; - cached_sess->sess_id = sess_id; - - cached_sess->next = cache->session_cache_head.next; - cached_sess->next->prev = cached_sess; - cached_sess->prev = &cache->session_cache_head; - cache->session_cache_head.next = cached_sess; - - ngx_rbtree_insert(cache->session_rbtree, &sess_id->node); - - ngx_shmtx_unlock(&shpool->mutex); - - return 0; - -failed: - - if (cached_sess) { - ngx_slab_free_locked(shpool, cached_sess); - } - - if (id) { - ngx_slab_free_locked(shpool, id); - } - - ngx_shmtx_unlock(&shpool->mutex); - - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "could not add new SSL session to the session cache"); - - return 0; -} - - -static ngx_ssl_session_t * -ngx_http_ssl_get_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len, - int *copy) -{ -#if OPENSSL_VERSION_NUMBER >= 0x00908000 - const -#endif - u_char *p; - uint32_t hash; - ngx_time_t *tp; - ngx_slab_pool_t *shpool; - ngx_connection_t *c; - ngx_rbtree_node_t *node, *sentinel; - ngx_ssl_session_t *sess; - ngx_http_request_t *r; - ngx_http_ssl_sess_id_t *sess_id; - ngx_http_ssl_srv_conf_t *sscf; - ngx_http_ssl_cached_sess_t *cached_sess; - ngx_http_ssl_sesssion_cache_t *cache; - u_char buf[NGX_HTTP_SSL_MAX_SESSION_SIZE]; - - c = ngx_ssl_get_connection(ssl_conn); - r = c->data; - - sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); - - hash = ngx_crc32_short(id, len); - *copy = 0; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http ssl get session: %08XD:%d", hash, len); - - cache = sscf->shm_zone->data; - - if (cache->session_rbtree == NULL) { - return NULL; - } - - sess = NULL; - - shpool = (ngx_slab_pool_t *) sscf->shm_zone->shm.addr; - - ngx_shmtx_lock(&shpool->mutex); - - node = cache->session_rbtree->root; - sentinel = cache->session_rbtree->sentinel; - - while (node != sentinel) { - - if (hash < node->key) { - node = node->left; - continue; - } - - if (hash > node->key) { - node = node->right; - continue; - } - - if (hash == node->key && (u_char) len == node->data) { - sess_id = (ngx_http_ssl_sess_id_t *) node; - - if (ngx_strncmp(id, sess_id->id, len) == 0) { - - cached_sess = sess_id->session; - - tp = ngx_timeofday(); - - if (cached_sess->expire > tp->sec) { - ngx_memcpy(buf, &cached_sess->asn1[0], sess_id->len); - - ngx_shmtx_unlock(&shpool->mutex); - - p = buf; - sess = d2i_SSL_SESSION(NULL, &p, sess_id->len); - - return sess; - } - - cached_sess->next->prev = cached_sess->prev; - cached_sess->prev->next = cached_sess->next; - - ngx_rbtree_delete(cache->session_rbtree, node); - - ngx_slab_free_locked(shpool, cached_sess); - ngx_slab_free_locked(shpool, sess_id->id); - ngx_slab_free_locked(shpool, sess_id); - - sess = NULL; - - break; - } - } - - node = node->right; - } - - ngx_shmtx_unlock(&shpool->mutex); - - return sess; -} - - -static void -ngx_http_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess) -{ - u_char *id, len; - uint32_t hash; - ngx_slab_pool_t *shpool; - ngx_rbtree_node_t *node, *sentinel; - ngx_http_ssl_sess_id_t *sess_id; - ngx_http_ssl_srv_conf_t *sscf; - ngx_http_ssl_cached_sess_t *cached_sess; - ngx_http_ssl_sesssion_cache_t *cache; - - sscf = ngx_ssl_get_server_conf(ssl); - - cache = sscf->shm_zone->data; - - id = sess->session_id; - len = (u_char) sess->session_id_length; - - hash = ngx_crc32_short(id, (size_t) len); - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "http ssl remove session: %08XD:%d", hash, len); - - shpool = (ngx_slab_pool_t *) sscf->shm_zone->shm.addr; - - ngx_shmtx_lock(&shpool->mutex); - - node = cache->session_rbtree->root; - sentinel = cache->session_rbtree->sentinel; - - while (node != sentinel) { - - if (hash < node->key) { - node = node->left; - continue; - } - - if (hash > node->key) { - node = node->right; - continue; - } - - if (hash == node->key && len == node->data) { - sess_id = (ngx_http_ssl_sess_id_t *) node; - - if (ngx_strncmp(id, sess_id->id, (size_t) len) == 0) { - - cached_sess = sess_id->session; - - cached_sess->next->prev = cached_sess->prev; - cached_sess->prev->next = cached_sess->next; - - ngx_rbtree_delete(cache->session_rbtree, node); - - ngx_slab_free_locked(shpool, cached_sess); - ngx_slab_free_locked(shpool, sess_id->id); - ngx_slab_free_locked(shpool, sess_id); - - break; - } - } - - node = node->right; - } - - ngx_shmtx_unlock(&shpool->mutex); -} - - -static void -ngx_http_ssl_expire_sessions(ngx_http_ssl_sesssion_cache_t *cache, - ngx_slab_pool_t *shpool, ngx_uint_t n) -{ - ngx_time_t *tp; - ngx_http_ssl_sess_id_t *sess_id; - ngx_http_ssl_cached_sess_t *sess; - - tp = ngx_timeofday(); - - while (n < 3) { - - sess = cache->session_cache_tail.prev; - - if (sess == &cache->session_cache_head) { - return; - } - - if (n++ != 0 && sess->expire > tp->sec) { - break; - } - - sess->next->prev = sess->prev; - sess->prev->next = sess->next; - - sess_id = sess->sess_id; - - ngx_rbtree_delete(cache->session_rbtree, &sess_id->node); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "expire session: %08Xi", sess_id->node.key); - - ngx_slab_free_locked(shpool, sess); - ngx_slab_free_locked(shpool, sess_id->id); - ngx_slab_free_locked(shpool, sess_id); - } -} +static ngx_str_t ngx_http_ssl_sess_id_ctx = ngx_string("HTTP"); static ngx_int_t @@ -695,7 +306,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_ssl_srv_conf_t *prev = parent; ngx_http_ssl_srv_conf_t *conf = child; - long cache_mode; ngx_pool_cleanup_t *cln; ngx_conf_merge_value(conf->enable, prev->enable, 0); @@ -784,39 +394,18 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->builtin_session_cache, prev->builtin_session_cache, - NGX_HTTP_SSL_DFLT_BUILTIN_SCACHE); + NGX_SSL_DFLT_BUILTIN_SCACHE); if (conf->shm_zone == NULL) { conf->shm_zone = prev->shm_zone; } - cache_mode = SSL_SESS_CACHE_SERVER; - - if (conf->shm_zone - && conf->builtin_session_cache == NGX_HTTP_SSL_NO_BUILTIN_SCACHE) + if (ngx_ssl_session_cache(&conf->ssl, &ngx_http_ssl_sess_id_ctx, + conf->builtin_session_cache, + conf->shm_zone, conf->session_timeout) + != NGX_OK) { - cache_mode |= SSL_SESS_CACHE_NO_INTERNAL; - } - - SSL_CTX_set_session_cache_mode(conf->ssl.ctx, cache_mode); - - SSL_CTX_set_session_id_context(conf->ssl.ctx, ngx_http_session_id_ctx, - sizeof(ngx_http_session_id_ctx) - 1); - - if (conf->builtin_session_cache != NGX_HTTP_SSL_NO_BUILTIN_SCACHE) { - - if (conf->builtin_session_cache != NGX_HTTP_SSL_DFLT_BUILTIN_SCACHE) { - SSL_CTX_sess_set_cache_size(conf->ssl.ctx, - conf->builtin_session_cache); - } - - SSL_CTX_set_timeout(conf->ssl.ctx, conf->session_timeout); - } - - if (conf->shm_zone) { - SSL_CTX_sess_set_new_cb(conf->ssl.ctx, ngx_http_ssl_new_session); - SSL_CTX_sess_set_get_cb(conf->ssl.ctx, ngx_http_ssl_get_session); - SSL_CTX_sess_set_remove_cb(conf->ssl.ctx, ngx_http_ssl_remove_session); + return NGX_CONF_ERROR; } return NGX_CONF_OK; @@ -838,7 +427,7 @@ ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) for (i = 1; i < cf->args->nelts; i++) { if (ngx_strcmp(value[i].data, "builtin") == 0) { - sscf->builtin_session_cache = NGX_HTTP_SSL_DFLT_BUILTIN_SCACHE; + sscf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE; continue; } @@ -890,7 +479,7 @@ ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (n < (ngx_int_t) (8 * ngx_pagesize)) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "session cache \"%V\" to small", + "session cache \"%V\" is too small", &value[i]); return NGX_CONF_ERROR; @@ -902,8 +491,6 @@ ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - sscf->shm_zone->init = ngx_http_ssl_session_cache_init; - continue; } @@ -911,7 +498,7 @@ ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } if (sscf->shm_zone && sscf->builtin_session_cache == NGX_CONF_UNSET) { - sscf->builtin_session_cache = NGX_HTTP_SSL_NO_BUILTIN_SCACHE; + sscf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE; } return NGX_CONF_OK; diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index 7a5c6d5ad..1ef1ffe0f 100644 --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -13,33 +13,6 @@ #include -typedef struct ngx_http_ssl_cached_sess_s ngx_http_ssl_cached_sess_t; - - -typedef struct { - ngx_rbtree_node_t node; - u_char *id; - size_t len; - ngx_http_ssl_cached_sess_t *session; -} ngx_http_ssl_sess_id_t; - - -struct ngx_http_ssl_cached_sess_s { - ngx_http_ssl_cached_sess_t *prev; - ngx_http_ssl_cached_sess_t *next; - time_t expire; - ngx_http_ssl_sess_id_t *sess_id; - u_char asn1[1]; -}; - - -typedef struct { - ngx_rbtree_t *session_rbtree; - ngx_http_ssl_cached_sess_t session_cache_head; - ngx_http_ssl_cached_sess_t session_cache_tail; -} ngx_http_ssl_sesssion_cache_t; - - typedef struct { ngx_flag_t enable;