浏览代码

Allow SSL session caching

Add a configuration value "ssl_cache_timeout" (in seconds).
If this is set >0, SSL/TLS session caching is activated.

See #887
bel2125 4 年之前
父节点
当前提交
74f000914f
共有 2 个文件被更改,包括 50 次插入1 次删除
  1. 7 0
      docs/UserManual.md
  2. 43 1
      src/civetweb.c

+ 7 - 0
docs/UserManual.md

@@ -583,6 +583,13 @@ by the subject name’s hash and an extension of “.0”. If there is more than
 certificate with the same subject name they should have extensions ".0", ".1",
 ".2" and so on respectively.
 
+### ssl\_cache\_timeout `-1`
+Allow caching of SSL/TLS sessions, so HTTPS connection from the same client
+to the same server can be established faster. A configuration value >0 activates
+session caching. The configuration value is the maximum lifetime of a cached 
+session in seconds.
+The default is to deactivated session caching.
+
 ### ssl\_certificate
 Path to the SSL certificate file. This option is only required when at least
 one of the `listening\_ports` is SSL. The file must be in PEM format,

+ 43 - 1
src/civetweb.c

@@ -1875,6 +1875,8 @@ typedef struct x509 X509;
 #define SSL_TLSEXT_ERR_ALERT_FATAL (2)
 #define SSL_TLSEXT_ERR_NOACK (3)
 
