Details
-
Bug
-
Status: Closed (View Workflow)
-
Major
-
Resolution: Fixed
-
None
-
None
Description
ParsecPasswordPlugin accepts the PBKDF2 iteration factor from the server's ext-salt response, capped at 20. The factor is an exponent (effective work is 1024 << iterations, so 20 means ~1.07 billion PBKDF2-HMAC-SHA512 rounds, measured at ~13 min on an i9-11900K / OpenJDK 25; 49.6 s at factor 16, measured).
The derivation runs on the Netty event loop thread: pluginHandler.next() is invoked synchronously from AuthenticationFlow.AUTH_SWITCH.handle(), and the client scheduler is the event loop itself (SimpleClient:100). A malicious or MITM server therefore stalls not just the connecting client but every other connection assigned to that event loop thread, for minutes, with a single small response.
Fix 1: derive the cap from the connection time budget instead of hardcoding:
budget = connectTimeout > 0 ? connectTimeout : SERVER_CONNECT_TIMEOUT_DEFAULT (10s)
maxIterationFactor = max(0, floor(log2(PBKDF2_ROUNDS_PER_MS * budget / 1024)))
PBKDF2_ROUNDS_PER_MS is a deliberately conservative throughput constant (262144 rounds / 225 ms).
connectTimeout cap work at cap
|
100 ms 6 48 ms
|
2.5 s 11 1.5 s
|
10 s (default) 13 6.2 s
|
30 s 15 25.7 s
|
0 13 6.2 s
|
The bound scales with connectTimeout by design: the client declares its own budget, and a longer declared budget permits a larger factor.
Fix 2: offload the derivation. Wrap the pluginHandler.next() call so the PBKDF2 runs on Schedulers.boundedElastic() rather than the event loop.
Thanks fg0x0 for reporting it.