From 93d4e186c2f45ba4f16cbe1dd107545b606dde89 Mon Sep 17 00:00:00 2001 From: Andy Green <andy@warmcat.com> Date: Sat, 27 Oct 2018 08:05:21 +0800 Subject: [PATCH] openssl tls1.3: allow setting ciphersuites at context creation time https://github.com/warmcat/libwebsockets/issues/1440 --- CMakeLists.txt | 1 + READMEs/README.lwsws.md | 10 ++++++++-- cmake/lws_config.h.in | 1 + include/libwebsockets/lws-context-vhost.h | 20 ++++++++++++++++++-- lib/roles/http/server/lejp-conf.c | 11 +++++++++++ lib/roles/http/server/server.c | 15 ++++++++------- lib/tls/openssl/openssl-client.c | 6 ++++++ lib/tls/openssl/openssl-server.c | 6 ++++++ test-apps/test-server.c | 3 +-- 9 files changed, 60 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a7738d09..64c0e574 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1550,6 +1550,7 @@ CHECK_FUNCTION_EXISTS(X509_get_key_usage LWS_HAVE_X509_get_key_usage) CHECK_FUNCTION_EXISTS(SSL_CTX_get0_certificate LWS_HAVE_SSL_CTX_get0_certificate) CHECK_FUNCTION_EXISTS(SSL_get0_alpn_selected LWS_HAVE_SSL_get0_alpn_selected) CHECK_FUNCTION_EXISTS(SSL_set_alpn_protos LWS_HAVE_SSL_set_alpn_protos) +CHECK_FUNCTION_EXISTS(SSL_CTX_set_ciphersuites LWS_HAVE_SSL_CTX_set_ciphersuites) if (LWS_WITH_SSL AND NOT LWS_WITH_MBEDTLS) CHECK_SYMBOL_EXISTS(SSL_CTX_get_extra_chain_certs_only openssl/ssl.h LWS_HAVE_SSL_EXTRA_CHAIN_CERTS) endif() diff --git a/READMEs/README.lwsws.md b/READMEs/README.lwsws.md index b36b3885..8893c86b 100644 --- a/READMEs/README.lwsws.md +++ b/READMEs/README.lwsws.md @@ -233,9 +233,15 @@ See also "rawonly" below. - `"enable-client-ssl"`: `"1"` enables the vhost's client SSL context, you will need this if you plan to create client conections on the vhost that will use SSL. You don't need it if you only want http / ws client connections. - - "`ciphers`": "<cipher list>" sets the allowed list of ciphers and key exchange protocols for the vhost. The default list is restricted to only those providing PFS (Perfect Forward Secrecy) on the author's Fedora system. + - "`ciphers`": "<cipher list>" OPENSSL only: sets the allowed list of TLS <= 1.2 ciphers and key exchange protocols for the serving SSL_CTX on the vhost. The default list is restricted to only those providing PFS (Perfect Forward Secrecy) on the author's Fedora system. - If you need to allow weaker ciphers,you can provide an alternative list here per-vhost. + If you need to allow weaker ciphers, you can provide an alternative list here per-vhost. + + - "`client-ssl-ciphers`": "<cipher list>" OPENSSL only: sets the allowed list of <= TLS1.2 ciphers and key exchange protocols for the client SSL_CTX on the vhost + + - "`tls13-ciphers`": "<cipher list>" OPENSSL 1.1.1+ only: sets allowed list of TLS1.3+ ciphers and key exchange protocols for the client SSL_CTX on the vhost. The default is to allow all. + + - "`client-tls13-ciphers`": "<cipher list>" OPENSSL 1.1.1+ only: sets the allowed list of TLS1.3+ ciphers and key exchange protocols for the client SSL_CTX on the vhost. The default is to allow all. - "`ecdh-curve`": "<curve name>" The default ecdh curve is "prime256v1", but you can override it here, per-vhost diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in index e8539c1d..045be0e6 100644 --- a/cmake/lws_config.h.in +++ b/cmake/lws_config.h.in @@ -111,6 +111,7 @@ #cmakedefine LWS_HAVE_RSA_SET0_KEY #cmakedefine LWS_HAVE_X509_get_key_usage #cmakedefine LWS_HAVE_SSL_CTX_get0_certificate +#cmakedefine LWS_HAVE_SSL_CTX_set_ciphersuites #cmakedefine LWS_HAVE_UV_VERSION_H #cmakedefine LWS_HAVE_NEW_UV_VERSION_H diff --git a/include/libwebsockets/lws-context-vhost.h b/include/libwebsockets/lws-context-vhost.h index 2dbf6eb3..1746093c 100644 --- a/include/libwebsockets/lws-context-vhost.h +++ b/include/libwebsockets/lws-context-vhost.h @@ -205,12 +205,15 @@ struct lws_context_creation_info { * filepath when setting up a vhost client SSL context, * but it is preferred to use .client_ssl_ca_filepath for that.) */ const char *ssl_cipher_list; - /**< VHOST: List of valid ciphers to use (eg, + /**< VHOST: List of valid ciphers to use ON TLS1.2 AND LOWER ONLY (eg, * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL" * or you can leave it as NULL to get "DEFAULT" (For backwards * compatibility, this can also be used to pass the client cipher * list when setting up a vhost client SSL context, - * but it is preferred to use .client_ssl_cipher_list for that.)*/ + * but it is preferred to use .client_ssl_cipher_list for that.) + * SEE .tls1_3_plus_cipher_list and .client_tls_1_3_plus_cipher_list + * for the equivalent for tls1.3. + */ const char *http_proxy_address; /**< VHOST: If non-NULL, attempts to proxy via the given address. * If proxy auth is required, use format "username:password\@server:port" */ @@ -491,6 +494,19 @@ struct lws_context_creation_info { long ssl_client_options_clear; /**< VHOST: Any bits set here will be cleared as CLIENT SSL options */ + const char *tls1_3_plus_cipher_list; + /**< VHOST: List of valid ciphers to use for incoming server connections + * ON TLS1.3 AND ABOVE (eg, "TLS_CHACHA20_POLY1305_SHA256" on this vhost + * or you can leave it as NULL to get "DEFAULT". + * SEE .client_tls_1_3_plus_cipher_list to do the same on the vhost + * client SSL_CTX. + */ + const char *client_tls_1_3_plus_cipher_list; + /**< VHOST: List of valid ciphers to use for outgoing client connections + * ON TLS1.3 AND ABOVE on this vhost (eg, + * "TLS_CHACHA20_POLY1305_SHA256") or you can leave it as NULL to get + * "DEFAULT". + */ /* Add new things just above here ---^ * This is part of the ABI, don't needlessly break compatibility diff --git a/lib/roles/http/server/lejp-conf.c b/lib/roles/http/server/lejp-conf.c index 425c956a..cc6a7666 100644 --- a/lib/roles/http/server/lejp-conf.c +++ b/lib/roles/http/server/lejp-conf.c @@ -107,6 +107,8 @@ static const char * const paths_vhosts[] = { "vhosts[].alpn", "vhosts[].ssl-client-option-set", "vhosts[].ssl-client-option-clear", + "vhosts[].tls13-ciphers", + "vhosts[].client-tls13-ciphers", }; enum lejp_vhost_paths { @@ -160,6 +162,8 @@ enum lejp_vhost_paths { LEJPVP_ALPN, LEJPVP_SSL_CLIENT_OPTION_SET, LEJPVP_SSL_CLIENT_OPTION_CLEAR, + LEJPVP_TLS13_CIPHERS, + LEJPVP_CLIENT_TLS13_CIPHERS, }; static const char * const parser_errs[] = { @@ -623,6 +627,13 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) case LEJPVP_CIPHERS: a->info->ssl_cipher_list = a->p; break; + case LEJPVP_TLS13_CIPHERS: + a->info->tls1_3_plus_cipher_list = a->p; + break; + case LEJPVP_CLIENT_TLS13_CIPHERS: + a->info->client_tls_1_3_plus_cipher_list = a->p; + break; + case LEJPVP_ECDH_CURVE: a->info->ecdh_curve = a->p; break; diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c index 61e82ac1..16e3f104 100644 --- a/lib/roles/http/server/server.c +++ b/lib/roles/http/server/server.c @@ -1270,14 +1270,15 @@ lws_http_action(struct lws *wsi) } *p++ = '?'; - lws_hdr_copy(wsi, p, + if (lws_hdr_copy(wsi, p, (int)(&rpath[sizeof(rpath) - 1] - p), - WSI_TOKEN_HTTP_URI_ARGS); - while (--na) { - if (*p == '\0') - *p = '&'; - p++; - } + WSI_TOKEN_HTTP_URI_ARGS) > 0) + while (--na) { + if (*p == '\0') + *p = '&'; + p++; + } + *p = '\0'; } i.path = rpath; diff --git a/lib/tls/openssl/openssl-client.c b/lib/tls/openssl/openssl-client.c index 52976d71..a452aa3e 100644 --- a/lib/tls/openssl/openssl-client.c +++ b/lib/tls/openssl/openssl-client.c @@ -389,6 +389,12 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, if (cipher_list) SSL_CTX_set_cipher_list(vh->tls.ssl_client_ctx, cipher_list); +#if defined(LWS_HAVE_SSL_CTX_set_ciphersuites) + if (info->client_tls_1_3_plus_cipher_list) + SSL_CTX_set_ciphersuites(vh->tls.ssl_client_ctx, + info->client_tls_1_3_plus_cipher_list); +#endif + #ifdef LWS_SSL_CLIENT_USE_OS_CA_CERTS if (!lws_check_opt(vh->options, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS)) /* loads OS default CA certs */ diff --git a/lib/tls/openssl/openssl-server.c b/lib/tls/openssl/openssl-server.c index 7e23c2e6..4afe1d6c 100644 --- a/lib/tls/openssl/openssl-server.c +++ b/lib/tls/openssl/openssl-server.c @@ -376,6 +376,12 @@ lws_tls_server_vhost_backend_init(const struct lws_context_creation_info *info, if (info->ssl_cipher_list) SSL_CTX_set_cipher_list(vhost->tls.ssl_ctx, info->ssl_cipher_list); +#if defined(LWS_HAVE_SSL_CTX_set_ciphersuites) + if (info->tls1_3_plus_cipher_list) + SSL_CTX_set_ciphersuites(vhost->tls.ssl_ctx, + info->tls1_3_plus_cipher_list); +#endif + #if !defined(OPENSSL_NO_TLSEXT) SSL_CTX_set_tlsext_servername_callback(vhost->tls.ssl_ctx, lws_ssl_server_name_cb); diff --git a/test-apps/test-server.c b/test-apps/test-server.c index 355dbc5e..1e1f1ee5 100644 --- a/test-apps/test-server.c +++ b/test-apps/test-server.c @@ -107,8 +107,7 @@ lws_callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, } if (lws_hdr_copy(wsi, buf, sizeof buf, n) < 0) - fprintf(stderr, " %s (too big)\n", - (char *)c, buf); + fprintf(stderr, " %s (too big)\n", (char *)c); else { buf[sizeof(buf) - 1] = '\0'; -- GitLab