From c09acbeb8a030942d9825b3d0dd01c84e0a0b919 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Sat, 4 Nov 2017 21:39:30 -0400 Subject: [PATCH] [mod_openssl] ssl.openssl.ssl-conf-cmd (fixes #2758) (similar to Apache mod_ssl SSLOpenSSLConfCmd directive) (experimental) This new directive is for use with OpenSSL only, and is not currently available in LibreSSL. https://wiki.openssl.org/index.php/Manual:SSL_CONF_cmd(3) lighttpd takes "file commands" not "command line commands" as openssl SSL_CONF_cmd() appears to permit only one mode at a time. lighttpd processes this directive after all other ssl.* directives have been applied for the $SERVER["socket"] scope. x-ref: "Option to disable TLS session tickets" https://redmine.lighttpd.net/issues/2758 "Allow to selectively disable TLS 1.0, 1.1 and 1.2 versions" https://github.com/lighttpd/lighttpd1.4/pull/84 github: closes #84 --- src/mod_openssl.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/mod_openssl.c b/src/mod_openssl.c index 6001b3fd..88520edb 100644 --- a/src/mod_openssl.c +++ b/src/mod_openssl.c @@ -62,6 +62,7 @@ typedef struct { buffer *ssl_cipher_list; buffer *ssl_dh_file; buffer *ssl_ec_curve; + array *ssl_conf_cmd; } plugin_config; typedef struct { @@ -129,6 +130,8 @@ FREE_FUNC(mod_openssl_free) buffer_free(s->ssl_dh_file); buffer_free(s->ssl_ec_curve); buffer_free(s->ssl_verifyclient_username); + array_free(s->ssl_conf_cmd); + if (copy) continue; SSL_CTX_free(s->ssl_ctx); EVP_PKEY_free(s->ssl_pemfile_pkey); @@ -489,6 +492,62 @@ network_openssl_load_pemfile (server *srv, plugin_config *s, size_t ndx) static int +network_openssl_ssl_conf_cmd (server *srv, plugin_config *s) +{ + #ifdef SSL_CONF_FLAG_CMDLINE + + int rc = 0; + data_string *ds; + SSL_CONF_CTX * const cctx = SSL_CONF_CTX_new(); + SSL_CONF_CTX_set_ssl_ctx(cctx, s->ssl_ctx); + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE + | SSL_CONF_FLAG_SERVER + | SSL_CONF_FLAG_SHOW_ERRORS + | SSL_CONF_FLAG_CERTIFICATE); + + /* always disable null and export ciphers */ + ds = (data_string *) + array_get_element_klen(s->ssl_conf_cmd, + CONST_STR_LEN("CipherString")); + if (NULL != ds) { + buffer_append_string_len(ds->value, + CONST_STR_LEN(":!aNULL:!eNULL:!EXP")); + } + + for (size_t i = 0; i < s->ssl_conf_cmd->used; ++i) { + ds = (data_string *)s->ssl_conf_cmd->data[i]; + ERR_clear_error(); + if (SSL_CONF_cmd(cctx, ds->key->ptr, ds->value->ptr) <= 0) { + log_error_write(srv, __FILE__, __LINE__, "ssbbss", "SSL:", + "SSL_CONF_cmd", ds->key, ds->value, ":", + ERR_error_string(ERR_get_error(), NULL)); + rc = -1; + break; + } + } + + if (0 == rc && 1 != SSL_CONF_CTX_finish(cctx)) { + log_error_write(srv, __FILE__, __LINE__, "sss", "SSL:", + "SSL_CONF_CTX_finish():", + ERR_error_string(ERR_get_error(), NULL)); + rc = -1; + } + + SSL_CONF_CTX_free(cctx); + return rc; + + #else + + UNUSED(s); + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", + "ssl.openssl.ssl-conf-cmd not available; ignored"); + return 0; + + #endif +} + + +static int network_init_ssl (server *srv, void *p_d) { plugin_data *p = p_d; @@ -883,6 +942,10 @@ network_init_ssl (server *srv, void *p_d) return -1; } #endif + + if (s->ssl_conf_cmd->used) { + if (0 != network_openssl_ssl_conf_cmd(srv, s)) return -1; + } } return 0; @@ -913,6 +976,7 @@ SETDEFAULTS_FUNC(mod_openssl_set_defaults) { "ssl.use-sslv3", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 17 */ { "ssl.ca-crl-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 18 */ { "ssl.ca-dn-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 19 */ + { "ssl.openssl.ssl-conf-cmd", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 20 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; @@ -947,6 +1011,9 @@ SETDEFAULTS_FUNC(mod_openssl_set_defaults) : p->config_storage[0]->ssl_read_ahead; if (0 != i) buffer_copy_buffer(s->ssl_ca_crl_file, p->config_storage[0]->ssl_ca_crl_file); if (0 != i) buffer_copy_buffer(s->ssl_ca_dn_file, p->config_storage[0]->ssl_ca_dn_file); + s->ssl_conf_cmd = (0 == i) + ? array_init() + : array_init_array(p->config_storage[0]->ssl_conf_cmd); cv[0].destination = &(s->ssl_log_noise); cv[1].destination = &(s->ssl_enabled); @@ -968,6 +1035,7 @@ SETDEFAULTS_FUNC(mod_openssl_set_defaults) cv[17].destination = &(s->ssl_use_sslv3); cv[18].destination = s->ssl_ca_crl_file; cv[19].destination = s->ssl_ca_dn_file; + cv[20].destination = s->ssl_conf_cmd; p->config_storage[i] = s; @@ -997,6 +1065,12 @@ SETDEFAULTS_FUNC(mod_openssl_set_defaults) "ssl.engine is valid only in global scope " "or $SERVER[\"socket\"] condition"); } + + if (!array_is_kvstring(s->ssl_conf_cmd)) { + log_error_write(srv, __FILE__, __LINE__, "s", + "ssl.openssl.ssl-conf-cmd must be array " + "of \"key\" => \"value\" strings"); + } } if (0 != network_init_ssl(srv, p)) return HANDLER_ERROR; @@ -1027,6 +1101,7 @@ mod_openssl_patch_connection (server *srv, connection *con, handler_ctx *hctx) /*PATCH(ssl_empty_fragments);*//*(not patched)*/ /*PATCH(ssl_use_sslv2);*//*(not patched)*/ /*PATCH(ssl_use_sslv3);*//*(not patched)*/ + /*PATCH(ssl_conf_cmd);*//*(not patched)*/ PATCH(ssl_verifyclient); PATCH(ssl_verifyclient_enforce); @@ -1095,6 +1170,8 @@ mod_openssl_patch_connection (server *srv, connection *con, handler_ctx *hctx) PATCH(ssl_ec_curve); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.engine"))) { PATCH(ssl_enabled); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.openssl.ssl-conf-cmd"))) { + PATCH(ssl_conf_cmd); #endif } } -- 2.11.4.GIT