challenger

OAuth 2.0-based authentication service that validates user can receive messages at a certain address
Log | Files | Refs | Submodules | README | LICENSE

commit 60024bbd1180e938c44a10753d53d79a6b6affd0
parent 93a1a1cdae66ab06c0fa3f23332f6faada936e27
Author: Christian Grothoff <grothoff@gnunet.org>
Date:   Sun, 19 Jul 2026 15:15:06 +0200

guard against large chunked uploads

Diffstat:
Msrc/challenger/challenger-httpd_challenge.c | 23+++++++++++++++++++++++
Msrc/challenger/challenger-httpd_solve.c | 22++++++++++++++++++++++
Msrc/challenger/challenger-httpd_token.c | 23+++++++++++++++++++++++
Msrc/challengerdb/token_add_token.c | 5++++-
4 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/src/challenger/challenger-httpd_challenge.c b/src/challenger/challenger-httpd_challenge.c @@ -183,6 +183,11 @@ struct ChallengeContext * Is the upload in JSON? */ bool is_json; + + /** + * Set to true if the upload is too big. + */ + bool too_big; }; @@ -539,6 +544,15 @@ post_iter (void *cls, { bc->last_key = GNUNET_strdup (key); } + /* Hard cap independent of Content-Length: TALER_MHD_check_content_length() + does not reject requests that omit Content-Length (e.g. chunked uploads), + so without this guard an attacker could stream an unbounded field value. */ + if (bc->data_len + size > 1024) + { + GNUNET_break_op (0); + bc->too_big = true; + return MHD_NO; + } bc->data = GNUNET_realloc (bc->data, bc->data_len + size + 1); memcpy (bc->data + bc->data_len, @@ -764,6 +778,15 @@ CH_handler_challenge (struct CH_HandlerContext *hc, GNUNET_break (0); return MHD_NO; } + if (bc->too_big) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error ( + hc->connection, + MHD_HTTP_CONTENT_TOO_LARGE, + TALER_EC_GENERIC_UPLOAD_EXCEEDS_LIMIT, + NULL); + } if (NULL != bc->last_key) { GNUNET_assert (0 == diff --git a/src/challenger/challenger-httpd_solve.c b/src/challenger/challenger-httpd_solve.c @@ -92,6 +92,10 @@ struct SolveContext */ uint32_t pin_transmissions_left; + /** + * Set to true if the upload is too big. + */ + bool too_big; }; @@ -157,6 +161,15 @@ post_iter (void *cls, return MHD_YES; if (MHD_POSTDATA_KIND != kind) return MHD_YES; + /* Hard cap independent of Content-Length: TALER_MHD_check_content_length() + does not reject requests that omit Content-Length (e.g. chunked uploads), + so without this guard an attacker could stream an unbounded 'pin' value. */ + if (bc->pin_len + size > 1024) + { + bc->too_big = true; + GNUNET_break_op (0); + return MHD_NO; + } bc->pin = GNUNET_realloc (bc->pin, bc->pin_len + size + 1); memcpy (bc->pin + bc->pin_len, @@ -225,6 +238,15 @@ CH_handler_solve (struct CH_HandlerContext *hc, return MHD_YES; return MHD_NO; } + if (bc->too_big) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error ( + hc->connection, + MHD_HTTP_CONTENT_TOO_LARGE, + TALER_EC_GENERIC_UPLOAD_EXCEEDS_LIMIT, + NULL); + } if (NULL == bc->pin) { GNUNET_break_op (0); diff --git a/src/challenger/challenger-httpd_token.c b/src/challenger/challenger-httpd_token.c @@ -79,6 +79,11 @@ struct TokenContext * Uploaded 'code_verifier' field from POST data. */ char *code_verifier; + + /** + * Set to true if the upload was too big. + */ + bool too_big; }; @@ -189,6 +194,15 @@ post_iter (void *cls, slen = 0; else slen = strlen (*ptr); + /* Hard cap independent of Content-Length: TALER_MHD_check_content_length() + does not reject requests that omit Content-Length (e.g. chunked uploads), + so without this guard an attacker could stream an unbounded field value. */ + if (slen + size > 2 * 1024) + { + GNUNET_break_op (0); + bc->too_big = true; + return MHD_NO; + } if (NULL == *ptr) *ptr = GNUNET_malloc (size + 1); else @@ -246,6 +260,15 @@ CH_handler_token (struct CH_HandlerContext *hc, return MHD_YES; return MHD_NO; } + if (bc->too_big) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error ( + hc->connection, + MHD_HTTP_CONTENT_TOO_LARGE, + TALER_EC_GENERIC_UPLOAD_EXCEEDS_LIMIT, + NULL); + } if (NULL == bc->grant_type) { /* RFC 6749 5.2: a missing required parameter is 'invalid_request', not diff --git a/src/challengerdb/token_add_token.c b/src/challengerdb/token_add_token.c @@ -63,7 +63,10 @@ CHALLENGERDB_token_add_token (struct CHALLENGERDB_PostgresContext *ctx, " ,token_expiration_time" " ,address_expiration_time" ") SELECT" - " $2, address, $3, $4 + last_tx_time" + " $2" + " ,address" + " ,$3" + " ,LEAST($4, 9223372036854775807::BIGINT - last_tx_time) + last_tx_time" " FROM consumed;"); return GNUNET_PQ_eval_prepared_non_select (ctx->conn, "token_add_token",