QUIC LCID hash table collapse on Windows/32-bit due to SipHash digest size misuse Using sizeof(unsigned long) as SipHash digest size; SipHash supports only 8 or 16 bytes. On platforms where sizeof(unsigned long) == 4, the call fails, and lcid_hash returns the zero-initialized value, degrading the hash table into list. The issue was kindly reported and fix provided by Stanislav Fort at Aisle Research. Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org> Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Neil Horman <nhorman@openssl.org> MergeDate: Thu Mar 12 18:04:10 2026 (Merged from https://github.com/openssl/openssl/pull/29814)
diff --git a/ssl/quic/quic_lcidm.c b/ssl/quic/quic_lcidm.c index 660eb80..e23c16c 100644 --- a/ssl/quic/quic_lcidm.c +++ b/ssl/quic/quic_lcidm.c
@@ -74,15 +74,21 @@ 0, }; unsigned long hashval = 0; + unsigned char digest[SIPHASH_MIN_DIGEST_SIZE]; - if (!SipHash_set_hash_size(&siphash, sizeof(unsigned long))) + /* Use a supported SipHash digest size (8 or 16); 8 is sufficient here. */ + if (!SipHash_set_hash_size(&siphash, SIPHASH_MIN_DIGEST_SIZE)) goto out; if (!SipHash_Init(&siphash, (uint8_t *)lcid_obj->hash_key, 0, 0)) goto out; SipHash_Update(&siphash, lcid_obj->cid.id, lcid_obj->cid.id_len); - if (!SipHash_Final(&siphash, (unsigned char *)&hashval, - sizeof(unsigned long))) + if (!SipHash_Final(&siphash, digest, SIPHASH_MIN_DIGEST_SIZE)) goto out; + + /* + * Truncate the 64-bit SipHash digest into an unsigned long. + */ + memcpy(&hashval, digest, sizeof(hashval) < sizeof(digest) ? sizeof(hashval) : sizeof(digest)); out: return hashval; }