60 lines
2.3 KiB
Diff
60 lines
2.3 KiB
Diff
# UNDF: UNDF-2026-000000202
|
|
From b8df87a Mon Sep 17 00:00:00 2001
|
|
Subject: [CWE-407] ssl_lib: fix O(n²) SSL_get_shared_ciphers via hash-set membership
|
|
|
|
SSL_get_shared_ciphers() iterated all client ciphers and called
|
|
sk_SSL_CIPHER_find() on the unsorted server stack for each one.
|
|
sk_SSL_CIPHER_find() on an unsorted stack falls through to a linear
|
|
scan (see crypto/stack/stack.c:internal_find), making the total
|
|
complexity O(n*m).
|
|
|
|
Fix: build a 64-bit bitmask of server cipher IDs before the loop.
|
|
All TLS cipher IDs fit in 32 bits; we use a simple open-addressing
|
|
hash table of size 256 (power-of-two, load ≤ 50% for typical lists
|
|
of ≤128 ciphers) so lookup is O(1) expected.
|
|
|
|
--- a/ssl/ssl_lib.c
|
|
+++ b/ssl/ssl_lib.c
|
|
@@ -3594,6 +3594,8 @@ char *SSL_get_shared_ciphers(const SSL *s, char *buf, int size)
|
|
{
|
|
char *p;
|
|
STACK_OF(SSL_CIPHER) *clntsk, *srvrsk;
|
|
+ uint32_t srvr_ids[256]; /* open-addressing hash set, 0 = empty slot */
|
|
+ int srvr_count, j;
|
|
const SSL_CIPHER *c;
|
|
int i;
|
|
const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
|
|
@@ -3610,12 +3612,30 @@ char *SSL_get_shared_ciphers(const SSL *s, char *buf, int size)
|
|
if (clntsk == NULL || sk_SSL_CIPHER_num(clntsk) == 0
|
|
|| srvrsk == NULL || sk_SSL_CIPHER_num(srvrsk) == 0)
|
|
return buf;
|
|
+
|
|
+ /* Build O(1) membership set from server ciphers.
|
|
+ * Table size 256, probe = linear, load kept ≤ 50%. */
|
|
+ memset(srvr_ids, 0, sizeof(srvr_ids));
|
|
+ srvr_count = sk_SSL_CIPHER_num(srvrsk);
|
|
+ for (j = 0; j < srvr_count; j++) {
|
|
+ uint32_t id = sk_SSL_CIPHER_value(srvrsk, j)->id;
|
|
+ unsigned slot = (id * 2654435761u) >> 24; /* Knuth multiplicative hash */
|
|
+ while (srvr_ids[slot] != 0 && srvr_ids[slot] != id)
|
|
+ slot = (slot + 1) & 0xff;
|
|
+ srvr_ids[slot] = id;
|
|
+ }
|
|
|
|
for (i = 0; i < sk_SSL_CIPHER_num(clntsk); i++) {
|
|
int n;
|
|
+ uint32_t id;
|
|
+ unsigned slot;
|
|
|
|
c = sk_SSL_CIPHER_value(clntsk, i);
|
|
- if (sk_SSL_CIPHER_find(srvrsk, c) < 0)
|
|
- continue;
|
|
+ id = c->id;
|
|
+ slot = (id * 2654435761u) >> 24;
|
|
+ while (srvr_ids[slot] != 0 && srvr_ids[slot] != id)
|
|
+ slot = (slot + 1) & 0xff;
|
|
+ if (srvr_ids[slot] != id)
|
|
+ continue; /* not in server set */
|
|
|
|
n = (int)OPENSSL_strnlen(c->name, size);
|
|
if (n >= size)
|