Saltar a contenido

ADR-010 — Claves HMAC por keyId en tabla cifrada

  • Status: accepted (D10 del BRIEF; secreto cifrado como invariante en CONSTITUTION)
  • Context: La firma del token es HMAC-SHA256 (simétrica): el mismo secreto vive en ~250 cajas y en el servidor. Hay que poder rotar sin corte de servicio.
  • Alternatives: JKS/keystore de PKI (concepto de firma asimétrica que acá no aplica); secreto único hardcodeado (sin rotación); tabla clave_firma por key_id (elegida).
  • Decision: "Keystore" = tabla clave_firma(key_id, secreto_cifrado, estado, vigencia_desde, vigencia_hasta). El server valida contra la clave que indica el keyId (offset 0) del token. Rotación: alta de nueva clave con nuevo keyId, distribución a cajas, ambas válidas durante la transición.
  • Consequences: Compromiso de una caja se mitiga rotando keyIdriesgo aceptado y documentado (RISKS.md). El secreto se guarda cifrado at-rest (master key vía env/Vaultwarden), nunca en claro en repo ni logs.
  • Riesgo aceptado: quien extraiga el secreto de una caja puede fabricar vouchers válidos hasta la rotación. Mitigación: rotación de keyId + señales antifraude (concentración por caja/DNI/conexión).

Implementation Plan

  • Tabla clave_firma; cifrado del secreto con AES-GCM y master key por variable de entorno; caché en memoria del secreto descifrado.
  • Validación: leer keyId del token → clave correspondiente → HMAC en tiempo constante.
  • Precisión (QA pass 1): la aceptación de una clave en validación se resuelve por estado (activa y rotada validan; revocada no), NUNCA por reloj contra vigencia_*: un voucher emitido con una clave luego rotada debe seguir validando ("rotación sin corte"). Las fechas de vigencia son informativas para operación/rotación en cajas.
  • Clave de prueba para el ambiente de test (M6) con keyId reservado.

Verification

  • [ ] Test: token firmado con clave rotada (estado activa en su vigencia) valida OK.
  • [ ] Test: keyId inexistente/revocado → caso A (error genérico).
  • [ ] El secreto no aparece en claro en repo, logs ni dumps de configuración.