]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
SLH-DSA: Fix Integer overflow in msg_encode leading to buffer overflow
authorslontis <shane.lontis@oracle.com>
Tue, 17 Mar 2026 23:16:44 +0000 (10:16 +1100)
committerEugene Syromiatnikov <esyr@openssl.org>
Sun, 22 Mar 2026 00:19:23 +0000 (01:19 +0100)
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:19:24 2026
(Merged from https://github.com/openssl/openssl/pull/30477)

crypto/slh_dsa/slh_dsa.c

index 36d0a615314d279970e1c752fc21a2656e0768f8..6519e8640fb186c48d585eeec6e37a2f10406959 100644 (file)
@@ -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;
 }