# 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)