hmac_sign() previously trusted whatever secret_hex came out of NVS:
- Lengths >128 chars overflowed the fixed 64-byte stack buffer in
hex_to_bytes (out_len was unbounded).
- Non-hex characters were silently decoded to 0 via strtol with no
end-pointer check, producing signatures under a corrupted key.
- Empty secrets fell through to mbedtls_md_hmac_starts with len=0.
flash_device.py now rejects malformed --hmac-secret at provision time,
but hmac_sign should also refuse to sign under a malformed key regardless
of how it ended up in NVS (legacy provisioning, partial flash, etc.).
Add length, hex-charset, and even-length validation; make hex_to_bytes
return bool and have hmac_sign return empty HString on any failure
(callers already treat empty as failure via post_json_once).
Found via adversarial review (run 2026-05-01-202910, both reviewers).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>