From 8c9950561488f99f6530040deef6ebf8122800b2 Mon Sep 17 00:00:00 2001 From: Jens Elkner Date: Thu, 31 Dec 2020 16:39:00 +0100 Subject: [PATCH] fix acme wrt. security, redundancy, consistency --- configure | 11 ++++++ src/apps/relay/acme.c | 81 ++++++++++++++----------------------------- src/apps/relay/acme.h | 2 -- 3 files changed, 37 insertions(+), 57 deletions(-) diff --git a/configure b/configure index 38227c6e..b85a65ca 100755 --- a/configure +++ b/configure @@ -556,6 +556,17 @@ if [ "${SYSTEM}" = "NetBSD" ] ; then fi fi +# If acme_redirect does not work, send_data_from_ioa_socket_nbh() probably +# does not work. Set LIBEV_OK=1 to use a workaround for it. +if [ -z "${LIBEV_OK}" ]; then + LIBEV_OK=1 + if [ "${SYSTEM}" = "Linux" ]; then + OS=$( lsb_release -si 2>/dev/null ) + [ "${OS}" = "Ubuntu" ] || LIBEV_OK=0 + fi +fi +[ "${LIBEV_OK}" = "1" ] && OSCFLAGS="${OSCFLAGS} -DLIBEV_OK" + ########################### # Install shell commands ########################### diff --git a/src/apps/relay/acme.c b/src/apps/relay/acme.c index 13023d7d..f713d348 100644 --- a/src/apps/relay/acme.c +++ b/src/apps/relay/acme.c @@ -1,43 +1,22 @@ /* - * Copyright (C) 2011, 2012, 2013, 2014 Citrix Systems + * Copyright (C) 2020 Jens Elkner. All rights reserved. * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * License: MIT - see https://opensource.org/licenses/MIT */ #include "acme.h" #include "ns_ioalib_impl.h" +#define GET_ACME_PREFIX "GET /.well-known/acme-challenge/" +#define GET_ACME_PREFIX_LEN 32 + static int is_acme_req(char *req, size_t len) { static const char *A = " - 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ _ abcdefghijklmnopqrstuvwxyz "; int c, i, k; // Check first request line. Should be like: GET path HTTP/1.x - if (strncmp(req, "GET /.well-known/acme-challenge/", 32)) + if (strncmp(req, GET_ACME_PREFIX, GET_ACME_PREFIX_LEN)) return -1; // Usually (for LE) the "method path" is 32 + 43 = 55 chars. But other // implementations may choose longer pathes. We define PATHMAX = 127 chars @@ -45,15 +24,15 @@ static int is_acme_req(char *req, size_t len) { len =- 21; // min size of trailing headers if (len > 131) len = 131; - for (i=32; i < (int) len; i++) { + for (i=GET_ACME_PREFIX_LEN; i < (int) len; i++) { // find the end of the path if (req[i] != ' ') continue; // consider path < 10 chars invalid. Also we wanna see a "trailer". - if (i < 42 || strncmp(req + i, " HTTP/1.", 8)) + if (i < (GET_ACME_PREFIX_LEN + 10) || strncmp(req + i, " HTTP/1.", 8)) return -2; // finally check for allowed chars - for (k=32; k < i; k++) { + for (k=GET_ACME_PREFIX_LEN; k < i; k++) { c = req[k]; if ((c > 127) || (A[c] == ' ')) return -3; @@ -71,51 +50,43 @@ int try_acme_redirect(char *req, size_t len, const char *url, "301 Moved Permanently\

301 Moved Permanently

"; char http_response[1024]; - char req_url[600]; - char *req_url_end_space, *req_url_end_tab; - int path_length; - strcpy(req_url, req + GET_WELLKNOWN_ACMECHALLANGE_URL_PREFIX_LENGTH); - req_url_end_space=strchr(req_url,' '); - req_url_end_tab=strchr(req_url,'\t'); - if (req_url_end_space != NULL && req_url_end_tab != NULL) { - if (req_url_end_space - req_url_end_tab > 0 ){ - path_length=req_url_end_space - req_url; - req_url[path_length]='\0'; - } else { - path_length=req_url_end_tab - req_url; - req_url[req_url_end_tab - req_url]='\0'; - } - } else if(req_url_end_space != NULL) { - path_length=req_url_end_space - req_url; - req_url[path_length]='\0'; - } - else if(req_url_end_tab != NULL) { - path_length=req_url_end_tab - req_url; - req_url[path_length]='\0'; - } - size_t plen, rlen; if (url == NULL || url[0] == '\0' || req == NULL || s == 0 ) return 1; - if (len < 64 || len > 512 || (plen = is_acme_req(req, len)) < 33) + if (len < (GET_ACME_PREFIX_LEN + 32) || len > (512 - GET_ACME_PREFIX_LEN) + || (plen = is_acme_req(req, len)) < (GET_ACME_PREFIX_LEN + 1)) return 2; + req[plen] = '\0'; + snprintf(http_response, sizeof(http_response) - 1, "HTTP/1.1 301 Moved Permanently\r\n" "Content-Type: text/html\r\n" "Content-Length: %ld\r\n" "Connection: close\r\n" "Location: %s%s\r\n" - "\r\n%s", strlen(HTML), url, req_url, HTML); + "\r\n%s", strlen(HTML), url, req + GET_ACME_PREFIX_LEN, HTML); rlen = strlen(http_response); +#ifdef LIBEV_OK ioa_network_buffer_handle nbh_acme = ioa_network_buffer_allocate(s->e); uint8_t *data = ioa_network_buffer_data(nbh_acme); bcopy(http_response, data, rlen); ioa_network_buffer_set_size(nbh_acme, rlen); send_data_from_ioa_socket_nbh(s, NULL, nbh_acme, TTL_IGNORE, TOS_IGNORE, NULL); +#else + if (write(s->fd, http_response, rlen) == -1) { + TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, + "Sending redirect to '%s%s' failed",url, req + GET_ACME_PREFIX_LEN); + } else if (((turn_turnserver *)s->session->server)->verbose) { + TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "ACME redirected to %s%s\n", + url, req + GET_ACME_PREFIX_LEN); + } +#endif + + req[plen] = ' '; return 0; } diff --git a/src/apps/relay/acme.h b/src/apps/relay/acme.h index a927dc56..133c22d1 100644 --- a/src/apps/relay/acme.h +++ b/src/apps/relay/acme.h @@ -44,8 +44,6 @@ extern "C" { ///////////// ACME ///////////////////// -#define GET_WELLKNOWN_ACMECHALLANGE_URL_PREFIX_LENGTH 32 - int try_acme_redirect(char *req, size_t len, const char *url, ioa_socket_handle s); ///////////////////////////////////////