# Introducción a constancias NOM-151 y sellos de tiempo Fuente: /timestamping/introduction/ Verificamex emite, a través de un **Prestador de Servicios de Certificación (PSC) autorizado**, dos tipos de evidencia con fecha cierta sobre la huella digital (SHA-256) de tus archivos: | | Constancia de conservación NOM-151 | Sello de tiempo | | - | - | - | | Qué prueba | Que el documento existía, íntegro, en la fecha de la constancia. | Que una huella SHA-256 existía en la fecha del sello. | | Uso típico | Una por documento terminado (contrato, expediente). La guardas junto al archivo. | Incrustado dentro de una firma electrónica (PAdES/CAdES), normalmente uno por firmante. | | Qué recibes | La constancia completa (`.asn1`, RFC 3161). | El sello (`TimeStampToken`, `.tst`, RFC 3161) listo para incrustar. | | Costo | 5 tokens | 5 tokens | | Endpoint | [Generar constancia NOM-151](/timestamping/create-nom151-constancy/) | [Generar sello de tiempo](/timestamping/create-time-stamp/) | > **Tu documento nunca sale de tu sistema** > > No envías el archivo: solo su huella SHA-256. La constancia o el sello se emiten sobre esa huella, > así que el contenido del documento nunca llega a Verificamex ni al PSC. ## 1. Calcula la huella SHA-256 La API acepta la huella en **hexadecimal** (64 caracteres, mayúsculas o minúsculas) o en **Base64** (44 caracteres). Estos comandos la dan en hexadecimal: **Windows (PowerShell)** ```powershell (Get-FileHash .\contrato.pdf -Algorithm SHA256).Hash ``` **Windows (CMD)** ```bash certutil -hashfile contrato.pdf SHA256 ``` **Mac / Linux** ```bash shasum -a 256 contrato.pdf ``` **Node.js** ```javascript import { createHash } from 'node:crypto'; import { readFileSync } from 'node:fs'; const hash = createHash('sha256').update(readFileSync('contrato.pdf')).digest('hex'); ``` > **Conserva el archivo exacto** > > La constancia o el sello solo corresponden a los bytes exactos de los que sacaste la huella. Si el > archivo cambia en un solo byte (por ejemplo, al agregarle una hoja de firmas), ya no le corresponde. > Guarda la versión exacta que sellaste. ## 2. Solicita la constancia o el sello Envía la huella al endpoint correspondiente. La respuesta es **síncrona**: en unos segundos recibes el archivo en Base64 dentro del mismo JSON. Solo se cobran tokens si el PSC emite el archivo y este corresponde a la huella que enviaste. ## 3. Guarda y verifica el archivo Decodifica el Base64 y guarda el archivo sin modificarlo. Para verificarlo puedes usar OpenSSL: **Sello de tiempo (.tst)** ```bash # 1) Verifica la firma del sello y extrae su contenido openssl cms -verify -inform DER -in sello.tst -noverify -binary -out tstinfo.der # 2) Muestra la huella sellada y la fecha openssl asn1parse -inform DER -in tstinfo.der ``` **Constancia NOM-151 (.asn1)** ```bash # 1) La constancia es la respuesta completa del PSC: primero extrae el sello que contiene openssl asn1parse -inform DER -in constancia.asn1 -strparse 9 -noout -out token.der # 2) Verifica la firma y extrae su contenido openssl cms -verify -inform DER -in token.der -noverify -binary -out tstinfo.der # 3) Muestra la huella sellada y la fecha openssl asn1parse -inform DER -in tstinfo.der ``` Cómo leer el resultado: - **`CMS Verification successful`**: la firma está íntegra y la hizo el certificado del PSC incluido en el archivo. La opción `-noverify` omite validar quién emitió ese certificado; para hacerlo, sigue la [validación de la cadena de confianza](#4-opcional-valida-la-cadena-de-confianza). - **`OCTET STRING [HEX DUMP]`**: es la huella sellada; debe ser la misma que enviaste (OpenSSL la muestra en mayúsculas). - **`GENERALIZEDTIME`**: es la fecha oficial del sello en UTC, la misma que recibes en la respuesta de la API. > **openssl ts no lee estos archivos** > > Los archivos del PSC incluyen un certificado adicional en un formato que el comando `openssl ts` > no reconoce, por lo que `openssl ts -reply ... -text` responde con un error. Usa `openssl cms` > como se muestra arriba. ## 4. (Opcional) Valida la cadena de confianza El paso anterior confirma que el archivo no se alteró. Para confirmar además que el certificado del PSC lo emitió la **Secretaría de Economía**, la autoridad raíz de los PSC acreditados en México, valida la firma contra su certificado raíz. La Secretaría lo publica en su [directorio de PSC acreditados](https://psc.economia.gob.mx/directorio.html), junto con los certificados de cada PSC. ```bash # 1) Descarga el certificado raíz de la Secretaría de Economía y conviértelo a PEM curl -O https://psc.economia.gob.mx/certificados/ACR2_SE.cer openssl x509 -inform DER -in ACR2_SE.cer -out ACR2_SE.pem # 2) Comprueba que es el certificado correcto: la huella debe terminar en ...1E:09:C7:20 openssl x509 -in ACR2_SE.pem -noout -fingerprint -sha256 # 3) Verifica la firma y la cadena completa # (para la constancia NOM-151 usa el token.der que extrajiste en el paso 3) openssl cms -verify -inform DER -in sello.tst -CAfile ACR2_SE.pem -ignore_critical -purpose any -binary -out tstinfo.der ``` La huella SHA-256 completa del certificado raíz es `B2:F2:58:C4:2C:30:66:C5:4C:3D:9B:BC:B9:A4:C1:6B:ED:4E:7B:74:F3:02:64:3A:11:AF:26:96:1E:09:C7:20`. Si obtienes `CMS Verification successful`, el archivo está íntegro y lo firmó un PSC acreditado por la Secretaría de Economía. > **¿Por qué -ignore\_critical y -purpose any?** > > Las dos opciones se deben al perfil de los certificados del PSC, no a un problema del archivo. Sus > certificados marcan como crítica una extensión que OpenSSL no procesa, así que sin > `-ignore_critical` la verificación falla con `unhandled critical extension`. Con `-purpose any`, > OpenSSL no aplica su regla estricta sobre los usos declarados del certificado. Para revisar también que el certificado del PSC no esté revocado, compáralo con la lista de revocación (CRL) de la Secretaría de Economía: ```bash # 1) Extrae el certificado del PSC incluido en el archivo openssl cms -verify -inform DER -in sello.tst -noverify -binary -out tstinfo.der -certsout psc.pem # 2) Descarga la CRL y conviértela a PEM curl -O https://www.acr2se.economia.gob.mx/economia.crl openssl crl -inform DER -in economia.crl -out economia.pem # 3) Valida el certificado contra la raíz y la CRL: debe responder "psc.pem: OK" openssl verify -CAfile ACR2_SE.pem -crl_check -CRLfile economia.pem -ignore_critical psc.pem ``` **Fecha cierta** La fecha la asigna el PSC autorizado, no tu servidor ni Verificamex. **Sin documentos** Solo viaja la huella SHA-256; el contenido del archivo nunca se envía. **Estándar RFC 3161** Los archivos se pueden validar con cualquier herramienta compatible, como OpenSSL. **Solo pagas lo emitido** Si el PSC no emite el archivo, no se descuentan tokens.