Commit a24fbf403a for openssl.org
commit a24fbf403a891ec026847f70bef1fd582b1e9601
Author: slontis <shane.lontis@oracle.com>
Date: Wed Mar 18 10:16:44 2026 +1100
SLH-DSA: Fix Integer overflow in msg_encode leading to buffer overflow
Reported by Zehua Qiao and me@snkth.com
An encode message buffer M = 00 || CXT_LEN || CTX || MSG was being
allocated followed by memcpy's into the buffer for CTX and MSG.
If len(MSG) was close to size_t the allocated buffer would be
overwritten.
The fix uses WPACKET to perform the message encoding M = 00 || CXT_LEN || CTX || MSG
Although ML_DSA does a similiar operation, SLH-DSA has to buffer the
encoding because the encoded message is processed multiple times for
PRF_MSG and H_MSG. FOr ML_DSA the encoded message can just be hashed.
Fixes: 2f9e152d86a7 "Add SLH_DSA signature verification."
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
Reviewed-by: Matt Caswell <matt@openssl.foundation>
Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
MergeDate: Sun Mar 22 00:15:47 2026
(Merged from https://github.com/openssl/openssl/pull/30477)
diff --git a/crypto/slh_dsa/slh_dsa.c b/crypto/slh_dsa/slh_dsa.c
index 36d0a61531..6519e8640f 100644
--- a/crypto/slh_dsa/slh_dsa.c
+++ b/crypto/slh_dsa/slh_dsa.c
@@ -232,6 +232,7 @@ static uint8_t *msg_encode(const uint8_t *msg, size_t msg_len,
const uint8_t *ctx, size_t ctx_len, int encode,
uint8_t *tmp, size_t tmp_len, size_t *out_len)
{
+ WPACKET pkt;
uint8_t *encoded = NULL;
size_t encoded_len;
@@ -240,11 +241,14 @@ static uint8_t *msg_encode(const uint8_t *msg, size_t msg_len,
*out_len = msg_len;
return (uint8_t *)msg;
}
+
if (ctx_len > SLH_DSA_MAX_CONTEXT_STRING_LEN)
return NULL;
/* Pure encoding */
encoded_len = 1 + 1 + ctx_len + msg_len;
+ if (encoded_len < msg_len) /* Check for overflow */
+ return NULL;
*out_len = encoded_len;
if (encoded_len <= tmp_len) {
encoded = tmp;
@@ -253,10 +257,17 @@ static uint8_t *msg_encode(const uint8_t *msg, size_t msg_len,
if (encoded == NULL)
return NULL;
}
- encoded[0] = 0;
- encoded[1] = (uint8_t)ctx_len;
- memcpy(&encoded[2], ctx, ctx_len);
- memcpy(&encoded[2 + ctx_len], msg, msg_len);
+ if (!WPACKET_init_static_len(&pkt, encoded, encoded_len, 0)
+ || !WPACKET_put_bytes_u8(&pkt, 0)
+ || !WPACKET_put_bytes_u8(&pkt, (uint8_t)ctx_len)
+ || !WPACKET_memcpy(&pkt, ctx, ctx_len)
+ || !WPACKET_memcpy(&pkt, msg, msg_len)
+ || !WPACKET_finish(&pkt)) {
+ if (encoded != tmp)
+ OPENSSL_free(encoded);
+ encoded = NULL;
+ WPACKET_cleanup(&pkt);
+ }
return encoded;
}