diff --git a/CMakeLists.txt b/CMakeLists.txt index a7738d098..64c0e5749 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 b36b38851..8893c86b6 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`": "" 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`": "" 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`": "" OPENSSL only: sets the allowed list of <= TLS1.2 ciphers and key exchange protocols for the client SSL_CTX on the vhost + + - "`tls13-ciphers`": "" 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`": "" 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`": "" 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 e8539c1d5..045be0e65 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 2dbf6eb3d..1746093c5 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 425c956aa..cc6a76663 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 61e82ac13..16e3f1041 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 52976d712..a452aa3e6 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 7e23c2e6b..4afe1d6c3 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 355dbc5ee..1e1f1ee53 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';