From: Greg Kroah-Hartman Date: Tue, 7 Apr 2026 07:48:12 +0000 (+0200) Subject: BUG/MEDIUM: jwt: fix heap overflow in ECDSA signature DER conversion X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=648b0e7beac4746f1f4184a2f09eedad5246fff3;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: jwt: fix heap overflow in ECDSA signature DER conversion convert_ecdsa_sig() calls i2d_ECDSA_SIG(ecdsa_sig, &p) where p points into signature->area, a trash chunk of tune.bufsize bytes (default 16384). i2d writes with no output bound. The raw R||S input can be up to bufsize bytes (filled by base64urldec at jwt.c:520-527), giving bignum_len up to 8192. The DER encoding adds a SEQUENCE header (2-4 bytes), two INTEGER headers (2-4 bytes each), and up to two leading-zero sign-padding bytes when the bignum high bit is set. With two 8192-byte bignums having the high bit set, the encoding is ~16398 bytes, overflowing the 16384- byte buffer by ~14 bytes. Triggered by any JWT with alg=ES256/384/512 and a ~21830-character base64url signature. The signature does not need to verify successfully; the overflow happens before verification. Reachable from any config using jwt_verify with an EC algorithm. Also fixes the existing wrong check: i2d returns -1 on error which became SIZE_MAX in the size_t signature->data, defeating the "== 0" test. This must be backported as far as JWT support exists. --- diff --git a/src/jwt.c b/src/jwt.c index 3dc04b1fb..0ab557afe 100644 --- a/src/jwt.c +++ b/src/jwt.c @@ -331,14 +331,21 @@ static int convert_ecdsa_sig(const struct jwt_ctx *ctx, struct buffer *signature /* Build ecdsa out of R and S values. */ ECDSA_SIG_set0(ecdsa_sig, ec_R, ec_S); - p = (unsigned char*)signature->area; - - signature->data = i2d_ECDSA_SIG(ecdsa_sig, &p); - if (signature->data == 0) { + /* i2d_ECDSA_SIG writes with no output bound. The DER encoding adds + * a SEQUENCE header (~4 bytes), two INTEGER headers (~4 bytes each), + * and up to two sign-padding bytes on top of the raw R||S bytes. + * Compute the length first to avoid overflowing signature->area. + */ + retval = i2d_ECDSA_SIG(ecdsa_sig, NULL); + if (retval <= 0 || (size_t)retval > signature->size) { retval = JWT_VRFY_INVALID_TOKEN; goto end; } + p = (unsigned char*)signature->area; + signature->data = i2d_ECDSA_SIG(ecdsa_sig, &p); + retval = 0; + end: ECDSA_SIG_free(ecdsa_sig); return retval;