zeroclaw-labs/zeroclaw · info
HMAC accepts any key length
Error message
HMAC accepts any key length
What it means
TuiIdentityRegistry::sign() signs a TUI id with HMAC-SHA256 when a signing key is configured. new_from_slice() is expected to succeed with "HMAC accepts any key length"; HMAC imposes no key-length restriction, so this is a static invariant and the expect cannot realistically fire.
Source
Thrown at crates/zeroclaw-runtime/src/rpc/tui_identity.rs:99
/// Generate a TUI ID that is not currently in the registry.
pub fn generate_unique_tui_id(&self) -> String {
let connected = self.connected.lock().unwrap_or_else(|e| e.into_inner());
loop {
let id = Self::generate_tui_id();
if !connected.contains_key(&id) {
return id;
}
}
}
// ── HMAC signing ─────────────────────────────────────────────
/// Sign a TUI ID with HMAC-SHA256. Returns `None` if signing is
/// disabled.
pub fn sign(&self, tui_id: &str) -> Option<String> {
let key = self.signing_key.as_ref()?;
let mut mac = HmacSha256::new_from_slice(key).expect("HMAC accepts any key length");
mac.update(tui_id.as_bytes());
Some(hex::encode(mac.finalize().into_bytes()))
}
/// Verify a TUI ID + signature. Returns `true` if:
/// - Signing is disabled (trust all), OR
/// - The signature is valid.
pub fn verify(&self, tui_id: &str, sig: &str) -> bool {
let Some(ref key) = self.signing_key else {
return true;
};
let Ok(sig_bytes) = hex::decode(sig) else {
return false;
};
let mut mac = HmacSha256::new_from_slice(key).expect("HMAC accepts any key length");
mac.update(tui_id.as_bytes());
mac.verify_slice(&sig_bytes).is_ok()
}View on GitHub (pinned to 88bb9c8533)
Solutions
- No action needed at runtime; if seen, inspect local modifications to TuiIdentityRegistry key handling.
- Keep the configured signing key a non-empty secret as good practice.
- Add a roundtrip unit test (sign_verify_roundtrip exists) when modifying this code.
Defensive patterns
Strategy: validation
Validate before calling
// At config load, reject empty signing keys before they reach the registry:
if let Some(key) = &config.tui_signing_key {
anyhow::ensure!(!key.is_empty(), "tui signing key must be a non-empty secret");
} Prevention
- Configure a non-empty, high-entropy TUI signing key.
- Note sign() returns None when signing is disabled; no panic path exists for callers.
- Re-run sign_verify_roundtrip tests when modifying TuiIdentityRegistry.
When it happens
Trigger: Calling sign() while TUI-id signing is enabled (signing_key is Some). No key material can make new_from_slice fail; only a refactor that bypasses HMAC's key contract could trigger it.
Common situations: None for users. Maintainers touching the signing_key type (e.g. changing it from Vec<u8>) should re-check the invariant.
Related errors
- HMAC accepts any key length
- Schema missing required 'type' field
- Request timestamp too old or too far in future
- Encrypted value too short (missing nonce)
- Key file must contain exactly 32 bytes (got {})
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/b2cfb52640e9e610.
Report an issue: GitHub.