diff --git a/changelog b/changelog index 99758be4..602a9bb9 100644 --- a/changelog +++ b/changelog @@ -20,6 +20,12 @@ processing is protected by a 5s timeout. The chunks are stored in a malloc'd buffer of size protocols[0].rx_buffer_size. +New server option you can enable from user code +LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT allows non-SSL connections to +also be accepted on an SSL listening port. It's disabled unless you enable +it explicitly. + + User api changes ---------------- diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 7342e9ba..8b2fec52 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -1892,6 +1892,7 @@ libwebsocket_create_context(struct lws_context_creation_info *info) #ifdef LWS_OPENSSL_SUPPORT context->use_ssl = 0; + context->allow_non_ssl_on_ssl_port = 0; context->ssl_ctx = NULL; context->ssl_client_ctx = NULL; openssl_websocket_private_data_index = 0; @@ -2135,6 +2136,11 @@ libwebsocket_create_context(struct lws_context_creation_info *info) context->ssl_ctx, NULL, 0); } + if(info->options & LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT) { + /* Normally SSL listener rejects non-ssl, optionally allow */ + context->allow_non_ssl_on_ssl_port = 1; + } + if (context->use_ssl) { /* openssl init for server sockets */ diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index cfd1f8c5..b2ba3594 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -138,6 +138,7 @@ LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len); enum libwebsocket_context_options { LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2, LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = 4, + LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT = 8 }; enum libwebsocket_callback_reasons { diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 12b8d5a8..ea68f4bc 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -289,6 +289,7 @@ struct libwebsocket_context { #ifdef LWS_OPENSSL_SUPPORT int use_ssl; + int allow_non_ssl_on_ssl_port; SSL_CTX *ssl_ctx; SSL_CTX *ssl_client_ctx; #endif diff --git a/lib/server.c b/lib/server.c index 6c35c98e..700a6e28 100644 --- a/lib/server.c +++ b/lib/server.c @@ -354,6 +354,37 @@ int lws_server_socket_service(struct libwebsocket_context *context, wsi->user_space, (void *)(long)wsi->sock, POLLOUT); lws_latency_pre(context, wsi); + + n = recv(wsi->sock, context->service_buffer, + sizeof(context->service_buffer), MSG_PEEK); + + /* + * optionally allow non-SSL connect on SSL listening socket + * This is disabled by default, if enabled it goes around any + * SSL-level access control (eg, client-side certs) so leave + * it disabled unless you know it's not a problem for you + */ + + if (context->allow_non_ssl_on_ssl_port && n >= 1 && + context->service_buffer[0] >= ' ') { + /* + * TLS content-type for Handshake is 0x16 + * TLS content-type for ChangeCipherSpec Record is 0x14 + * + * A non-ssl session will start with the HTTP method in + * ASCII. If we see it's not a legit SSL handshake + * kill the SSL for this connection and try to handle + * as a HTTP connection upgrade directly. + */ + wsi->use_ssl = 0; + SSL_shutdown(wsi->ssl); + SSL_free(wsi->ssl); + wsi->ssl = NULL; + goto accepted; + } + + /* normal SSL connection processing path */ + n = SSL_accept(wsi->ssl); lws_latency(context, wsi, "SSL_accept LWS_CONNMODE_SSL_ACK_PENDING\n", n, n == 1); @@ -378,7 +409,6 @@ int lws_server_socket_service(struct libwebsocket_context *context, if (m == SSL_ERROR_WANT_WRITE) { context->fds[ wsi->position_in_fds_table].events |= POLLOUT; - /* external POLL support via protocol 0 */ context->protocols[0].callback(context, wsi, LWS_CALLBACK_SET_MODE_POLL_FD, @@ -387,13 +417,14 @@ int lws_server_socket_service(struct libwebsocket_context *context, break; } lwsl_debug("SSL_accept failed skt %u: %s\n", - pollfd->fd, - ERR_error_string(m, NULL)); + pollfd->fd, + ERR_error_string(m, NULL)); libwebsocket_close_and_free_session(context, wsi, - LWS_CLOSE_STATUS_NOSTATUS); + LWS_CLOSE_STATUS_NOSTATUS); break; } +accepted: /* OK, we are accepted */ libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); diff --git a/test-server/test-server.c b/test-server/test-server.c index 0a32ba08..f82cd0c5 100644 --- a/test-server/test-server.c +++ b/test-server/test-server.c @@ -715,6 +715,7 @@ static struct option options[] = { { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, + { "allow-non-ssl", no_argument, NULL, 'a' }, { "interface", required_argument, NULL, 'i' }, { "closetest", no_argument, NULL, 'c' }, #ifndef LWS_NO_DAEMONIZE @@ -749,7 +750,7 @@ int main(int argc, char **argv) info.port = 7681; while (n >= 0) { - n = getopt_long(argc, argv, "ci:hsp:d:Dr:", options, NULL); + n = getopt_long(argc, argv, "ci:hsap:d:Dr:", options, NULL); if (n < 0) continue; switch (n) { @@ -767,6 +768,9 @@ int main(int argc, char **argv) case 's': use_ssl = 1; break; + case 'a': + opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT; + break; case 'p': info.port = atoi(optarg); break;