diff --git a/core/cache.c b/core/cache.c index 3eaf1d66..4cc9bc91 100644 --- a/core/cache.c +++ b/core/cache.c @@ -4,9 +4,6 @@ extern struct uwsgi_server uwsgi; void uwsgi_init_cache() { - if (!uwsgi.cache_blocksize) - uwsgi.cache_blocksize = UMAX16; - uwsgi.cache_hashtable = (uint64_t *) mmap(NULL, sizeof(uint64_t) * UMAX16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); if (!uwsgi.cache_hashtable) { uwsgi_error("mmap()"); diff --git a/core/init.c b/core/init.c index fa56949a..6d1c034e 100644 --- a/core/init.c +++ b/core/init.c @@ -14,6 +14,7 @@ void uwsgi_init_default() { uwsgi.signal_socket = -1; uwsgi.my_signal_socket = -1; uwsgi.cache_server_fd = -1; + uwsgi.cache_blocksize = UMAX16; uwsgi.stats_fd = -1; uwsgi.stats_pusher_default_freq = 3; @@ -76,6 +77,7 @@ void uwsgi_init_default() { #ifdef UWSGI_SSL // 1 day of tolerance uwsgi.subscriptions_sign_check_tolerance = 3600 * 24; + uwsgi.ssl_sessions_timeout = 300; #endif #ifdef UWSGI_ALARM diff --git a/core/utils.c b/core/utils.c index e04e5688..174c9dbf 100644 --- a/core/utils.c +++ b/core/utils.c @@ -4294,6 +4294,59 @@ int uwsgi_ssl_verify_callback(int ok, X509_STORE_CTX * x509_store) { return 1; } +int uwsgi_ssl_session_new_cb(SSL *ssl, SSL_SESSION *sess) { + char session_blob[4096]; + int len = i2d_SSL_SESSION(sess, NULL); + if (len > 4096) { + if (uwsgi.ssl_verbose) { + uwsgi_log("[uwsgi-ssl] unable to store session of size %d\n", len); + } + return 0; + } + + unsigned char *p = (unsigned char *) session_blob; + i2d_SSL_SESSION(sess, &p); + + // ok let's write the value to the cache + uwsgi_wlock(uwsgi.cache_lock); + if (uwsgi_cache_set((char *) sess->session_id, sess->session_id_length, session_blob, len, uwsgi.ssl_sessions_timeout, 0)) { + if (uwsgi.ssl_verbose) { + uwsgi_log("[uwsgi-ssl] unable to store session of size %d in the cache\n", len); + } + } + uwsgi_rwunlock(uwsgi.cache_lock); + return 0; +} + +SSL_SESSION *uwsgi_ssl_session_get_cb(SSL *ssl, unsigned char *key, int keylen, int *copy) { + + uint64_t valsize = 0; + + *copy = 0; + uwsgi_rlock(uwsgi.cache_lock); + char *value = uwsgi_cache_get((char *)key, keylen, &valsize); + if (!value) { + uwsgi_rwunlock(uwsgi.cache_lock); + if (uwsgi.ssl_verbose) { + uwsgi_log("[uwsgi-ssl] cache miss\n"); + } + return NULL; + } + SSL_SESSION *sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&value, valsize); + uwsgi_rwunlock(uwsgi.cache_lock); + return sess; +} + +void uwsgi_ssl_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) { + uwsgi_wlock(uwsgi.cache_lock); + if (uwsgi_cache_del((char *) sess->session_id, sess->session_id_length, 0)) { + if (uwsgi.ssl_verbose) { + uwsgi_log("[uwsgi-ssl] error removing cache item\n"); + } + } + uwsgi_rwunlock(uwsgi.cache_lock); +} + SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ciphers, char *client_ca) { SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method()); @@ -4310,7 +4363,6 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci #ifdef SSL_OP_NO_COMPRESSION ssloptions |= SSL_OP_NO_COMPRESSION; #endif - SSL_CTX_set_options(ctx, ssloptions); // release/reuse buffers as soon as possibile #ifdef SSL_MODE_RELEASE_BUFFERS @@ -4354,7 +4406,7 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci exit(1); } - SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); + ssloptions |= SSL_OP_CIPHER_SERVER_PREFERENCE; } // set session context (if possibile), this is required for client certificate authentication @@ -4391,6 +4443,35 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci // disable session caching by default SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); + if (uwsgi.ssl_sessions_use_cache) { + + if (!uwsgi.cache_max_items) { + uwsgi_log("you have to enable uWSGI cache to use it as SSL session store !!!\n"); + exit(1); + } + + if (uwsgi.cache_blocksize < 4096) { + uwsgi_log("cache blocksize for SSL session store must be at least 4096 bytes\n"); + exit(1); + } + + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER| + SSL_SESS_CACHE_NO_INTERNAL| + SSL_SESS_CACHE_NO_AUTO_CLEAR); + + ssloptions |= SSL_OP_NO_TICKET; + + // just for fun + SSL_CTX_sess_set_cache_size(ctx, 0); + + // set the callback for ssl sessions + SSL_CTX_sess_set_new_cb(ctx, uwsgi_ssl_session_new_cb); + SSL_CTX_sess_set_get_cb(ctx, uwsgi_ssl_session_get_cb); + SSL_CTX_sess_set_remove_cb(ctx, uwsgi_ssl_session_remove_cb); + } + + SSL_CTX_set_timeout(ctx, uwsgi.ssl_sessions_timeout); + /* SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); #ifdef UWSGI_DEBUG @@ -4401,6 +4482,9 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci } */ + SSL_CTX_set_options(ctx, ssloptions); + + return ctx; } diff --git a/core/uwsgi.c b/core/uwsgi.c index 1ebea24d..094791de 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -343,6 +343,10 @@ static struct uwsgi_option uwsgi_base_options[] = { #endif #ifdef UWSGI_SSL {"ssl-verbose", no_argument, 0, "be verbose about SSL errors", uwsgi_opt_true, &uwsgi.ssl_verbose, 0}, + {"ssl-sessions-use-cache", no_argument, 0, "use uWSGI cache for ssl sessions storage", uwsgi_opt_true, &uwsgi.ssl_sessions_use_cache, 0}, + {"ssl-session-use-cache", no_argument, 0, "use uWSGI cache for ssl sessions storage", uwsgi_opt_true, &uwsgi.ssl_sessions_use_cache, 0}, + {"ssl-sessions-timeout", required_argument, 0, "set SSL sessions timeout (default: 300 seconds)", uwsgi_opt_set_int, &uwsgi.ssl_sessions_timeout, 0}, + {"ssl-session-timeout", required_argument, 0, "set SSL sessions timeout (default: 300 seconds)", uwsgi_opt_set_int, &uwsgi.ssl_sessions_timeout, 0}, #endif {"check-interval", required_argument, 0, "set the interval (in seconds) of master checks", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_MASTER_INTERVAL, 0}, {"forkbomb-delay", required_argument, 0, "sleep for the specified number of seconds when a forkbomb is detected", uwsgi_opt_set_int, &uwsgi.forkbomb_delay, UWSGI_OPT_MASTER}, diff --git a/uwsgi.h b/uwsgi.h index 62b24a49..90d476bb 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -1886,6 +1886,8 @@ struct uwsgi_server { #ifdef UWSGI_SSL int ssl_initialized; int ssl_verbose; + int ssl_sessions_use_cache; + int ssl_sessions_timeout; #endif #ifdef __linux__