commit lighttpd for openSUSE:Factory
Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package lighttpd for openSUSE:Factory checked in at 2023-10-31 20:25:56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/lighttpd (Old) and /work/SRC/openSUSE:Factory/.lighttpd.new.17445 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "lighttpd" Tue Oct 31 20:25:56 2023 rev:62 rq:1121373 version:1.4.73 Changes: -------- --- /work/SRC/openSUSE:Factory/lighttpd/lighttpd.changes 2023-10-08 12:23:05.224444980 +0200 +++ /work/SRC/openSUSE:Factory/.lighttpd.new.17445/lighttpd.changes 2023-10-31 20:26:15.003152780 +0100 @@ -1,0 +2,7 @@ +Tue Oct 31 06:53:05 UTC 2023 - Andreas Stieger <andreas.stieger@gmx.de> + +- update to 1.4.73: + * CVE-2023-44487: HTTP/2 detect and log rapid reset attack + (boo#1216123) + +------------------------------------------------------------------- Old: ---- lighttpd-1.4.72.tar.xz lighttpd-1.4.72.tar.xz.asc New: ---- lighttpd-1.4.73.tar.xz lighttpd-1.4.73.tar.xz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ lighttpd.spec ++++++ --- /var/tmp/diff_new_pack.MXB2H7/_old 2023-10-31 20:26:15.819182753 +0100 +++ /var/tmp/diff_new_pack.MXB2H7/_new 2023-10-31 20:26:15.823182900 +0100 @@ -26,7 +26,7 @@ %define _fillupdir %{_localstatedir}/adm/fillup-templates %endif Name: lighttpd -Version: 1.4.72 +Version: 1.4.73 Release: 0 Summary: A Secure, Fast, Compliant, and Very Flexible Web Server License: BSD-3-Clause ++++++ lighttpd-1.4.72.tar.xz -> lighttpd-1.4.73.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/CMakeLists.txt new/lighttpd-1.4.73/CMakeLists.txt --- old/lighttpd-1.4.72/CMakeLists.txt 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/CMakeLists.txt 2023-10-31 03:35:56.000000000 +0100 @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.7.0 FATAL_ERROR) -project(lighttpd VERSION 1.4.72 LANGUAGES C) +project(lighttpd VERSION 1.4.73 LANGUAGES C) # use C11 with CMake >= 3.1 set(CMAKE_C_STANDARD 11) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/NEWS new/lighttpd-1.4.73/NEWS --- old/lighttpd-1.4.72/NEWS 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/NEWS 2023-10-31 03:35:56.000000000 +0100 @@ -3,6 +3,34 @@ NEWS ==== +- 1.4.73 - 2023-10-30 + * [core] add .mkv to mimetype.assign builtin defaults + * [core] warn if out-of-range value for config short + * [mod_openssl] set default curves for ossl < 1.1.0 + * [mod_h2] parse HEADERS flags sooner + * [mod_h2] check send window before defer frame rd + * [mod_h2] send GOAWAY to excessive request flood + * [mod_h2] h2_parse_headers_frame() adjust args + * [mod_h2] h2_recv_headers() parse trailers earlier + * [mod_h2] send GOAWAY to excessive request flood + * [mod_h2] discard new streams after GOAWAY sent + * [mod_h2] h2_discard_headers() to HPACK-decode hdrs + * [core] parse entire server.http-parseopts list + * [mod_wstunnel] Sec-WebSocket-Protocol only if req hdr + * [mod_h2] disable h2proto if mod_h2 was not found + * [core] omit dlopen trace for mod_h2, mod_deflate + * [mod_h2] defer input parsing if large output queue + * [mod_h2] defer frame handling if stream pend close + * [mod_h2] detect and log HTTP/2 rapid reset attack + * [core] honor MBEDTLS_USE_PSA_CRYPTO for hash,rand + * [mod_mbedtls] honor MBEDTLS_USE_PSA_CRYPTO for rand + * [core] comment out li_rand_bytes() (unused) + * [mod_mbedtls] handle mbedtls 3.x partial write + * [mod_h2] detect and log HTTP/2 rapid reset attack + * [mod_h2] detect and log HTTP/2 rapid reset attack + * [mod_openssl] warn if openssl version < 3.0.0 + * [mod_openssl] include openssl/hmac.h for boringssl + - 1.4.72 - 2023-10-06 * [core] save config read from stdin across restart * [core] warn if daemonize w/o absolute config path diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/SConstruct new/lighttpd-1.4.73/SConstruct --- old/lighttpd-1.4.72/SConstruct 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/SConstruct 2023-10-31 03:35:56.000000000 +0100 @@ -12,7 +12,7 @@ string_types = str package = 'lighttpd' -version = '1.4.72' +version = '1.4.73' underscorify_reg = re.compile('[^A-Z0-9]') def underscorify(id): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/configure new/lighttpd-1.4.73/configure --- old/lighttpd-1.4.72/configure 2023-10-07 02:10:58.000000000 +0200 +++ new/lighttpd-1.4.73/configure 2023-10-31 03:36:07.000000000 +0100 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for lighttpd 1.4.72. +# Generated by GNU Autoconf 2.71 for lighttpd 1.4.73. # # Report bugs to <https://redmine.lighttpd.net/projects/lighttpd/boards/2>. # @@ -622,8 +622,8 @@ # Identity of this package. PACKAGE_NAME='lighttpd' PACKAGE_TARNAME='lighttpd' -PACKAGE_VERSION='1.4.72' -PACKAGE_STRING='lighttpd 1.4.72' +PACKAGE_VERSION='1.4.73' +PACKAGE_STRING='lighttpd 1.4.73' PACKAGE_BUGREPORT='https://redmine.lighttpd.net/projects/lighttpd/boards/2' PACKAGE_URL='https://www.lighttpd.net/' @@ -1527,7 +1527,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures lighttpd 1.4.72 to adapt to many kinds of systems. +\`configure' configures lighttpd 1.4.73 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1598,7 +1598,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of lighttpd 1.4.72:";; + short | recursive ) echo "Configuration of lighttpd 1.4.73:";; esac cat <<\_ACEOF @@ -1807,7 +1807,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -lighttpd configure 1.4.72 +lighttpd configure 1.4.73 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. @@ -2223,7 +2223,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by lighttpd $as_me 1.4.72, which was +It was created by lighttpd $as_me 1.4.73, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -3575,7 +3575,7 @@ # Define the identity of the package. PACKAGE='lighttpd' - VERSION='1.4.72' + VERSION='1.4.73' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -21856,7 +21856,7 @@ fi fi -LIGHTTPD_VERSION_ID=0x10448 +LIGHTTPD_VERSION_ID=0x10449 printf "%s\n" "#define LIGHTTPD_VERSION_ID $LIGHTTPD_VERSION_ID" >>confdefs.h @@ -22454,7 +22454,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by lighttpd $as_me 1.4.72, which was +This file was extended by lighttpd $as_me 1.4.73, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -22523,7 +22523,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -lighttpd config.status 1.4.72 +lighttpd config.status 1.4.73 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/configure.ac new/lighttpd-1.4.73/configure.ac --- old/lighttpd-1.4.72/configure.ac 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/configure.ac 2023-10-31 03:35:56.000000000 +0100 @@ -14,7 +14,7 @@ dnl function call, the argument should be on different lines than the dnl wrapping braces AC_PREREQ([2.60]) -AC_INIT([lighttpd],[1.4.72],[https://redmine.lighttpd.net/projects/lighttpd/boards/2],[lighttpd],[https://www.lighttpd.net/]) +AC_INIT([lighttpd],[1.4.73],[https://redmine.lighttpd.net/projects/lighttpd/boards/2],[lighttpd],[https://www.lighttpd.net/]) AC_CONFIG_SRCDIR([src/server.c]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/meson.build new/lighttpd-1.4.73/meson.build --- old/lighttpd-1.4.72/meson.build 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/meson.build 2023-10-31 03:35:56.000000000 +0100 @@ -1,7 +1,7 @@ project( 'lighttpd', 'c', - version: '1.4.72', + version: '1.4.73', license: 'BSD-3-Clause', default_options: ['c_std=c11'], meson_version: '>=0.47.0', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/src/configfile-glue.c new/lighttpd-1.4.73/src/configfile-glue.c --- old/lighttpd-1.4.72/src/configfile-glue.c 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/src/configfile-glue.c 2023-10-31 03:35:56.000000000 +0100 @@ -197,10 +197,6 @@ break; case T_CONFIG_SHORT: switch(du->type) { - case TYPE_INTEGER: - cpv->v.shrt = - (unsigned short)((const data_integer *)du)->value; - break; case TYPE_STRING: { /* If the value came from an environment variable, then it is * a data_string, although it may contain a number in ASCII @@ -218,10 +214,17 @@ } } log_error(srv->errh, __FILE__, __LINE__, - "got a string but expected a short: %s %s", cpk[i].k, v); + "got a string but expected a short integer: %s %s", cpk[i].k, v); rc = 0; continue; } + case TYPE_INTEGER: + cpv->v.shrt = + (unsigned short)((const data_integer *)du)->value; + if (((const data_integer *)du)->value >= 0 + && ((const data_integer *)du)->value <= 65535) + break; + __attribute_fallthrough__ default: log_error(srv->errh, __FILE__, __LINE__, "unexpected type for key: %s %d expected a short integer, " diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/src/configfile.c new/lighttpd-1.4.73/src/configfile.c --- old/lighttpd-1.4.72/src/configfile.c 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/src/configfile.c 2023-10-31 03:35:56.000000000 +0100 @@ -554,7 +554,8 @@ static int config_http_parseopts (server *srv, const array *a) { unsigned short int opts = srv->srvconf.http_url_normalize; - unsigned short int decode_2f = 1; + uint8_t decode_2f = 1; + uint8_t url_normalize = 1; int rc = 1; for (size_t i = 0; i < a->used; ++i) { const data_string * const ds = (const data_string *)a->data[i]; @@ -616,14 +617,15 @@ else { opts &= ~opt; if (opt == HTTP_PARSEOPT_URL_NORMALIZE) { - opts = 0; - break; + url_normalize = 0; } if (opt == HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE) { decode_2f = 0; } } } + if (!url_normalize) + opts = 0; if (opts != 0) { opts |= HTTP_PARSEOPT_URL_NORMALIZE; if ((opts & (HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE @@ -992,6 +994,7 @@ ,".webp", "image/webp" ,".avi", "video/x-msvideo" + ,".mkv", "video/x-matroska" ,".m4v", "video/mp4" ,".mp4", "video/mp4" ,".mpeg", "video/mpeg" @@ -1367,6 +1370,9 @@ config_feature_bool(srv, "server.metrics-high-precision", srv->srvconf.high_precision_timestamps); + /* disable h2proto if mod_h2 was not found during plugin load */ + p->defaults.h2proto = srv->srvconf.h2proto; + /* configure default server_tag if not set * (if configured to blank, unset server_tag)*/ if (!p->defaults.server_tag) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/src/h2.c new/lighttpd-1.4.73/src/h2.c --- old/lighttpd-1.4.72/src/h2.c 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/src/h2.c 2023-10-31 03:35:56.000000000 +0100 @@ -435,6 +435,22 @@ { h2con * const h2c = (h2con *)con->hx; + /* avoid sending REFUSED_STREAM if an existing stream is ready to be + * cleaned up, better handling edge case where stream concurrency limit + * has been reached and client sends RST_STREAM followed by HEADERS to + * cancel an existing stream and create a new, different stream. + * Note: this handles HTTP/2 rapid reset attack (CVE-2023-44487) + * slightly better than prior behavior by avoiding the minor overhead + * of responding with RST_STREAM REFUSED_STREAM */ + for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) { + const request_st * const r = h2c->r[i]; + if (r->state > CON_STATE_WRITE) + /* (CON_STATE_RESPONSE_END or CON_STATE_ERROR) + * request will be cleaned up shortly, releasing a slot; + * defer processing frame rather than sending REFUSED_STREAM */ + return -1; + } + if (h2c->sent_settings) { /*(see h2_recv_settings() comments)*/ /* client connected and immediately sent flurry of request streams * (h2c->sent_settings is non-zero if sent SETTINGS frame to @@ -443,13 +459,31 @@ * server Connection Preface, so a well-behaved client will * adjust after it sends its initial requests. * (e.g. h2load -n 100 -m 100 sends 100 requests upon connect) - * + */ + + /* Send GOAWAY if too many requests (> 100) sent prior to SETTINGS ackn + * (and if we reach here checking to refuse excess stream). + * (lighttpd currently sends SETTINGS once, following server preface) */ + if (h2id > 200) { + log_error(NULL, __FILE__, __LINE__, + "h2: %s too many refused requests before SETTINGS ackn", + con->request.dst_addr_buf->ptr); + h2_send_goaway_e(con, H2_E_ENHANCE_YOUR_CALM); + return 0; + } + + /* * Check if active streams have pending request body. If all active * streams have pending request body, then must refuse new stream as * progress might be blocked if active streams all wait for DATA. */ for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) { const request_st * const r = h2c->r[i]; if (r->reqbody_length == r->reqbody_queue.bytes_in) { + /* check that stream response will not be blocked waiting + * for stream WINDOW_UPDATE or connection WINDOW_UPDATE */ + request_st * const h2r = &con->request; + if (r->x.h2.swin <= 0 || h2r->x.h2.swin <= 0) continue; + /* no pending request body; at least this request may proceed, * though others waiting for request body may block until new * request streams become active if new request streams precede @@ -472,6 +506,30 @@ /* too many active streams; refuse new stream */ h2c->h2_cid = h2id; h2_send_rst_stream_id(h2id, con, H2_E_REFUSED_STREAM); + + /* mitigate request floods pipelining streams in excess of concurrency limit + * + * excess streams opened after SETTINGS_MAX_CONCURRENT_STREAMS 8 sent may + * indicate an attack, or may indicate an impatient and ill-behaved client + * (SETTINGS_MAX_CONCURRENT_STREAMS >= 100 recommended by RFC 9113) + * If client sends more than 100 requests before sending SETTINGS ackn, + * then lighttpd treats that as excessive (above). It could be accidental, + * but could be malicious since an attacker might intentionally omit sending + * SETTINGS ackn. Note: SETTINGS_MAX_CONCURRENT_STREAMS is not currently + * sent by lighttpd after SETTINGS following HTTP/2 server preface, so this + * stream concurrency limit does not change after connection initiation. + * Here, either SETTINGS ackn has been received, and still too many requests + * (more than concurrenty limit of 8) *or* fall through from above if active + * requests might block/timeout waiting for later frames). Well-behaved + * clients should not fall afoul of server SETTINGS_MAX_CONCURRENT_STREAMS*/ + if (++h2c->n_refused_stream > 16) { + log_error(NULL, __FILE__, __LINE__, + "h2: %s too many refused requests", + con->request.dst_addr_buf->ptr); + h2_send_goaway_e(con, H2_E_NO_ERROR); + /*(return 0 if sending H2_E_ENHANCE_YOUR_CALM instead)*/ + } + return 1; } @@ -537,6 +595,27 @@ /* XXX: ? add debug trace including error code from RST_STREAM ? */ r->state = CON_STATE_ERROR; r->x.h2.state = H2_STATE_CLOSED; + + /* attempt to detect HTTP/2 rapid reset attack (CVE-2023-44487) + * Send GOAWAY if 17 or more requests in recent batch of up to 32 + * requests have been cancelled by client sending RST_STREAM. + * Note: this can legitimately occur, but is less likely for RST_STREAM + * in < 2 secs in which request was sent, repeated 16 more times within + * the next 32 requests, w/ SETTINGS_MAX_CONCURRENT_STREAMS only 8. + * Still, send GOAWAY NO_ERROR instead of sending ENHANCE_YOUR_CALM. */ + if (!h2c->sent_goaway && r->start_hp.tv_sec+2 > log_epoch_secs) { + if ((++h2c->n_recv_rst_stream & 0xf) == 0) + h2c->n_recv_rst_stream |= 0xf; + uint8_t n_recv_rst_stream = + (h2c->n_recv_rst_stream >> 4) + (h2c->n_recv_rst_stream & 0xf); + if (n_recv_rst_stream > 16) { + log_error(NULL, __FILE__, __LINE__, + "h2: %s sent too many RST_STREAM too quickly", + con->request.dst_addr_buf->ptr); + h2_send_goaway_e(con, H2_E_NO_ERROR); + } + } + return; } /* unknown/inactive stream id @@ -1392,6 +1471,11 @@ * be optional, like in HTTP/1.1 */ request_st * const r = h2_get_stream_req(h2c, id); if (NULL == r) { + /* Note: sending GOAWAY here might be too strict. With the introduction + * of h2_discard_headers(), the GOAWAY can now safely be commented out + * if this causes any issue with legitimate use in the field due to + * lighttpd responding to a stream, closing and forgetting about the + * stream, and then receiving trailers from the client for the stream.*/ h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR); return NULL; } @@ -1413,15 +1497,42 @@ } +__attribute_cold__ +static void +h2_discard_headers_frame (struct lshpack_dec * const restrict decoder, const unsigned char **psrc, const unsigned char * const restrict endp, const request_st * const restrict r) +{ + /* HPACK decode and discard; stripped down from h2_parse_headers_frame(). + * If HEADERS frame is received, HEADERS frame must be HPACK-decoded to + * maintain HPACK decoder state consistency for the connection, unless + * GOAWAY has been sent and no new streams will be opened. Even then, + * if GOAWAY was sent with H2_E_NO_ERROR, there is still chance that + * trailers sent later on active streams will fail to be decoded unless + * all HEADERS frames are HPACK-decoded in the order received. */ + + /*(h2_init_con() resized h2r->tmp_buf to 64k; shared with r->tmp_buf)*/ + buffer * const tb = r->tmp_buf; + char * const tbptr = tb->ptr; + const lsxpack_strlen_t tbsz = (tb->size <= LSXPACK_MAX_STRLEN) + ? tb->size + : LSXPACK_MAX_STRLEN; + + lsxpack_header_t lsx; + while (*psrc < endp) { + memset(&lsx, 0, sizeof(lsxpack_header_t)); + lsx.buf = tbptr; + lsx.val_len = tbsz; + if (lshpack_dec_decode(decoder, psrc, endp, &lsx) != LSHPACK_OK) + break; /* HPACK decode failed; should probably send GOAWAY? */ + } +} + + static void h2_retire_stream (request_st *r, connection * const con); static void -h2_parse_headers_frame (request_st * const restrict r, const unsigned char *psrc, const uint32_t plen, const int trailers) +h2_parse_headers_frame (struct lshpack_dec * const restrict decoder, const unsigned char **psrc, const unsigned char * const endp, request_st * const restrict r, const int trailers) { - h2con * const h2c = (h2con *)r->con->hx; - struct lshpack_dec * const restrict decoder = &h2c->decoder; - const unsigned char * const endp = psrc + plen; http_header_parse_ctx hpctx; hpctx.hlen = 0; hpctx.pseudo = 1; /*(XXX: should be !trailers if handling trailers)*/ @@ -1442,11 +1553,11 @@ : LSXPACK_MAX_STRLEN; lsxpack_header_t lsx; - while (psrc < endp) { + while (*psrc < endp) { memset(&lsx, 0, sizeof(lsxpack_header_t)); lsx.buf = tbptr; lsx.val_len = tbsz; - rc = lshpack_dec_decode(decoder, &psrc, endp, &lsx); + rc = lshpack_dec_decode(decoder, psrc, endp, &lsx); if (0 == lsx.name_len) rc = LSHPACK_ERR_BAD_DATA; if (__builtin_expect( (rc == LSHPACK_OK), 1)) { @@ -1466,6 +1577,9 @@ if (__builtin_expect( (0 != http_status), 0)) { if (r->http_status == 0) /*might be set if processing trailers*/ r->http_status = http_status; + /* Note: hpctx.hlen is not adjusted for rest of headers, nor + * debug printing of headers if hpctx.log_request_header */ + h2_discard_headers_frame(decoder, psrc, endp, r); break; } } @@ -1495,19 +1609,22 @@ if (rc != LSHPACK_ERR_BAD_DATA) { /* LSHPACK_ERR_TOO_LARGE, LSHPACK_ERR_MORE_BUF */ err = H2_E_PROTOCOL_ERROR; + #if 0 + /* redundant: h2_send_goaway_e() sends RST_STREAM with + * H2_E_PROTOCOL_ERROR if GOAWAY not already sent. + * (If GOAWAY were sent with higher id, we would want + * to send RST_STREAM here, but that is not the case) */ h2_send_rst_stream(r, r->con, err); + #endif } - if (!h2c->sent_goaway && !hpctx.trailers) - h2c->h2_cid = r->x.h2.id; - h2_send_goaway_e(r->con, err); if (!hpctx.trailers) { - h2_retire_stream(r, r->con); + h2con * const h2c = (h2con *)r->con->hx; + if (!h2c->sent_goaway) + h2c->h2_cid = r->x.h2.id; + h2_send_goaway_e(r->con, err); return; } - else { - r->state = CON_STATE_ERROR; - r->x.h2.state = H2_STATE_CLOSED; - } + h2_send_goaway_e(r->con, err); break; } } @@ -1550,6 +1667,41 @@ } +__attribute_cold__ +static int +h2_discard_headers (struct lshpack_dec * const restrict decoder, const unsigned char **psrc, const unsigned char * const restrict endp, const request_st * const restrict r, h2con * const h2c) +{ + /* If GOAWAY was sent with an error, return quickly without decoding; + * choose *to not keep* HPACK decoder state in sync, since + * h2_send_rst_stream_state() set r->state = CON_STATE_ERROR and + * r->x.h2.state = H2_STATE_CLOSED for previously active streams. */ + if (h2c->sent_goaway > 0) return 0; + + /* Send error if too many discarded HEADERS frames. + * (similar to h2_send_refused_stream()) + * Note: this could legitimately be triggered by a client sending trailers + * after lighttpd has responded to and closed a stream, so no longer tracked + * by lighttpd, but that is not expected to be a common scenario. (Also, if + * this were permitted without limit, it could be abused to bypass limit.)*/ + if (++h2c->n_discarded_headers > 32) { + connection * const con = r->con; + log_error(NULL, __FILE__, __LINE__, + "h2: %s too many discarded requests", + con->request.dst_addr_buf->ptr); + h2_send_goaway_e(con, H2_E_ENHANCE_YOUR_CALM); + } + + h2_discard_headers_frame(decoder, psrc, endp, r); + + /* return 1 to continue processing HTTP/2 frames + * Note: if returning 0 to defer processing additional frames and + * yield to other connections, must also joblist_append(con) unless + * all h2c->r slots are full and next frame is HEADERS (which could + * be passed in as a flag depending on the calling location) */ + return 1; +} + + __attribute_noinline__ static int h2_recv_headers (connection * const con, uint8_t * const s, uint32_t flen) @@ -1561,7 +1713,6 @@ * might be made to the code in the future. */ __coverity_tainted_data_sink__(s); #endif - request_st *r = NULL; h2con * const h2c = (h2con *)con->hx; const uint32_t id = h2_u31(s+5); #if 0 /*(included in (!(id & 1)) below)*/ @@ -1575,53 +1726,6 @@ return 0; } - request_st * const h2r = &con->request; - int trailers = 0; - - if (id > h2c->h2_cid) { - if (h2c->rused == sizeof(h2c->r)/sizeof(*h2c->r)) - return h2_send_refused_stream(id, con); - /* Note: MUST process HPACK decode even if already sent GOAWAY. - * This is necessary since there may be active streams not in - * H2_STATE_HALF_CLOSED_REMOTE, e.g. H2_STATE_OPEN, still possibly - * receiving DATA and, more relevantly, still might receive HEADERS - * frame with trailers, for which the decoder state is required. - * XXX: future might try to reduce other processing done if sent - * GOAWAY, e.g. might avoid allocating (request_st *r) */ - r = h2_init_stream(h2r, con); - r->x.h2.id = id; - if (s[4] & H2_FLAG_END_STREAM) { - r->x.h2.state = H2_STATE_HALF_CLOSED_REMOTE; - r->state = CON_STATE_HANDLE_REQUEST; - r->reqbody_length = 0; - } - else { - r->x.h2.state = H2_STATE_OPEN; - r->state = CON_STATE_READ_POST; - r->reqbody_length = -1; - } - /* Note: timestamps here are updated only after receipt of entire header - * (HEADERS frame might have been sent in multiple packets - * and CONTINUATION frames may have been sent in multiple packets) - * (affects high precision timestamp, if enabled) - * (large sets of headers are not typical, and even when they do - * occur, they will typically be sent within the same second) - * (future: might keep high precision timestamp in h2con when first - * packet of HEADERS or PUSH_PROMISE is received, and clear that - * timestamp when frame + CONTINUATION(s) are complete (so that - * re-read of initial frame does not overwrite the timestamp)) - */ - r->start_hp.tv_sec = log_epoch_secs; - if (r->conf.high_precision_timestamps) - log_clock_gettime_realtime(&r->start_hp); - } - else { - r = h2_recv_trailers_r(con, h2c, id, s[4]); /* (cold code path) */ - if (NULL == r) - return (h2c->sent_goaway > 0) ? 0 : 1; - trailers = 1; - } - const unsigned char *psrc = s + 9; uint32_t alen = flen; if (s[4] & H2_FLAG_PADDED) { @@ -1631,23 +1735,26 @@ /* Padding that exceeds the size remaining for the header block * fragment MUST be treated as a PROTOCOL_ERROR. */ h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR); - if (!trailers) - h2_retire_stream(r, con); - else { - r->state = CON_STATE_ERROR; - r->x.h2.state = H2_STATE_CLOSED; - } return 0; } alen -= (1 + pad); /*(alen is adjusted for PRIORITY below)*/ } if (s[4] & H2_FLAG_PRIORITY) { - /* XXX: TODO: handle PRIORITY (prio fields start at *psrc) */ - if (alen < 5 || (/*prio = */h2_u32(psrc)) == id) { - h2_send_rst_stream(r, con, H2_E_PROTOCOL_ERROR); - if (!trailers) - h2_retire_stream(r, con); - return 1; + if (alen < 5) { + h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR); + return 0; + } + if (((/*prio = */h2_u32(psrc)) == id) & (id > h2c->h2_cid)) { + /*(ignore dep if HEADERS frame is trailers (id <= h2c->h2_cid)*/ + /* https://www.rfc-editor.org/rfc/rfc7540#section-5.3.1 + * A stream cannot depend on itself. An endpoint MUST treat this + * as a stream error (Section 5.4.2) of type PROTOCOL_ERROR.*/ + h2_send_rst_stream_id(id, con, H2_E_PROTOCOL_ERROR); + /* PRIORITY is deprecated in RFC9113. As this mistake is now more + * likely an attack, follow with goaway error since HEADERS frame + * is not HPACK decoded here to maintain HPACK decoder state. */ + h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR); + return 0; } #if 0 uint32_t exclusive_dependency = (psrc[0] & 0x80) ? 1 : 0; @@ -1661,29 +1768,85 @@ alen -= 5; } - h2_parse_headers_frame(r, psrc, alen, trailers); - - if (__builtin_expect( (trailers), 0)) + if (id <= h2c->h2_cid) { /* (trailers; cold code path) */ + request_st * const r = h2_recv_trailers_r(con, h2c, id, s[4]); + if (NULL == r) + return h2_discard_headers(&h2c->decoder, &psrc, psrc+alen, + &con->request, h2c); + h2_parse_headers_frame(&h2c->decoder,&psrc,psrc+alen,r,1);/*(trailers)*/ return 1; + } + + /* Note: MUST process HPACK decode even if already sent GOAWAY. + * This is necessary since there may be active streams not in + * H2_STATE_HALF_CLOSED_REMOTE, e.g. H2_STATE_OPEN, still possibly + * receiving DATA and, more relevantly, still might receive HEADERS + * frame with trailers, for which the decoder state may be required. */ + + if (h2c->sent_goaway) + return h2_discard_headers(&h2c->decoder, &psrc, psrc+alen, + &con->request, h2c); #if 0 /*(handled in h2_parse_frames() as a connection error)*/ - /* not handled here: - * r is invalid if h2_parse_headers_frame() HPACK decode error */ if (s[3] == H2_FTYPE_PUSH_PROMISE) { - /* Had to process HPACK to keep HPACK tables sync'd with peer but now - * discard the request if PUSH_PROMISE, since not expected, as this code - * is running as a server, not as a client. - * XXX: future might try to reduce other processing done if - * discarding, e.g. might avoid allocating (request_st *r) */ + /* discard the request if PUSH_PROMISE, since not expected, as this code + * is running as a server, not as a client. */ + /* note: h2_parse_headers_frame() sets h2c->h2_cid on HPACK decode error + * and would need to be changed for code to be shared by PUSH_PROMISE */ /* rant: PUSH_PROMISE could have been a flag on HEADERS frame * instead of an independent frame type */ - r->http_status = 0; - h2_retire_stream(r, con); + h2c->h2_sid = id; + return h2_discard_headers(&h2c->decoder, &psrc, psrc+alen, + &con->request, h2c); } #endif + /* new stream */ + + if (h2c->rused == sizeof(h2c->r)/sizeof(*h2c->r)) + return h2_send_refused_stream(id, con) == -1 + ? -1 + : h2_discard_headers(&h2c->decoder, &psrc, psrc+alen, + &con->request, h2c); + + request_st * const h2r = &con->request; + request_st * const r = h2_init_stream(h2r, con); + r->x.h2.id = id; + if (s[4] & H2_FLAG_END_STREAM) { + r->x.h2.state = H2_STATE_HALF_CLOSED_REMOTE; + r->state = CON_STATE_HANDLE_REQUEST; + r->reqbody_length = 0; + } + else { + r->x.h2.state = H2_STATE_OPEN; + r->state = CON_STATE_READ_POST; + r->reqbody_length = -1; + } + /* Note: timestamps here are updated only after receipt of entire header + * (HEADERS frame might have been sent in multiple packets + * and CONTINUATION frames may have been sent in multiple packets) + * (affects high precision timestamp, if enabled) + * (large sets of headers are not typical, and even when they do + * occur, they will typically be sent within the same second) + * (future: might keep high precision timestamp in h2con when first + * packet of HEADERS or PUSH_PROMISE is received, and clear that + * timestamp when frame + CONTINUATION(s) are complete (so that + * re-read of initial frame does not overwrite the timestamp)) + */ + r->start_hp.tv_sec = log_epoch_secs; + if (r->conf.high_precision_timestamps) + log_clock_gettime_realtime(&r->start_hp); + + h2_parse_headers_frame(&h2c->decoder, &psrc, psrc+alen, r, 0); /*(headers)*/ + if (!h2c->sent_goaway) { h2c->h2_cid = id; + + /* counter to detect HTTP/2 rapid reset attack (CVE-2023-44487) + * HTTP/2 client ids are odds, so use mask 0x1f + * in order to reset lower counter every 16 requests */ + if ((id & 0x1f) == 0x1) h2c->n_recv_rst_stream <<= 4; + /*(lighttpd.conf config conditions not yet applied to request, * but do not increase window size if BUFMIN set in global config)*/ if (r->reqbody_length /*(see h2_init_con() for session window)*/ @@ -1719,11 +1882,9 @@ if (h2c->rused-1) /*(true if more than one active stream)*/ h2_apply_priority_update(h2c, r, h2c->rused-1); } - else if (h2c->h2_cid < id) { + else { /* Had to process HPACK to keep HPACK tables sync'd with peer - * but now discard the request if id is after id sent in GOAWAY. - * XXX: future might try to reduce other processing done if - * discarding, e.g. might avoid allocating (request_st *r) */ + * but now discard the request */ r->http_status = 0; h2_retire_stream(r, con); } @@ -1745,6 +1906,11 @@ * should accept the larger frame size until SETTINGS is ACK'd) */ const uint32_t fsize = h2c->s_max_frame_size; for (off_t cqlen; (cqlen = chunkqueue_length(cq)) >= 9; ) { + + /* defer parsing additional frames if large output queue pending write*/ + if (__builtin_expect( (chunkqueue_length(con->write_queue) > 65536), 0)) + return 0; + chunk *c = cq->first; /*assert(c->type == MEM_CHUNK);*/ /* copy data if frame header crosses chunk boundary @@ -3308,8 +3474,19 @@ request_st * const h2r = &con->request; if (h2r->state == CON_STATE_WRITE) { /* write HTTP/2 frames to socket */ - if (!chunkqueue_is_empty(con->write_queue)) + if (!chunkqueue_is_empty(con->write_queue)) { connection_handle_write(h2r, con); + /* check if might need to resched to process more frames + * (could be more precise duplicating parts of h2_want_read(), + * though prefer to check here when write_queue has been emptied) + * need to resched if still CON_STATE_WRITE, write_queue empty, + * full frame pending, and frame is not HEADERS or h2c->r not full, + * which might happen if parsing frames was deferred if write_queue + * grew too large generating HTTP/2 replies to various frame types*/ + if (chunkqueue_is_empty(con->write_queue) + && !chunkqueue_is_empty(con->read_queue)) + resched |= 2; + } if (chunkqueue_is_empty(con->write_queue) && 0 == h2c->rused && h2c->sent_goaway) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/src/h2.h new/lighttpd-1.4.73/src/h2.h --- old/lighttpd-1.4.72/src/h2.h 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/src/h2.h 2023-10-31 03:35:56.000000000 +0100 @@ -88,6 +88,9 @@ struct lshpack_dec decoder; struct lshpack_enc encoder; unix_time64_t half_closed_ts; + uint8_t n_refused_stream; + uint8_t n_discarded_headers; + uint8_t n_recv_rst_stream; }; typedef struct h2con h2con; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/src/mod_mbedtls.c new/lighttpd-1.4.73/src/mod_mbedtls.c --- old/lighttpd-1.4.72/src/mod_mbedtls.c 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/src/mod_mbedtls.c 2023-10-31 03:35:56.000000000 +0100 @@ -62,11 +62,15 @@ #define MBEDTLS_ALLOW_PRIVATE_ACCESS #endif #endif +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include <mbedtls/psa_util.h> +#else #include <mbedtls/ctr_drbg.h> +#include <mbedtls/entropy.h> +#endif #include <mbedtls/debug.h> #include <mbedtls/dhm.h> #include <mbedtls/error.h> -#include <mbedtls/entropy.h> #include <mbedtls/oid.h> #include <mbedtls/pem.h> #include <mbedtls/ssl.h> @@ -168,10 +172,12 @@ plugin_ssl_ctx *ssl_ctxs; plugin_config defaults; server *srv; + #if !defined(MBEDTLS_USE_PSA_CRYPTO) /* NIST counter-mode deterministic random byte generator */ mbedtls_ctr_drbg_context ctr_drbg; /* entropy collection and state management */ mbedtls_entropy_context entropy; + #endif #if defined(MBEDTLS_SSL_SESSION_TICKETS) mbedtls_ssl_ticket_context ticket_ctx; const char *ssl_stek_file; @@ -407,6 +413,14 @@ if (ssl_is_init) return 1; ssl_is_init = 1; + #if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_status_t ps = psa_crypto_init(); + if (ps != PSA_SUCCESS) { + log_error(srv->errh, __FILE__, __LINE__, + "MTLS: %s: (-0x%04x)", "psa_crypto_init()", ps); + return 0; + } + #else plugin_data * const p = plugin_data_singleton; mbedtls_ctr_drbg_init(&p->ctr_drbg); /* init empty NSIT random num gen */ mbedtls_entropy_init(&p->entropy); /* init empty entropy collection struct @@ -422,6 +436,7 @@ "Init of random number generator failed"); return 0; } + #endif local_send_buffer = ck_malloc(LOCAL_SEND_BUFSIZE); return 1; @@ -438,8 +453,12 @@ #endif plugin_data * const p = plugin_data_singleton; + #if defined(MBEDTLS_USE_PSA_CRYPTO) + mbedtls_psa_crypto_free(); + #else mbedtls_ctr_drbg_free(&p->ctr_drbg); mbedtls_entropy_free(&p->entropy); + #endif #if defined(MBEDTLS_SSL_SESSION_TICKETS) mbedtls_ssl_ticket_free(&p->ticket_ctx); #endif @@ -977,11 +996,18 @@ if (NULL == data) return rc; #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.00.0 */ + #if defined(MBEDTLS_USE_PSA_CRYPTO) + rc = mbedtls_pk_parse_key(ctx, (unsigned char *)data, (size_t)dlen+1, + (const unsigned char *)pwd, + pwd ? strlen(pwd) : 0, + mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE); + #else plugin_data * const p = plugin_data_singleton; rc = mbedtls_pk_parse_key(ctx, (unsigned char *)data, (size_t)dlen+1, (const unsigned char *)pwd, pwd ? strlen(pwd) : 0, mbedtls_ctr_drbg_random, &p->ctr_drbg); + #endif #else rc = mbedtls_pk_parse_key(ctx, (unsigned char *)data, (size_t)dlen+1, (const unsigned char *)pwd, @@ -1024,9 +1050,14 @@ } #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.00.0 */ + #if defined(MBEDTLS_USE_PSA_CRYPTO) + rc = mbedtls_pk_check_pair(&ssl_pemfile_x509.pk, &ssl_pemfile_pkey, + mbedtls_psa_get_random,MBEDTLS_PSA_RANDOM_STATE); + #else plugin_data * const p = plugin_data_singleton; rc = mbedtls_pk_check_pair(&ssl_pemfile_x509.pk, &ssl_pemfile_pkey, mbedtls_ctr_drbg_random, &p->ctr_drbg); + #endif #else rc = mbedtls_pk_check_pair(&ssl_pemfile_x509.pk, &ssl_pemfile_pkey); #endif @@ -1437,7 +1468,12 @@ mbedtls_ssl_config_init(s->ssl_ctx); /* set the RNG in the ssl config context, using the default random func */ + #if defined(MBEDTLS_USE_PSA_CRYPTO) + mbedtls_ssl_conf_rng(s->ssl_ctx, + mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE); + #else mbedtls_ssl_conf_rng(s->ssl_ctx, mbedtls_ctr_drbg_random, &p->ctr_drbg); + #endif /* mbedtls defaults to disable client renegotiation * mbedtls defaults to no record compression unless mbedtls is built @@ -1527,9 +1563,17 @@ #if defined(MBEDTLS_SSL_SESSION_TICKETS) if (s->ssl_session_ticket /*(.ticket_lifetime is private)*/ && !*(unsigned char *)&p->ticket_ctx) { /*init once*/ + #if defined(MBEDTLS_USE_PSA_CRYPTO) + rc = mbedtls_ssl_ticket_setup(&p->ticket_ctx, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE, + MBEDTLS_CIPHER_AES_256_GCM, + 43200); /* ticket timeout: 12 hours */ + #else rc = mbedtls_ssl_ticket_setup(&p->ticket_ctx, mbedtls_ctr_drbg_random, &p->ctr_drbg, MBEDTLS_CIPHER_AES_256_GCM, 43200); /* ticket timeout: 12 hours */ + #endif if (0 != rc) { elog(srv->errh,__FILE__,__LINE__,rc,"mbedtls_ssl_ticket_setup()"); return -1; @@ -1993,6 +2037,9 @@ break; /* try again later */ case MBEDTLS_ERR_SSL_WANT_WRITE: con->is_writable = -1; + #if MBEDTLS_VERSION_NUMBER >= 0x03000000 /* mbedtls 3.00.0 */ + hctx->pending_write = wr_len; /* partial write; save attempted wr_len */ + #endif break; /* try again later */ case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS: case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS: @@ -2009,8 +2056,8 @@ #if MBEDTLS_VERSION_NUMBER < 0x03000000 /* mbedtls 3.00.0 */ if (0 != hctx->ssl.out_left) /* partial write; save attempted wr_len */ - #endif hctx->pending_write = wr_len; + #endif return 0; /* try again later */ } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/src/mod_openssl.c new/lighttpd-1.4.73/src/mod_openssl.c --- old/lighttpd-1.4.72/src/mod_openssl.c 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/src/mod_openssl.c 2023-10-31 03:35:56.000000000 +0100 @@ -82,6 +82,7 @@ #include <openssl/ocsp.h> #endif #ifdef BORINGSSL_API_VERSION +#include <openssl/hmac.h> /* BoringSSL purports to have some OCSP support */ #undef OPENSSL_NO_OCSP #endif @@ -2191,7 +2192,8 @@ #if defined(BORINGSSL_API_VERSION) \ - || defined(LIBRESSL_VERSION_NUMBER) + || defined(LIBRESSL_VERSION_NUMBER) \ + || OPENSSL_VERSION_NUMBER < 0x10100000L static int mod_openssl_ssl_conf_curves(server *srv, plugin_config_socket *s, const buffer *ssl_ec_curve) { @@ -2254,6 +2256,7 @@ return 1; } #endif /* BORINGSSL_API_VERSION || LIBRESSL_VERSION_NUMBER */ + /* || OPENSSL_VERSION_NUMBER < 0x10100000L */ static int @@ -2365,6 +2368,11 @@ if (!mod_openssl_ssl_conf_dhparameters(srv, s, NULL)) return -1; + #if OPENSSL_VERSION_NUMBER < 0x10100000L + if (!mod_openssl_ssl_conf_curves(srv, s, NULL)) + return -1; + #endif + #ifdef TLSEXT_TYPE_session_ticket #if OPENSSL_VERSION_NUMBER < 0x30000000L SSL_CTX_set_tlsext_ticket_key_cb(s->ssl_ctx, ssl_tlsext_ticket_key_cb); @@ -2996,11 +3004,12 @@ mod_openssl_merge_config(&p->defaults, cpv); } - #if OPENSSL_VERSION_NUMBER < 0x10101000L \ + #if OPENSSL_VERSION_NUMBER < 0x30000000L \ + && !defined(BORINGSSL_API_VERSION) \ && !defined(LIBRESSL_VERSION_NUMBER) log_error(srv->errh, __FILE__, __LINE__, "SSL:" "openssl library version is outdated and has reached end-of-life. " - "As of 1 Jan 2020, only openssl 1.1.1 and later continue to receive " + "As of 11 Sep 2023, only openssl 3.0.0 and later continue to receive " "security patches from openssl.org"); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/src/mod_wstunnel.c new/lighttpd-1.4.73/src/mod_wstunnel.c --- old/lighttpd-1.4.72/src/mod_wstunnel.c 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/src/mod_wstunnel.c 2023-10-31 03:35:56.000000000 +0100 @@ -822,7 +822,7 @@ buffer_append_base64_encode(value, sha_digest, SHA_DIGEST_LENGTH, BASE64_STANDARD); } - if (hctx->frame.type == MOD_WEBSOCKET_FRAME_TYPE_BIN) + if (1 == hctx->subproto) http_header_response_set(r, HTTP_HEADER_OTHER, CONST_STR_LEN("Sec-WebSocket-Protocol"), CONST_STR_LEN("binary")); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/src/plugin.c new/lighttpd-1.4.73/src/plugin.c --- old/lighttpd-1.4.72/src/plugin.c 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/src/plugin.c 2023-10-31 03:35:56.000000000 +0100 @@ -131,13 +131,15 @@ } } if (!load_functions[j].name) { - log_error(srv->errh, __FILE__, __LINE__, "%s plugin not found", module); if (srv->srvconf.compat_module_load) { if (buffer_eq_slen(&ds->value, CONST_STR_LEN("mod_deflate"))) continue; } - if (buffer_eq_slen(&ds->value, CONST_STR_LEN("mod_h2"))) + if (buffer_eq_slen(&ds->value, CONST_STR_LEN("mod_h2"))) { + srv->srvconf.h2proto = 0; continue; + } + log_error(srv->errh, __FILE__, __LINE__, "%s plugin not found", module); return -1; } } @@ -180,14 +182,16 @@ #ifdef _WIN32 buffer_append_string_len(tb, CONST_STR_LEN(".dll")); if (NULL == (lib = LoadLibrary(tb->ptr))) { - log_perror(srv->errh, __FILE__, __LINE__, - "LoadLibrary() %s", tb->ptr); if (srv->srvconf.compat_module_load) { if (buffer_eq_slen(module, CONST_STR_LEN("mod_deflate"))) continue; } - if (buffer_eq_slen(module, CONST_STR_LEN("mod_h2"))) + if (buffer_eq_slen(module, CONST_STR_LEN("mod_h2"))) { + srv->srvconf.h2proto = 0; continue; + } + log_perror(srv->errh, __FILE__, __LINE__, + "LoadLibrary() %s", tb->ptr); return -1; } buffer_copy_buffer(tb, module); @@ -206,14 +210,16 @@ buffer_append_string_len(tb, CONST_STR_LEN(".so")); #endif if (NULL == (lib = dlopen(tb->ptr, RTLD_NOW|RTLD_GLOBAL))) { - log_error(srv->errh, __FILE__, __LINE__, - "dlopen() failed for: %s %s", tb->ptr, dlerror()); if (srv->srvconf.compat_module_load) { if (buffer_eq_slen(module, CONST_STR_LEN("mod_deflate"))) continue; } - if (buffer_eq_slen(module, CONST_STR_LEN("mod_h2"))) + if (buffer_eq_slen(module, CONST_STR_LEN("mod_h2"))) { + srv->srvconf.h2proto = 0; continue; + } + log_error(srv->errh, __FILE__, __LINE__, + "dlopen() failed for: %s %s", tb->ptr, dlerror()); return -1; } buffer_clear(tb); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/src/rand.c new/lighttpd-1.4.73/src/rand.c --- old/lighttpd-1.4.72/src/rand.c 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/src/rand.c 2023-10-31 03:35:56.000000000 +0100 @@ -41,9 +41,13 @@ #undef USE_OPENSSL_CRYPTO #undef USE_GNUTLS_CRYPTO #undef USE_NSS_CRYPTO +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include <mbedtls/psa_util.h> +#else #include <mbedtls/ctr_drbg.h> #include <mbedtls/entropy.h> #endif +#endif #ifdef USE_WOLFSSL_CRYPTO #undef USE_OPENSSL_CRYPTO #undef USE_GNUTLS_CRYPTO @@ -219,6 +223,7 @@ static int li_rand_inited; static unsigned short xsubi[3]; #ifdef USE_MBEDTLS_CRYPTO +#if !defined(MBEDTLS_USE_PSA_CRYPTO) #ifdef MBEDTLS_ENTROPY_C static mbedtls_entropy_context entropy; #ifdef MBEDTLS_CTR_DRBG_C @@ -226,6 +231,7 @@ #endif #endif #endif +#endif #ifdef USE_WOLFSSL_CRYPTO static WC_RNG wolf_globalRNG; #endif @@ -334,6 +340,11 @@ RAND_seed(xsubi, (int)sizeof(xsubi)); #endif #ifdef USE_MBEDTLS_CRYPTO + #if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_status_t ps = psa_crypto_init(); + if (ps != PSA_SUCCESS) + ck_bt_abort(__FILE__, __LINE__, "psa_crypto_init() failed"); + #else #ifdef MBEDTLS_ENTROPY_C mbedtls_entropy_init(&entropy); #ifdef MBEDTLS_CTR_DRBG_C @@ -346,6 +357,7 @@ #endif #endif #endif + #endif #ifdef USE_NSS_CRYPTO if (!NSS_IsInitialized() && NSS_NoDB_Init(NULL) < 0) ck_bt_abort(__FILE__, __LINE__, "aborted"); @@ -382,13 +394,28 @@ #endif #ifdef USE_MBEDTLS_CRYPTO if (li_rand_inited) { + #if defined(MBEDTLS_USE_PSA_CRYPTO) + mbedtls_psa_crypto_free(); + #else #ifdef MBEDTLS_ENTROPY_C #ifdef MBEDTLS_CTR_DRBG_C mbedtls_ctr_drbg_free(&ctr_drbg); #endif mbedtls_entropy_free(&entropy); #endif + #endif + } + #if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_CRYPTO_DRIVER_TEST) + else { + /*(kludge to call psa_crypto_init() for sys-crypto-md.h from server.c)*/ + /*(However, we prefer to defer RNG initialization, and the builtin hash + * functions do not require psa_crypto_init(), so skip unless hash func + * might use an accelerated crypto driver)*/ + psa_status_t ps = psa_crypto_init(); + if (ps != PSA_SUCCESS) + ck_bt_abort(__FILE__, __LINE__, "psa_crypto_init() failed"); } + #endif #endif if (li_rand_inited) li_rand_init(); } @@ -420,12 +447,19 @@ if (i) return i; /*(cond to avoid compiler warning for code after return)*/ #endif #ifdef USE_MBEDTLS_CRYPTO + #if defined(MBEDTLS_USE_PSA_CRYPTO) + int i; + if (0 == mbedtls_psa_get_random(MBEDTLS_PSA_RANDOM_STATE, + (unsigned char *)&i, sizeof(i))) + return i; + #else #ifdef MBEDTLS_CTR_DRBG_C int i; if (0 == mbedtls_ctr_drbg_random(&ctr_drbg, (unsigned char *)&i, sizeof(i))) return i; #endif #endif + #endif #ifdef USE_NSS_CRYPTO int i; if (SECSuccess == PK11_GenerateRandom((unsigned char *)&i, sizeof(i))) @@ -466,10 +500,14 @@ if (SECSuccess == PK11_GenerateRandom(buf, num)) return; #endif #ifdef USE_MBEDTLS_CRYPTO + #if defined(MBEDTLS_USE_PSA_CRYPTO) + if (0 == psa_generate_random(buf, (size_t)num)) return; + #else #ifdef MBEDTLS_CTR_DRBG_C if (0 == mbedtls_ctr_drbg_random(&ctr_drbg, buf, (size_t)num)) return; #endif #endif + #endif #ifdef USE_WOLFSSL_CRYPTO /* RAND_pseudo_bytes() in WolfSSL is equivalent to RAND_bytes() */ if (0 == wc_RNG_GenerateBlock(&wolf_globalRNG, (byte *)buf, (word32)num)) @@ -479,6 +517,7 @@ buf[i] = li_rand_pseudo() & 0xFF; } +#if 0 /*(unused)*/ int li_rand_bytes (unsigned char *buf, int num) { #ifdef USE_GNUTLS_CRYPTO /* should use GNUTLS_RND_KEY for long-term keys */ @@ -516,6 +555,10 @@ #endif #ifdef USE_MBEDTLS_CRYPTO #ifdef MBEDTLS_ENTROPY_C + #if defined(MBEDTLS_USE_PSA_CRYPTO) + if (0 == psa_generate_random(buf, (size_t)num)) + return 1; + #else /*(each call <= MBEDTLS_ENTROPY_BLOCK_SIZE; could implement loop here)*/ if (num <= MBEDTLS_ENTROPY_BLOCK_SIZE && 0 == mbedtls_entropy_func(&entropy, buf, (size_t)num)) { @@ -523,6 +566,7 @@ } #endif #endif + #endif if (1 == li_rand_device_bytes(buf, num)) { return 1; } @@ -533,6 +577,7 @@ return 0; } } +#endif void li_rand_cleanup (void) { @@ -549,6 +594,9 @@ #endif #endif #ifdef USE_MBEDTLS_CRYPTO + #if defined(MBEDTLS_USE_PSA_CRYPTO) + mbedtls_psa_crypto_free(); + #else #ifdef MBEDTLS_ENTROPY_C #ifdef MBEDTLS_CTR_DRBG_C mbedtls_ctr_drbg_free(&ctr_drbg); @@ -556,5 +604,7 @@ mbedtls_entropy_free(&entropy); #endif #endif + li_rand_inited = 0; + #endif /* USE_MBEDTLS_CRYPTO */ ck_memzero(xsubi, sizeof(xsubi)); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lighttpd-1.4.72/src/sys-crypto-md.h new/lighttpd-1.4.73/src/sys-crypto-md.h --- old/lighttpd-1.4.72/src/sys-crypto-md.h 2023-10-07 02:10:38.000000000 +0200 +++ new/lighttpd-1.4.73/src/sys-crypto-md.h 2023-10-31 03:35:56.000000000 +0100 @@ -153,6 +153,102 @@ #include <mbedtls/version.h> /*#include <mbedtls/compat-2.x.h>*//*(func renames ifdef'd below)*/ +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "psa/crypto.h" +/* Note: psa_crypto_init() MUST be called once before use + * (see lighttpd src/rand.c for overload where this is done in lighttpd) */ +#include <string.h> /* memset() */ + +#ifdef PSA_WANT_ALG_MD5 +#define USE_LIB_CRYPTO_MD5 +typedef psa_hash_operation_t MD5_CTX; +static inline int +MD5_Init(MD5_CTX *ctx) +{ + memset(ctx, 0, sizeof(MD5_CTX)); + return (PSA_SUCCESS == psa_hash_setup(ctx, PSA_ALG_MD5)); +} +static inline int +MD5_Final(unsigned char *digest, MD5_CTX *ctx) +{ + size_t n; /* PSA_HASH_LENGTH(PSA_ALG_MD5) == 16 */ + return (PSA_SUCCESS == psa_hash_finish(ctx, digest, 16, &n)); +} +static inline int +MD5_Update(MD5_CTX *ctx, const void *data, size_t length) +{ + return (PSA_SUCCESS == psa_hash_update(ctx, data, length)); +} +#endif + +#ifdef PSA_WANT_ALG_SHA_1 +#define USE_LIB_CRYPTO_SHA1 +typedef psa_hash_operation_t SHA_CTX; +static inline int +SHA1_Init(SHA_CTX *ctx) +{ + memset(ctx, 0, sizeof(SHA_CTX)); + return (PSA_SUCCESS == psa_hash_setup(ctx, PSA_ALG_SHA_1)); +} +static inline int +SHA1_Final(unsigned char *digest, SHA_CTX *ctx) +{ + size_t n; /* PSA_HASH_LENGTH(PSA_ALG_SHA_1) == 20 */ + return (PSA_SUCCESS == psa_hash_finish(ctx, digest, 20, &n)); +} +static inline int +SHA1_Update(SHA_CTX *ctx, const void *data, size_t length) +{ + return (PSA_SUCCESS == psa_hash_update(ctx, data, length)); +} +#endif + +#ifdef PSA_WANT_ALG_SHA_256 +#define USE_LIB_CRYPTO_SHA256 +typedef psa_hash_operation_t SHA256_CTX; +static inline int +SHA256_Init(SHA256_CTX *ctx) +{ + memset(ctx, 0, sizeof(SHA256_CTX)); + return (PSA_SUCCESS == psa_hash_setup(ctx, PSA_ALG_SHA_256)); +} +static inline int +SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) +{ + size_t n; /* PSA_HASH_LENGTH(PSA_ALG_SHA_256) == 32 */ + return (PSA_SUCCESS == psa_hash_finish(ctx, digest, 32, &n)); +} +static inline int +SHA256_Update(SHA256_CTX *ctx, const void *data, size_t length) +{ + return (PSA_SUCCESS == psa_hash_update(ctx, data, length)); +} +#endif + +#ifdef PSA_WANT_ALG_SHA_512 +#define USE_LIB_CRYPTO_SHA512 +typedef psa_hash_operation_t SHA512_CTX; +static inline int +SHA512_Init(SHA512_CTX *ctx) +{ + memset(ctx, 0, sizeof(SHA512_CTX)); + return (PSA_SUCCESS == psa_hash_setup(ctx, PSA_ALG_SHA_512)); +} +static inline int +SHA512_Final(unsigned char *digest, SHA512_CTX *ctx) +{ + size_t n; /* PSA_HASH_LENGTH(PSA_ALG_SHA_512) == 64 */ + return (PSA_SUCCESS == psa_hash_finish(ctx, digest, 64, &n)); +} +static inline int +SHA512_Update(SHA512_CTX *ctx, const void *data, size_t length) +{ + return (PSA_SUCCESS == psa_hash_update(ctx, data, length)); +} +#endif + +#else /* !MBEDTLS_USE_PSA_CRYPTO */ + #ifdef MBEDTLS_MD4_C #define USE_LIB_CRYPTO_MD4 #include <mbedtls/md4.h> @@ -321,6 +417,8 @@ } #endif +#endif /* !MBEDTLS_USE_PSA_CRYPTO */ + #elif defined(USE_WOLFSSL_CRYPTO) /* WolfSSL compatibility API for OpenSSL unnecessarily bounces through an extra @@ -912,8 +1010,34 @@ /* message digest wrappers operating on single ptr, and on const_iovec */ +#if defined(USE_MBEDTLS_CRYPTO) +#if defined(MBEDTLS_USE_PSA_CRYPTO) + +#define li_md_once(algo, alg) \ + static inline int \ + algo##_once (unsigned char * const digest, \ + const void * const data, const size_t n) \ + { \ + size_t x; \ + return PSA_SUCCESS \ + == psa_hash_compute(alg,data,n,digest,PSA_HASH_LENGTH(alg),&x); \ + } +li_md_once(MD5, PSA_ALG_MD5) +li_md_once(SHA1, PSA_ALG_SHA_1) +li_md_once(SHA256, PSA_ALG_SHA_256) +li_md_once(SHA256_512, PSA_ALG_SHA_512_256) +li_md_once(SHA512, PSA_ALG_SHA_512) + +#endif +#endif + + typedef void(*li_md_once_fn)(unsigned char *digest, const void *data, size_t n); +#ifdef li_md_once +#undef li_md_once +#define li_md_once(algo) +#else #define li_md_once(algo) \ static inline void \ algo##_once (unsigned char * const digest, \ @@ -924,6 +1048,7 @@ algo##_Update(&ctx, data, n); \ algo##_Final(digest, &ctx); \ } +#endif #ifndef LI_CONST_IOVEC #define LI_CONST_IOVEC
participants (1)
-
Source-Sync