diff --git a/zephcore/app/RepeaterMesh.cpp b/zephcore/app/RepeaterMesh.cpp index 6196f02..6298d67 100644 --- a/zephcore/app/RepeaterMesh.cpp +++ b/zephcore/app/RepeaterMesh.cpp @@ -122,18 +122,22 @@ void RepeaterMesh::putNeighbour(const mesh::Identity& id, uint32_t timestamp, fl * byte of `a` matches `b`. No early exit — timing is independent of input, * defeating timing-leak attacks against password comparison. * + * `volatile` on the accumulator prevents the compiler from short-circuiting + * the XOR-OR loop back into a branching memcmp under aggressive LTO. Pattern + * matches rweather/arduinolibs Crypto.cpp secure_compare(). mbedtls offers + * mbedtls_ct_memcmp() but its implementation lives in a .c file that isn't + * pulled into the Zephyr mbedtls build under current Kconfig — would require + * enabling additional TLS features just for this one function. + * * Mitigation for the password-handling weakness tracked upstream as - * meshcore-dev/MeshCore#2556. The protocol still sends plaintext passwords - * (encrypted only at the mesh layer to whatever pubkey the user selected), - * but this fix removes the timing oracle that would otherwise let an - * already-MITM attacker reveal the stored password byte-by-byte. */ + * meshcore-dev/MeshCore#2556. See CRYPTO_AUDIT_INDEX.md P4.F1. */ static bool ct_memeq(const uint8_t *a, const uint8_t *b, size_t n) { - uint8_t diff = 0; + volatile uint8_t result = 0; for (size_t i = 0; i < n; i++) { - diff |= (uint8_t)(a[i] ^ b[i]); + result |= (uint8_t)(a[i] ^ b[i]); } - return diff == 0; + return result == 0; } uint8_t RepeaterMesh::handleLoginReq(const mesh::Identity& sender, const uint8_t* secret, uint32_t sender_timestamp, const uint8_t* data, bool is_flood) {