+#define SSL_SESS_CACHE_BOTH (3)
+
 enum ssl_func_category {
 	TLS_Mandatory, /* required for HTTPS */
 	TLS_ALPN,      /* required for Application Layer Protocol Negotiation */
@@ -1971,6 +1973,11 @@ typedef int (*tSSL_next_protos_advertised_cb)(SSL *ssl,
 	(*(void (*)(SSL_CTX *, tSSL_next_protos_advertised_cb, void *))ssl_sw[41]  \
 	      .ptr)
 
+#define SSL_CTX_set_session_cache_mode                                         \
+	(*(long (*)(SSL_CTX *, long))ssl_sw[42].ptr)
+#define SSL_CTX_sess_set_cache_size (*(long (*)(SSL_CTX *, long))ssl_sw[43].ptr)
+#define SSL_CTX_set_timeout (*(long (*)(SSL_CTX *, long))ssl_sw[44].ptr)
+
 #define SSL_CTX_clear_options(ctx, op)                                         \
 	SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
 #define SSL_CTX_set_ecdh_auto(ctx, onoff)                                      \
@@ -2067,6 +2074,9 @@ static struct ssl_func ssl_sw[] = {
     {"SSL_CTX_set_alpn_protos", TLS_ALPN, NULL},
     {"SSL_CTX_set_alpn_select_cb", TLS_ALPN, NULL},
     {"SSL_CTX_set_next_protos_advertised_cb", TLS_ALPN, NULL},
+    {"SSL_CTX_set_session_cache_mode", TLS_Mandatory, NULL},
+    {"SSL_CTX_sess_set_cache_size", TLS_Mandatory, NULL},
+    {"SSL_CTX_set_timeout", TLS_Mandatory, NULL},
     {NULL, TLS_END_OF_LIST, NULL}};
 
 
@@ -2165,6 +2175,11 @@ typedef int (*tSSL_next_protos_advertised_cb)(SSL *ssl,
 	(*(void (*)(SSL_CTX *, tSSL_next_protos_advertised_cb, void *))ssl_sw[41]  \
 	      .ptr)
 
+#define SSL_CTX_set_session_cache_mode                                         \
+	(*(long (*)(SSL_CTX *, long))ssl_sw[42].ptr)
+#define SSL_CTX_sess_set_cache_size (*(long (*)(SSL_CTX *, long))ssl_sw[43].ptr)
+#define SSL_CTX_set_timeout (*(long (*)(SSL_CTX *, long))ssl_sw[44].ptr)
+
 
 #define SSL_CTX_set_options(ctx, op)                                           \
 	SSL_CTX_ctrl((ctx), SSL_CTRL_OPTIONS, (op), NULL)
@@ -2279,6 +2294,9 @@ static struct ssl_func ssl_sw[] = {
     {"SSL_CTX_set_alpn_protos", TLS_ALPN, NULL},
     {"SSL_CTX_set_alpn_select_cb", TLS_ALPN, NULL},
     {"SSL_CTX_set_next_protos_advertised_cb", TLS_ALPN, NULL},
+    {"SSL_CTX_set_session_cache_mode", TLS_Mandatory, NULL},
+    {"SSL_CTX_sess_set_cache_size", TLS_Mandatory, NULL},
+    {"SSL_CTX_set_timeout", TLS_Mandatory, NULL},
     {NULL, TLS_END_OF_LIST, NULL}};
 
 
@@ -2486,6 +2504,7 @@ enum {
 	URL_REWRITE_PATTERN,
 	HIDE_FILES,
 	SSL_DO_VERIFY_PEER,
+	SSL_CACHE_TIMEOUT,
 	SSL_CA_PATH,
 	SSL_CA_FILE,
 	SSL_VERIFY_DEPTH,
@@ -2603,6 +2622,7 @@ static const struct mg_option config_options[] = {
     {"hide_files_patterns", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
 
     {"ssl_verify_peer", MG_CONFIG_TYPE_YES_NO_OPTIONAL, "no"},
+    {"ssl_cache_timeout", MG_CONFIG_TYPE_NUMBER, "-1"},
 
     {"ssl_ca_path", MG_CONFIG_TYPE_DIRECTORY, NULL},
     {"ssl_ca_file", MG_CONFIG_TYPE_FILE, NULL},
@@ -16474,6 +16494,7 @@ init_ssl_ctx_impl(struct mg_context *phys_ctx,
 	md5_byte_t ssl_context_id[16];
 	md5_state_t md5state;
 	int protocol_ver;
+	int ssl_cache_timeout;
 
 #if defined(OPENSSL_API_1_1)
 	if ((dom_ctx->ssl_ctx = SSL_CTX_new(TLS_server_method())) == NULL) {
@@ -16665,6 +16686,16 @@ init_ssl_ctx_impl(struct mg_context *phys_ctx,
 		}
 	}
 
+	/* SSL session caching */
+	ssl_cache_timeout = ((dom_ctx->config[SSL_CACHE_TIMEOUT] != NULL)
+	                         ? atoi(dom_ctx->config[SSL_CACHE_TIMEOUT])
+	                         : 0);
+	if (ssl_cache_timeout > 0) {
+		SSL_CTX_set_session_cache_mode(dom_ctx->ssl_ctx, SSL_SESS_CACHE_BOTH);
+		/* SSL_CTX_sess_set_cache_size(dom_ctx->ssl_ctx, 10000);  ... use default */
+		SSL_CTX_set_timeout(dom_ctx->ssl_ctx, (long)ssl_cache_timeout);
+	}
+
 	/* Initialize ALPN only of TLS library (OpenSSL version) supports ALPN */
 #if !defined(NO_SSL_DL)
 	if (!tls_feature_missing[TLS_ALPN])
@@ -16710,11 +16741,14 @@ init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
 	                                                phys_ctx->user_data));
 
 	if (callback_ret < 0) {
+		/* Callback exists and returns <0: Initializing failed. */
 		mg_cry_ctx_internal(phys_ctx,
 		                    "external_ssl_ctx callback returned error: %i",
 		                    callback_ret);
 		return 0;
 	} else if (callback_ret > 0) {
+		/* Callback exists and returns >0: Initializing complete,
+		 * civetweb should not modify the SSL context. */
 		dom_ctx->ssl_ctx = (SSL_CTX *)ssl_ctx;
 		if (!initialize_ssl(ebuf, sizeof(ebuf))) {
 			mg_cry_ctx_internal(phys_ctx, "%s", ebuf);
@@ -16722,8 +16756,10 @@ init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
 		}
 		return 1;
 	}
+	/* If the callback does not exist or return 0, civetweb must initialize
+	 * the SSL context. Handle "domain" callback next. */
 
-	/* Check for external domain SSL_CTX */
+	/* Check for external domain SSL_CTX callback. */
 	callback_ret = (phys_ctx->callbacks.external_ssl_ctx_domain == NULL)
 	                   ? 0
 	                   : (phys_ctx->callbacks.external_ssl_ctx_domain(
@@ -16732,12 +16768,14 @@ init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
 	                         phys_ctx->user_data));
 
 	if (callback_ret < 0) {
+		/* Callback < 0: Error. Abort init. */
 		mg_cry_ctx_internal(
 		    phys_ctx,
 		    "external_ssl_ctx_domain callback returned error: %i",
 		    callback_ret);
 		return 0;
 	} else if (callback_ret > 0) {
+		/* Callback > 0: Consider init done. */
 		dom_ctx->ssl_ctx = (SSL_CTX *)ssl_ctx;
 		if (!initialize_ssl(ebuf, sizeof(ebuf))) {
 			mg_cry_ctx_internal(phys_ctx, "%s", ebuf);
@@ -16762,11 +16800,14 @@ init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
 		return 0;
 	}
 
+	/* If a certificate chain is configured, use it. */
 	chain = dom_ctx->config[SSL_CERTIFICATE_CHAIN];
 	if (chain == NULL) {
+		/* Default: certificate chain in PEM file */
 		chain = pem;
 	}
 	if ((chain != NULL) && (*chain == 0)) {
+		/* If the chain is an empty string, don't use it. */
 		chain = NULL;
 	}
 
@@ -18337,6 +18378,7 @@ init_connection(struct mg_connection *conn)
 	 * goes to crule42. */
 	conn->data_len = 0;
 	conn->handled_requests = 0;
+	conn->connection_type = CONNECTION_TYPE_INVALID;
 	mg_set_user_connection_data(conn, NULL);
 
 #if defined(USE_SERVER_STATS)