Enterprise edición
Vinculación de confianza ASiC
De un vistazo
Sección titulada «De un vistazo»Un contenedor ASiC agrupa archivos firmados junto con las firmas que los protegen. La pregunta difícil no es «¿la firma computa?», sino «¿quién respalda al firmante?». NextPDF\Enterprise\Security\Asic\AsicTrustBinder responde exactamente a esa pregunta. Le entregas el certificado de firma tomado de la firma del contenedor, una lista de confianza y un tiempo de validación. Responde con un AsicTrustBindingResult: un veredicto de confianza/no confianza, la versión del paquete de anclas frente a la que decidió y motivos legibles por máquina. Cada rechazo nombra su causa, de modo que la evidencia de auditoría se escribe sola.
Un límite es deliberado y conviene señalarlo desde el principio. Esta API no analiza contenedores ASiC. Tus herramientas abren el contenedor y extraen el certificado de firma; NextPDF es responsable de la decisión de confianza.
Disponibilidad y licencias
Sección titulada «Disponibilidad y licencias»Esta capacidad se distribuye en NextPDF Enterprise (nextpdf/enterprise) y se activa con un sobre de licencia de nivel Enterprise. Un despliegue sin ese derecho no carga las clases de la capacidad. Compara ediciones y obtén una licencia.
Instalación
Sección titulada «Instalación»composer require nextpdf/enterpriseLa activación requiere tu sobre de licencia Enterprise. Consulta Instalar y autenticar. Las clases de esta página residen bajo NextPDF\Enterprise\Security\Asic y NextPDF\Enterprise\Security\Tsl.
Visión conceptual
Sección titulada «Visión conceptual»ASiC (Associated Signature Containers, ETSI EN 319 162-1) empaqueta archivos de datos y firmas en un único archivo comprimido. Un contenedor ASiC baseline incrusta únicamente firmas baseline CAdES o XAdES. Una firma baseline CAdES lleva su certificado de firma dentro de SignedData.certificates, de modo que se espera que un verificador lo extraiga cuando la firma está bien formada y las herramientas de contenedor la admiten, a partir de la firma del contenedor. Ese certificado extraído es la entrada de esta API.
La fuente de confianza es una lista de confianza (TSL) ETSI TS 119 612: un documento XML firmado que enumera los proveedores de servicios de confianza y sus certificados de servicio. NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider convierte un TslDocument analizado en un paquete de anclas. Solo los servicios que están a la vez en estado granted y del tipo de servicio CA/QC siembran el conjunto de anclas. El paquete lleva una cadena de versión derivada del número de secuencia de la TSL y del territorio, más un resumen de integridad SHA-256.
Antes de cualquier comparación de anclas se ejecutan dos controles fail-closed:
- Frescura de la TSL. Una lista de confianza cuyo instante
NextUpdateya ha pasado debe descartarse como expirada.AsicTrustBinder::verify()comprueba la frescura en el tiempo de validación suministrado antes de derivar una sola ancla. Una lista obsoleta, o un valorNextUpdatesin un designador UTC explícito, lanzaTslParseException. - Periodo de validez del firmante. La validación de ruta de RFC 5280 exige que el periodo de validez del certificado incluya el tiempo de validación. Una firma criptográficamente íntegra cuyo certificado estaba expirado, o aún no válido, en ese momento se rechaza con un código de motivo preciso.
Solo entonces el vinculador contrasta el certificado de firma con cada ancla. Una coincidencia produce trusted: true con el motivo anchor_signature_match. La ausencia de coincidencia produce trusted: false con el motivo no_anchor_chain.
Por qué funciona así
Sección titulada «Por qué funciona así»La decisión de diseño que sostiene todo es una separación estricta entre la mecánica del contenedor y la decisión de confianza, con la decisión de confianza obligada a ser explícita respecto al tiempo. Los formatos de contenedor varían (ASiC-S, ASiC-E, cargas CAdES o XAdES), pero la pregunta de confianza es un núcleo invariante: ¿encadena este certificado con un ancla de una lista de confianza fresca en un instante declarado? Mantener ese núcleo libre del análisis de ZIP y XML lo mantiene lo bastante pequeño para probarlo de forma exhaustiva y fallar cerrado en cada control. El mismo razonamiento prohíbe un now implícito por defecto: el tiempo de validación cambia el veredicto, así que quien llama debe hacerse cargo de él. La frescura se comprueba dentro de la propia ruta de derivación de anclas, no en un colaborador opcional, de modo que ninguna ruta productora puede omitirla.
Contexto de diseño: Cómo una firma digital demuestra quién firmó.
Superficie de la API
Sección titulada «Superficie de la API»AsicTrustBinder
Sección titulada «AsicTrustBinder»La construcción toma el proveedor de anclas que convierte listas de confianza en paquetes de anclas.
public function __construct( private readonly TslTrustAnchorProvider $anchorProvider,) {}El punto de entrada principal verifica un certificado de firmante frente a una lista de confianza:
public function verify( string $signerCertPem, TslDocument $tsl, DateTimeInterface $validationTime,): AsicTrustBindingResult$signerCertPem— cadena PEM no vacía: el certificado de firma de la firma ASiC.$tsl— la lista de confianza analizada y autenticada.$validationTime— el instante que debe incluir el periodo de validez del certificado del firmante. No hay valor por defecto.
Lanza o falla con: NextPDF\Enterprise\Security\Tsl\TslParseException cuando la TSL está obsoleta (NextUpdate pasado), cuando NextUpdate no es un valor UTC canónico, o cuando la lista no contiene servicios CA/QC activos. Los firmantes no confiables no lanzan; devuelven un resultado con trusted: false y un código de motivo.
Para cargas de trabajo por lotes, verifica frente a un paquete preconstruido:
public function verifyAgainstBundle( string $signerCertPem, EnterpriseCaTrustAnchorBundle $bundle, DateTimeInterface $validationTime,): AsicTrustBindingResultLanza o falla con: ninguna excepción propia; cada resultado es un AsicTrustBindingResult. Obtén el paquete de TslTrustAnchorProvider::buildBundle() — no lo construyas a mano.
TslTrustAnchorProvider
Sección titulada «TslTrustAnchorProvider»public function buildBundle(TslDocument $tsl, DateTimeImmutable $now): EnterpriseCaTrustAnchorBundleLanza o falla con: TslParseException si la TSL está obsoleta, si su NextUpdate no es un valor UTC canónico, o si no tiene servicios CA/QC activos.
AsicTrustBindingResult
Sección titulada «AsicTrustBindingResult»public function __construct( public bool $trusted, public string $anchorBundleVersion, public array $reasons,) {}$reasons es un list<non-empty-string> de códigos legibles por máquina. $anchorBundleVersion registra el conjunto de anclas utilizado, con la forma tsl-<territory>-seq<N> (por ejemplo tsl-eu-seq42).
| Código de motivo | Significado |
|---|---|
anchor_signature_match | El certificado del firmante se verifica frente a un ancla derivada de la TSL. Confiable. |
no_anchor_chain | Ningún ancla del paquete verifica el certificado del firmante. No confiable. |
signer_cert_expired | El tiempo de validación cae después del notAfter del certificado. No confiable. |
signer_cert_not_yet_valid | El tiempo de validación cae antes del notBefore del certificado. No confiable. |
cannot_parse_signer_cert | El PEM suministrado no se analiza como certificado X.509. No confiable. |
Ejemplo de código — Inicio rápido
Sección titulada «Ejemplo de código — Inicio rápido»Tus herramientas de contenedor ya han extraído el certificado de firma. Vincúlalo a una lista de confianza de un estado miembro que hayas obtenido y autenticado (consulta Listas de confianza).
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Asic\AsicTrustBinder;use NextPDF\Enterprise\Security\Tsl\TslParseException;use NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider;use NextPDF\Enterprise\Security\Tsl\TslXmlParser;
// Extracted by YOUR tooling from META-INF/signature.p7s or signatures.xml.$signerCertPem = (string) file_get_contents(__DIR__ . '/asic-signer.pem');
// A trusted list you have already fetched and authenticated.$tslXml = (string) file_get_contents(__DIR__ . '/member-state-tsl.xml');
$binder = new AsicTrustBinder(new TslTrustAnchorProvider());
try { $tsl = (new TslXmlParser())->parse($tslXml);
$result = $binder->verify( signerCertPem: $signerCertPem, tsl: $tsl, validationTime: new DateTimeImmutable('2026-07-03T12:00:00Z'), );} catch (TslParseException $e) { // Fail closed: stale TSL, malformed NextUpdate, or no active CA/QC services. fwrite(STDERR, 'Trusted list rejected: ' . $e->getMessage() . PHP_EOL); exit(1);}
echo $result->trusted ? "TRUSTED\n" : "NOT TRUSTED\n";echo 'Anchors: ' . $result->anchorBundleVersion . "\n";echo 'Reasons: ' . implode(', ', $result->reasons) . "\n";Salida esperada para un firmante emitido por un servicio CA/QC listado:
TRUSTEDAnchors: tsl-eu-seq42Reasons: anchor_signature_matchEjemplo de código — Producción
Sección titulada «Ejemplo de código — Producción»Deriva el paquete de anclas una vez por lista de confianza y luego verifica muchos firmantes de contenedores frente a él. Una única TSL obsoleta o inutilizable hace fallar cerrado todo el lote; los problemas de firmantes individuales se manifiestan por contenedor.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Asic\AsicTrustBinder;use NextPDF\Enterprise\Security\Asic\AsicTrustBindingResult;use NextPDF\Enterprise\Security\Tsl\TslDocument;use NextPDF\Enterprise\Security\Tsl\TslParseException;use NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider;use NextPDF\Enterprise\Security\Tsl\TslXmlParser;
/** * @param array<string, non-empty-string> $signerPemsByContainer PEM per container path. * @return array<string, AsicTrustBindingResult> * @throws TslParseException When no anchor set can be derived from the TSL. */function bindBatch( TslDocument $tsl, array $signerPemsByContainer, DateTimeImmutable $validationTime,): array { $provider = new TslTrustAnchorProvider();
// Derive the anchor set ONCE; a throw here means the trusted list itself // is unusable at this validation time. $bundle = $provider->buildBundle($tsl, $validationTime);
$binder = new AsicTrustBinder($provider);
$results = []; foreach ($signerPemsByContainer as $container => $signerPem) { $results[$container] = $binder->verifyAgainstBundle( signerCertPem: $signerPem, bundle: $bundle, validationTime: $validationTime, ); }
return $results;}
$tsl = (new TslXmlParser())->parse( (string) file_get_contents(__DIR__ . '/member-state-tsl.xml'),);
$signerPems = [ 'invoice-2026-06.asice' => (string) file_get_contents(__DIR__ . '/signer-a.pem'), 'tender-2019.asice' => (string) file_get_contents(__DIR__ . '/signer-b.pem'),];
try { $results = bindBatch( tsl: $tsl, signerPemsByContainer: $signerPems, validationTime: new DateTimeImmutable('now', new DateTimeZone('UTC')), );} catch (TslParseException $e) { // Fail closed for the WHOLE batch: no trustworthy anchor set exists. fwrite(STDERR, 'Anchor derivation failed: ' . $e->getMessage() . PHP_EOL); exit(1);}
foreach ($results as $container => $result) { printf( "%s => %s (%s; anchors %s)\n", $container, $result->trusted ? 'trusted' : 'rejected', implode(',', $result->reasons), $result->anchorBundleVersion, );}Salida esperada cuando un certificado de firmante ha expirado:
invoice-2026-06.asice => trusted (anchor_signature_match; anchors tsl-eu-seq42)tender-2019.asice => rejected (signer_cert_expired; anchors tsl-eu-seq42)Casos límite y trampas
Sección titulada «Casos límite y trampas»- El tiempo de validación es obligatorio y decisivo. No hay un
nowimplícito por defecto. Una firma que verificaba en 2019 informasigner_cert_expiredcuando la validas en un instante de 2026 posterior anotAfter. Para material histórico, pasa el tiempo que respalde tu evidencia (por ejemplo un tiempo de prueba de existencia), no el reloj de pared. - Una TSL obsoleta lanza; no es un veredicto de «no confiable». Un
TslParseExceptiondeverify()obuildBundle()significa que la fuente de confianza es inutilizable. Trátalo como un fallo operativo: refresca la lista, no lo registres como un rechazo de firmante. - Las anclas se prueban como emisores directos. Cada ancla se prueba como el certificado que firmó el certificado del firmante. Las TSL de los estados miembros de la UE listan los certificados de servicio CA/QC emisores, de modo que los certificados cualificados de entidad final suelen coincidir directamente. Un firmante emitido por una CA intermedia que no sea a su vez un servicio CA/QC activo listado produce
no_anchor_chain. - La derivación de anclas filtra con dureza. Los servicios que están retirados, o de cualquier tipo distinto de CA/QC, nunca se convierten en anclas. Una lista cuyo conjunto CA/QC activo está vacío lanza en lugar de producir un paquete vacío.
NextUpdatedebe ser UTC canónico. Un valor sin un designadorZexplícito o un desplazamiento numérico se rechaza fail-closed, nunca se reinterpreta en la zona horaria local del servidor.- La entrada malformada degrada con precisión. Un PEM que no se analiza devuelve
cannot_parse_signer_cert; un certificado aún no válido se distingue de uno expirado. - Registra
anchorBundleVersion. Nombra el conjunto exacto de anclas (tsl-<territory>-seq<N>) detrás de cada veredicto, que es lo que pedirá un auditor.
Notas de seguridad
Sección titulada «Notas de seguridad»- Fail-closed por construcción. La frescura se comprueba antes de derivar cualquier ancla. El control de validez del firmante se ejecuta antes de cualquier comparación de anclas. El material de confianza inutilizable lanza; los firmantes cuestionables se rechazan con motivos. Ninguna ruta degrada a un pase silencioso.
- La vinculación de confianza es una capa, no toda la validación. Esta API no verifica el valor de la firma CAdES sobre el contenido del contenedor, no comprueba la revocación (sin consulta CRL ni OCSP) y no autentica el propio documento TSL. Autentica la lista a través del flujo de listas de confianza primero (consulta Listas de confianza), verifica la firma criptográficamente con tus herramientas de firma y añade la comprobación de revocación según tu política.
- Elige el tiempo de validación de forma deliberada. El veredicto es una función del tiempo que pasas. Derívalo de evidencia fiable (una marca de tiempo cualificada, un registro de archivo), no de un reloj influenciable por un atacante.
- Las salidas de evidencia son deterministas.
trusted,anchorBundleVersionyreasonsson valores estables y legibles por máquina, aptos para registros de auditoría firmados.
Conformidad
Sección titulada «Conformidad»AsicTrustBinder admite flujos de trabajo alineados con ETSI EN 319 162-1 (contenedores ASiC baseline), ETSI EN 319 122-1 (firmas baseline CAdES) y ETSI TS 119 612 (listas de confianza), y aplica el control de periodo de validez de RFC 5280 en el tiempo de validación suministrado.
Admitir no es conformidad, y conformidad no es certificación. NextPDF implementa las comprobaciones que describe esta página; no ha sido certificado frente a estos estándares por ningún organismo, y usar esta API no hace por sí mismo que tu salida sea «cualificada» ni legalmente efectiva bajo eIDAS ni bajo ningún otro régimen. NextPDF no posee ninguna certificación y no otorga ninguna. Si un proceso de validación completo cumple un requisito legal o de contratación determinado es una decisión que corresponde a tus evaluadores.
Comportamiento en modo FIPS
Sección titulada «Comportamiento en modo FIPS»La vinculación de confianza realiza comprobaciones de firma de certificados X.509 en proceso; no se enruta a través del guardián del entorno de ejecución en modo FIPS de Enterprise, y activar el modo FIPS no cambia su comportamiento. No es un servicio criptográfico validado por FIPS, y no se reclama ninguna certificación FIPS 140. Los despliegues con obligaciones FIPS deberían delimitar esta API en consecuencia y consultar Política criptográfica FIPS 140-2/3.
Contrato de comportamiento
Sección titulada «Contrato de comportamiento»verify()deriva anclas únicamente de una TSL que sea fresca en el tiempo de validación suministrado; una lista obsoleta o malformada lanzaTslParseExceptionantes de que exista ancla alguna.- Las anclas se derivan exclusivamente de servicios de la TSL en estado granted con el tipo de servicio CA/QC; un conjunto activo vacío lanza.
- El periodo de validez del certificado del firmante debe incluir el tiempo de validación; las violaciones devuelven
signer_cert_expiredosigner_cert_not_yet_valid. - Cada resultado es un
AsicTrustBindingResultque llevatrusted,anchorBundleVersiony al menos un código de motivo; no hay veredicto sin motivo. - Los firmantes no confiables se devuelven, nunca se lanzan; el material de confianza inutilizable se lanza, nunca se devuelve como veredicto.
- El análisis del contenedor nunca ocurre dentro de esta API; las entradas son el PEM extraído, la lista de confianza y el tiempo de validación.
Alternativa en Core
Sección titulada «Alternativa en Core»NextPDF Core valida firmas PDF (CMS/PAdES) frente a anclas de confianza que fijas explícitamente mediante su contrato CaTrustAnchorBundle — consulta Seguridad en Core. Core no tiene ingesta de listas de confianza (TSL) ni vinculación de confianza específica de ASiC. Con Core en solitario, puedes mantener tu propio conjunto de anclas para la validación de firmas PDF; derivar anclas de una lista de confianza ETSI TS 119 612 y vincular a ellas los firmantes de contenedores ASiC requiere NextPDF Enterprise.
Límite de publicación
Sección titulada «Límite de publicación»Esta página documenta únicamente el comportamiento observable externamente y la superficie de API pública admitida. Las rutas de espacio de nombres internas, las clases auxiliares, las tablas de mecanismos, los nombres de archivo de runbook y los prefijos de tickets quedan fuera del alcance.
Véase también
Sección titulada «Véase también»- Listas de confianza — obtén, autentica y analiza la TSL que alimenta el proveedor de anclas.
- Verificación de firmas — la superficie de verificación Enterprise para firmas PDF.
- Política criptográfica FIPS 140-2/3 — la postura del modo FIPS de Enterprise.
- Cómo una firma digital demuestra quién firmó — contexto desde primeros principios.
- Validación a largo plazo — por qué importan el tiempo de validación y la evidencia preservada.