MACGUARD · DOCUMENTACIÓN
English

Verificación de reglas, firmas y transparencia

Cómo comprobar tú mismo una release, sin confiar en este sitio: comandos, URLs reales y cómo interpretar los resultados.

A. Qué vas a comprobar

Una release es válida si (1) el manifiesto y el checkpoint están firmados por la identidad del workflow esperado, (2) cada fichero del paquete coincide con el SHA-256 del manifiesto firmado, (3) la raíz Merkle recalculada coincide con rules_root, y (4) el checkpoint contiene la entrada de la release y extiende al anterior que ya conocías.

LÍMITE Una firma y unos hashes correctos prueban quién publicó exactamente esos bytes. No prueban que las reglas sean buenas ni que los ficheros que se escanean sean seguros.

B. Requisitos

C. Artefactos de la última release

Release rules-20261018-39150886414. Los artefactos obligatorios se descargan de esta ruta:

https://github.com/MacGuard/macguard-yara-channel/releases/download/rules-20261018-39150886414/rules-release.tar.gz
https://github.com/MacGuard/macguard-yara-channel/releases/download/rules-20261018-39150886414/manifest.json
https://github.com/MacGuard/macguard-yara-channel/releases/download/rules-20261018-39150886414/manifest.sigstore.json
https://github.com/MacGuard/macguard-yara-channel/releases/download/rules-20261018-39150886414/inclusion-proof.json
https://github.com/MacGuard/macguard-yara-channel/releases/download/rules-20261018-39150886414/checkpoint.txt
https://github.com/MacGuard/macguard-yara-channel/releases/download/rules-20261018-39150886414/checkpoint.sigstore.json

Opcionales: release.json, changes.json, CHANGELOG.md y consistency.json (esta última prueba que el registro extiende el de la release anterior). Para descargarlos todos:

mkdir verify && cd verify
gh release download rules-20261018-39150886414 --repo MacGuard/macguard-yara-channel

D. Verificar la firma con cosign

Ejemplo mínimo con la identidad y el emisor esperados:

cosign verify-blob manifest.json \
  --bundle manifest.sigstore.json \
  --certificate-identity "https://github.com/MacGuard/macguard-yara-channel/.github/workflows/publish.yml@refs/heads/main" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com"

Versión completa, que además exige que el certificado nombre este repositorio, para el manifiesto y para el checkpoint:

cosign verify-blob manifest.json \
  --bundle manifest.sigstore.json \
  --certificate-identity "https://github.com/MacGuard/macguard-yara-channel/.github/workflows/publish.yml@refs/heads/main" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  --certificate-github-workflow-repository "MacGuard/macguard-yara-channel"

cosign verify-blob checkpoint.txt \
  --bundle checkpoint.sigstore.json \
  --certificate-identity "https://github.com/MacGuard/macguard-yara-channel/.github/workflows/publish.yml@refs/heads/main" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  --certificate-github-workflow-repository "MacGuard/macguard-yara-channel"

Resultado correcto: Verified OK. Si la identidad o el emisor no coinciden, cosign falla; no ejecutes nada de esa release.

E. Verificar los hashes del paquete

SHA-256 del paquete (debe ser 97304ccc48e2ab69368618c49dbf40f18cd7d0c310dfd4ee736ed8823170a8d0 para esta release) y del manifiesto (f75c214683d6c169716be1a5ac6f90a7c9a74f408c5cd139553a87e5a25370ad):

# macOS
shasum -a 256 rules-release.tar.gz manifest.json
# Linux
sha256sum rules-release.tar.gz manifest.json

Los hashes del paquete no están firmados por separado; lo que lo ata a la firma es que cada fichero extraído tiene el SHA-256 de manifest.json. El verificador lo hace por ti (sección G).

F. Recalcular rules_root e inclusión

El recálculo manual de rules_root está en Árboles Merkle. La prueba de inclusión (inclusion-proof.json) la comprueba el verificador: lleva la entrada del registro de la release hasta la raíz del checkpoint y comprueba que esa entrada nombra el rules_root firmado.

G. Verificador público

El script verify_public_release.py hace todo lo anterior de una vez (biblioteca estándar de Python y cosign). Descárgalo a un fichero, léelo y ejecútalo; no lo canalices a un intérprete.

curl -fsSLo verify_public_release.py https://raw.githubusercontent.com/MacGuard/macguard-yara-channel/main/scripts/verify_public_release.py
less verify_public_release.py
python3 verify_public_release.py --latest

