Cómo se integra una firma en un PDF
ISO 32000-2 §12.8 Spec: ETSI EN 319 142-1 ETSI EN 319 142-1 Spec: RFC 5652 RFC 5652 Evidence: Standard-backed
De un vistazo
Sección titulada «De un vistazo»Una firma PDF no envuelve el archivo. Está incrustada dentro de él: consta de un diccionario que identifica la firma y de un resumen calculado sobre un rango declarado de bytes que omite deliberadamente el propio valor de la firma. Esta página explica ese mecanismo y, con la misma importancia, lo que no promete.
Por qué importa
Sección titulada «Por qué importa»«El documento está firmado» es una afirmación sobre la que se toman decisiones. Se asocia a un pago, a una aprobación o a una obligación legal. Si no se sabe con precisión qué bytes cubre una firma, no se puede afirmar qué prueba realmente un resultado válido. Un PDF puede llevar una firma perfectamente válida y aun así mostrar a quien lo lee contenido que el firmante nunca vio, porque ese contenido se añadió después de firmar, en una zona sobre la que la firma nunca se pronunció. Saber dónde empieza y dónde termina la autoridad de la firma es la diferencia entre una decisión defendible y una optimista.
La versión breve
Sección titulada «La versión breve»- Una firma PDF reside en un diccionario de firma y en un campo de firma dentro del documento, no en un sobre externo.
- Los bytes firmados se declaran mediante la matriz
ByteRange: dos segmentos(offset, length)que, juntos, cubren todo el archivo salvo el valor hexadecimal de la firma que contiene la entradaContents. - El resumen de esos dos segmentos concatenados es lo que realmente protege la firma criptográfica.
- Cualquier cosa añadida más tarde en una revisión nueva queda fuera del rango de bytes original. La firma original sigue siendo válida; nunca afirmó nada sobre los bytes nuevos.
- Una firma de aprobación y una de certificación difieren en su alcance: la certificación (DocMDP) restringe qué cambios posteriores se permiten; la aprobación no.
Cómo lo aborda NextPDF
Sección titulada «Cómo lo aborda NextPDF»NextPDF construye la firma tal como lo prevé el formato, en un orden fijo, para que el rango de bytes sea exacto y no aproximado.
Cuando el motor escribe una firma, primero reserva una ranura de tamaño fijo para el
valor Contents y escribe un marcador de posición ByteRange de ancho fijo. Después
espera a que el documento completo esté escrito, incluida la tabla de referencias cruzadas y
el marcador de fin de archivo. Solo entonces calcula los dos desplazamientos reales,
los reescribe en el marcador de posición sin desplazar ningún byte, calcula el resumen de los dos
segmentos y coloca el objeto CMS resultante en la ranura reservada. El
marcador de posición se rellena con ceros hasta una longitud constante precisamente para que insertar los
números reales no pueda mover los bytes que se están resumiendo. Este es el único orden
que produce una firma coherente consigo misma. El motor trata cualquier fallo en
esta secuencia como un error grave, no como un recurso silencioso.
El propio objeto de firma, para el perfil PDF 2.0, es una estructura CMS
SignedData desacoplada. El diccionario PDF indica dónde y cómo; el CMS
aporta el quién y la prueba criptográfica.
- Step 1 of 4: ISO 32000-2 §12.8.1 — ByteRange digest & signature dictionary
- Step 2 of 4: ISO 32000-2 §12.8.3.3 — ETSI.CAdES.detached SubFilter
- Step 3 of 4: ETSI EN 319 142-1 PAdES baseline profile
- Step 4 of 4: RFC 5652 CMS SignedData in Contents
Qué dice la evidencia
Sección titulada «Qué dice la evidencia» Evidence: Standard-backed El mecanismo lo define
Spec: ISO 32000-2, §12.8.1 ISO 32000-2 §12.8.1 . Un resumen de rango de bytes se
calcula sobre un rango de bytes indicado por la entrada ByteRange. Ese rango
debe abarcar el archivo entero, incluido el diccionario de firma pero excluido
el valor de la firma: la entrada Contents. ByteRange es una matriz de
pares de enteros: desplazamiento inicial y longitud. Los rangos discontinuos se
usan precisamente para que el resumen pueda omitir el propio valor de la firma.
Para el perfil PDF 2.0, Spec: ISO 32000-2, §12.8.3.3 ISO 32000-2 §12.8.3.3 especifica que, cuando el SubFilter es ETSI.CAdES.detached, el valor Contents es un objeto CMS SignedData codificado en DER, la misma estructura que
Spec: RFC 5652 RFC 5652 define —y el perfil PAdES de ese objeto
es el que describe Spec: ETSI EN 319 142-1 ETSI EN 319 142-1 .
El alcance no es igual en todas las firmas. Spec: ISO 32000-2, §12.7.4.5 ISO 32000-2 §12.7.4.5 define el permiso MDP: un valor de 0 convierte la firma en una firma de aprobación, mientras que los valores 1–3 la convierten en una firma de certificación que restringe qué modificaciones posteriores mantienen el documento conforme. Es el mismo mecanismo de rango de bytes, pero con una promesa distinta sobre el futuro.
El motor de NextPDF implementa exactamente esto: un marcador de posición ByteRange de ancho fijo, el resumen concatenado de dos segmentos y un objeto CMS desacoplado en una ranura Contents reservada, que se finaliza solo después de que el archivo esté completo.
Ejemplo práctico
Sección titulada «Ejemplo práctico»Rara vez se construye a mano un ByteRange. La finalidad del ejemplo es mostrar la forma del resultado para que sea reconocible al inspeccionar un archivo firmado.
<?php
declare(strict_types=1);
use NextPDF\Security\Signature\ByteRangeCalculator;
// Offsets the engine knows only after the whole PDF is written:// $contentsStart — byte just before the '<' of the hex signature// $contentsEnd — byte just after the '>' that closes it// $fileLength — total file size in bytes$range = ByteRangeCalculator::calculate( contentsStart: $contentsStart, contentsEnd: $contentsEnd, fileLength: $fileLength,);// $range === [0, $contentsStart, $contentsEnd, $fileLength - $contentsEnd]// Segment 1: file start → just before the signature value// Segment 2: just after the signature value → end of file// The signature value itself is the gap. It is never hashed.
$signedMessage = ByteRangeCalculator::extractSignedData($pdfBytes, $range);// $signedMessage is segment 1 concatenated with segment 2 — exactly the// bytes the cryptographic digest is computed over.El hueco entre los dos segmentos es el valor de la firma. No puede formar parte de su propio resumen; por eso el rango se compone de dos piezas y no de una.
Idea equivocada habitual
Sección titulada «Idea equivocada habitual»La trampa consiste en creer que una firma válida significa que todo el archivo que se está viendo es lo que se firmó. No es así. Significa que los bytes que hay dentro del rango declarado están intactos. Una revisión posterior puede añadir contenido de forma legítima —una segunda firma, datos de formulario, material de validación— fuera de ese rango. La primera firma sigue siendo válida y no dice nada sobre la adición. Un visor correcto indica que una firma cubre «el documento tal como existía al firmarlo», no «cada byte en pantalla». Tratar ambas cosas como equivalentes es la forma en que un documento firmado puede adquirir contenido sin firmar que parece firmado.
Límites y fronteras
Sección titulada «Límites y fronteras»Esta página explica la estructura, no la confianza. Un
ByteRange bien formado y el objeto CMS indican que los bytes están intactos y qué clave los firmó.
Por sí solos, no indican si esa clave pertenece a quien se
cree, si su certificado era válido al firmar o si fue revocado
más tarde. Eso corresponde a la ruta de certificación y a la revocación, que se tratan en
Validar una firma correctamente.
Esta página tampoco determina cuándo ocurrió la firma mediante una autoridad
independiente. Una hora de firma declarada por el propio firmante no es una hora de confianza:
véase Marcas de tiempo y hora de confianza.
NextPDF construye la estructura aquí descrita; los certificados, las anclas de confianza
y la autoridad de sellado de tiempo los aporta su despliegue, no el motor.
Lo que el motor ofrece, por nivel, es la capacidad de construir la estructura:
| Edition | Availability |
|---|---|
| Core | PAdES B-B: el diccionario de firma, el ByteRange de ancho fijo y el objeto CMS SignedData desacoplado descrito en esta página. |
| Pro | Añade PAdES B-T —una marca de tiempo de confianza sobre el valor de la firma— sobre la misma estructura. |
| Enterprise | Añade los perfiles a largo plazo (B-LT, B-LTA): material de validación incrustado y marcas de tiempo de documento construidas sobre la misma base de rango de bytes. |
Documentos relacionados
Sección titulada «Documentos relacionados»- Actualizaciones incrementales y por qué importan: por qué añadir, en lugar de reescribir, mantiene intacto el rango de bytes de la primera firma.
- Perfiles de base PAdES: qué se construye sobre esta estructura y qué perfil exige cada obligación.
- Validación a largo plazo: cómo se incrusta la evidencia de validación para que una firma siga siendo verificable durante años.
Glosario
Sección titulada «Glosario»- Diccionario de firma: el diccionario PDF que identifica el gestor de firma, el
SubFilter, elByteRangey el valorContents. ByteRange: una matriz de pares de enteros(offset, length)que declara los bytes exactos que cubre el resumen de la firma.Contents: la entrada hexadecimal que contiene el valor de la firma (para PDF 2.0, un objeto CMSSignedDatadesacoplado); queda excluida de su propio resumen.- CMS
SignedData: estructura de Cryptographic Message Syntax (RFC 5652) que transporta el certificado del firmante y los bytes de la firma. - PAdES: PDF Advanced Electronic Signatures, el perfil ETSI de firmas CMS para PDF, definido en la serie ETSI EN 319 142.
- Firma de aprobación: una firma con permiso
MDP0; afirma el contenido sin restringir cambios posteriores. - Firma de certificación: una firma con un permiso DocMDP (
MDP1–3) que limita qué modificaciones posteriores mantienen el documento conforme.