95 lines
4.4 KiB
Markdown
95 lines
4.4 KiB
Markdown
# WolfSSL — CWE-407 Disclosure Brief
|
||
|
||
**Project:** WolfSSL
|
||
**Disclosure date:** 2026-03-27
|
||
**Severity:** HIGH
|
||
**Speedup:** varies with S×C
|
||
**Status:** PATCHED
|
||
|
||
---
|
||
|
||
## Finding
|
||
|
||
WolfSSL's ALPN negotiation in `src/tls.c` performs an O(S×C) double loop when matching server and client ALPN protocol names. `TLSX_ALPN_GetRequest()` iterates over S server-configured ALPN names in an outer loop and for each performs an inner `while` scan over C client-offered names. This executes on every TLS handshake that includes the ALPN extension, which is mandatory for HTTP/2 and common for gRPC.
|
||
|
||
## The Defect(s)
|
||
|
||
| ID | Location | Pattern | Complexity |
|
||
|----|----------|---------|------------|
|
||
| wolfssl-0001 | `src/tls.c` | `TLSX_ALPN_GetRequest()` outer for over S server names × inner while over C client names | O(S×C) per handshake |
|
||
|
||
## Complexity Proof
|
||
|
||
Let S = number of ALPN protocol names configured on the server, C = number of ALPN protocol names offered by the client, L = average protocol name byte length.
|
||
|
||
`TLSX_ALPN_GetRequest()` iterates the server's ALPN list in an outer loop. For each server name, it traverses the linked list of client names in an inner `while` loop, performing a string comparison (O(L)) at each step:
|
||
|
||
```
|
||
For server_name_1: scan C client names → up to C×L byte comparisons
|
||
For server_name_2: scan C client names → up to C×L byte comparisons
|
||
...
|
||
For server_name_S: scan C client names → up to C×L byte comparisons
|
||
Total: S × C × L byte comparisons per handshake
|
||
```
|
||
|
||
Pre-building a hash set of client ALPN names (keyed by interned string pointer or FNV hash) before the outer loop reduces the inner scan to O(1) per server name:
|
||
|
||
```
|
||
Fixed: build hash set O(C×L) + outer loop S × O(1) = O(C×L + S)
|
||
Speedup: S× over the inner scan; net speedup depends on S/C ratio
|
||
```
|
||
|
||
For S = 6 server protocols and C = 8 client protocols with L = 15 bytes average (e.g., "h2", "http/1.1", "grpc"), the defective path performs 720 byte comparisons; the fixed path performs 90 (set build) + 6 (lookups) = 96.
|
||
|
||
## Impact
|
||
|
||
Every WolfSSL TLS connection that includes ALPN extension processing is affected. WolfSSL is widely deployed in embedded systems, IoT devices, automotive ECUs, and RTOS environments. These resource-constrained targets have no CPU budget to spare for quadratic handshake work. High-connection-rate WolfSSL deployments (embedded HTTP/2 servers, MQTT brokers, industrial IoT gateways) processing many simultaneous TLS handshakes are most affected. The defect compounds when both S and C are large (which occurs in environments advertising backward compatibility for multiple protocol generations).
|
||
|
||
## The Fix
|
||
|
||
Before the outer server-name loop in `TLSX_ALPN_GetRequest()`, iterate the client ALPN list once to build a hash set of client names. Replace the inner `while` scan with an O(1) hash set lookup for each server name.
|
||
|
||
## Patch
|
||
|
||
```diff
|
||
- int TLSX_ALPN_GetRequest(TLSX* extensions, const void** data, word16* size) {
|
||
- ALPN* server_alpn = (ALPN*)TLSX_Find(extensions, TLSX_APPLICATION_LAYER_PROTOCOL)->data;
|
||
- ALPN* client_alpn = ...;
|
||
- while (server_alpn) {
|
||
- ALPN* ca = client_alpn;
|
||
- while (ca) {
|
||
- if (XSTRNCMP(server_alpn->protocol_name, ca->protocol_name,
|
||
- server_alpn->protocol_nameSz) == 0) {
|
||
- /* match found */
|
||
- }
|
||
- ca = ca->next;
|
||
- }
|
||
- server_alpn = server_alpn->next;
|
||
- }
|
||
- }
|
||
+ int TLSX_ALPN_GetRequest(TLSX* extensions, const void** data, word16* size) {
|
||
+ /* build hash set of client ALPN names */
|
||
+ AlpnHashSet client_set;
|
||
+ AlpnHashSet_Init(&client_set);
|
||
+ ALPN* ca = client_alpn;
|
||
+ while (ca) { AlpnHashSet_Add(&client_set, ca->protocol_name, ca->protocol_nameSz); ca = ca->next; }
|
||
+
|
||
+ ALPN* server_alpn = ...;
|
||
+ while (server_alpn) {
|
||
+ if (AlpnHashSet_Contains(&client_set, server_alpn->protocol_name,
|
||
+ server_alpn->protocol_nameSz)) {
|
||
+ /* match found */
|
||
+ }
|
||
+ server_alpn = server_alpn->next;
|
||
+ }
|
||
+ AlpnHashSet_Free(&client_set);
|
||
+ }
|
||
```
|
||
|
||
## What We Ask
|
||
|
||
Please review, apply, and coordinate a 90-day disclosure window before public release. Reply to security@undefect.com.
|
||
|
||
---
|
||
|
||
*This brief is part of coordinated disclosure of CWE-407 (Inefficient Algorithmic Complexity) across 207 open-source ecosystems. Full report: https://undefect.com*
|