Opciones: --latest, --tag TAG, --directory DIR (artefactos ya descargados), --json, --previous-checkpoint FILE o --trust-state FILE (protección contra retroceso), --token o la variable GITHUB_TOKEN (opcional). Funciona sin token: la API anónima de GitHub admite 60 peticiones por hora y dirección IP; si se agota (HTTP 403 con X-RateLimit-Remaining: 0) el verificador lo dice con la hora de reinicio y, sin usar la API, resuelve latest con la redirección de github.com y descarga los mismos artefactos (se comprueba Content-Length, no el tamaño de la API) y lo anota en el informe. Un 403 sin cuota agotada (cortafuegos, proxy) se informa como tal. Salida real, abreviada, sobre la última release:

MacGuard release verification — PASS (exit 0)

Release        rules-20261018-39150886414  (latest)
Files          1174   individual YARA rules: 9958
rules_root     16d082395ef1ec53d0ad25d5840d83e7f5f3a75a283ce66f8fa75da106790ec5

  [PASS] signature.manifest
  [PASS] signature.checkpoint
  [PASS] files.sha256
  [PASS] merkle.rules_root
  [PASS] merkle.inclusion
  [n/a ] consistency: no previous checkpoint was given
ACTUAL Sin --previous-checkpoint ni --trust-state el verificador lo dice expresamente: es una primera verificación y la protección contra retroceso no queda establecida por esa ejecución.

Códigos de salida

CódigoSignificado
0Todas las comprobaciones obligatorias hechas y superadas.
1Integridad: un hash no coincide.
2Firma o identidad inválidas.
3Merkle, inclusión o consistencia.
4Descarga incompleta o error de red.
5Falta una dependencia (cosign).
6Formato inválido o conjunto incompleto.

Si hay varios fallos el informe los lista todos y el código de salida es el primero por esta precedencia: 5, 4, 6, 2, 1, 3.

Diagrama: Verificador independiente

Dibujando el diagrama…

Descripción del diagrama

verify_public_release.py resuelve la release una sola vez y fija la etiqueta, descarga los artefactos obligatorios, verifica la identidad Sigstore del manifiesto y del checkpoint, extrae el paquete con límites, compara cada hash, recalcula rules_root, comprueba cifras, checkpoint, inclusión y consistencia opcional, y termina con un código que indica el tipo de fallo.

Código Mermaid
flowchart TD
  A["resolve tag once<br/>--latest or --tag"]:::src --> B["download mandatory artifacts<br/>exit 4 if incomplete"]:::src
  B --> C["cosign verify-blob<br/>manifest and checkpoint<br/>exit 2 or 5"]:::sec
  C --> D["safe extraction<br/>exit 6 if unsafe"]:::val
  D --> E["SHA-256 of every file<br/>exit 1 if different"]:::val
  E --> F["recompute rules_root<br/>exit 3"]:::sec
  F --> G["checkpoint equals manifest log head<br/>inclusion proof<br/>exit 3"]:::sec
  G --> H{"previous checkpoint<br/>given?"}:::gate
  H -->|yes| I["consistency proof and rollback check<br/>exit 3"]:::sec
  H -->|no| J["report: rollback protection not established"]:::qua
  I --> K["PASS exit 0"]:::pub
  J --> K
  classDef src fill:#cfe3ff,stroke:#2f6df0,color:#0b1b33
  classDef val fill:#ffe9b8,stroke:#b8860b,color:#2b1d00
  classDef sec fill:#cdeedd,stroke:#1b6e3c,color:#08210f
  classDef pub fill:#e4d7ff,stroke:#6a3fd1,color:#1b0b3b
  classDef qua fill:#ffd4cc,stroke:#c0392b,color:#33100b
  classDef gate fill:#ffffff,stroke:#111111,stroke-width:3px,color:#111111

H. Cómo saber que el verificador es el correcto

El verificador es código que ejecutas tú: léelo (unas 400 líneas) y compara el commit en GitHub. Descargarlo del mismo sitio que aloja las reglas no es una raíz de confianza independiente.

PROPUESTA Firmar verify_public_release.py con Sigstore en publish.yml y adjuntarlo a cada release es una mejora propuesta: no existe todavía, así que las releases actuales no llevan una copia firmada del verificador.

I. Qué hacer si falla