Contrats / Signature
Le domaine de la signature regroupe six contrats. Ils définissent comment produire une signature CMS, appliquer un horodatage RFC 3161, signer avec une clé matérielle et activer la validation à long terme. Le core publie ces contrats ; les éditions Pro et Enterprise fournissent les implémentations de production.
Installation
Section intitulée « Installation »composer require nextpdf/core:^3Vue d’ensemble conceptuelle
Section intitulée « Vue d’ensemble conceptuelle »Une signature numérique PDF est une structure CMS SignedData stockée dans le dictionnaire de signature. L’entrée Contents contient la structure encodée en DER. L’entrée ByteRange indique les plages d’octets couvertes par l’empreinte. L’empreinte couvre tout le fichier et exclut la valeur de signature elle-même — voir ISO 32000-2 §12.8.1. La structure CMS suit la RFC 5652 §5.1 : une séquence composée de la version, des algorithmes d’empreinte, du contenu encapsulé et des informations sur le signataire.
SignerInterface est le contrat du core. Il produit le CMS SignedData pour une plage d’octets, applique un horodatage à une valeur de signature et indique s’il prend en charge la validation à long terme. Il couvre les niveaux de référence PAdES de B-B à B-LTA, tels que définis dans ETSI EN 319 142. Chaque niveau supérieur ajoute du contenu. B-B contient la signature de base. B-T ajoute un horodatage de signature. B-LT ajoute des données de révocation. B-LTA ajoute un horodatage d’archivage.
HsmSignerInterface signe à l’aide d’une clé conservée dans un module matériel de sécurité (HSM). La clé privée ne quitte pas la frontière matérielle. Le contrat renvoie le certificat du signataire et la chaîne de certificats au format DER, afin que la couche CMS puisse construire la structure. DeferredSignerInterface étend SignerInterface pour la signature asynchrone. L’appelant soumet les données, reçoit un identifiant de tâche, suit l’avancement, puis récupère le résultat. Utilise-le lorsqu’un HSM distant ou un service de clés cloud ne renvoie pas le résultat immédiatement.
TimestampProviderInterface demande un jeton d’horodatage RFC 3161. Le protocole repose sur un échange requête-réponse avec une autorité d’horodatage — voir RFC 3161 §2.4. Le messageImprint du jeton est une empreinte de la valeur de signature — RFC 3161 §2.4.2. LtvManagerInterface active la validation à long terme. Il collecte la chaîne de certificats, récupère les réponses OCSP et CRL, construit le Document Security Store et ajoute un horodatage de document pour B-LTA. CryptoPolicyInterface contrôle les algorithmes de hachage, de signature et de chiffrement, ainsi que les robustesses de clé, autorisés avant l’exécution d’une opération cryptographique.
Surface de l’API
Section intitulée « Surface de l’API »| Type | Nature | Membres clés | Stabilité | Depuis |
|---|---|---|---|---|
SignerInterface | interface | sign(string): SignatureResult, timestamp(string): string, supportsLtv(): bool | stable | 1.0.0 |
HsmSignerInterface | interface | sign(string, string): string, getCertificateDer(), getCertificateChainDer(), getPublicKeyAlgorithm() | stable | 1.0.0 |
DeferredSignerInterface | interface | submitForSigning(string): string, retrieveSignature(string), isComplete(string) (extends SignerInterface) | expérimental | 3.0.0 |
TimestampProviderInterface | interface | getTimestamp(string): string | expérimental | 3.0.0 |
LtvManagerInterface | interface | enableLtv(...), addDocumentTimestamp(...) | stable | 1.10.0 |
CryptoPolicyInterface | interface | isHashAlgorithmAllowed(), isSignatureAlgorithmAllowed(), isEncryptionAlgorithmAllowed(), isKeyStrengthAllowed(), getPreferredHashAlgorithm(), getName() | stable | 1.9.0 |
SignerInterface::sign() renvoie un NextPDF\Security\Signature\SignatureResult. La propriété publique $cmsSignedData contient le CMS encodé en DER. La propriété publique $digestHex contient l’empreinte SHA-256. La propriété publique $timestampToken contient le jeton TSA facultatif. Les accesseurs sont toHex() / toHexPadded(int) / getSize() / hasTimestamp(). HsmSignerInterface::sign() renvoie des octets encodés en DER pour RSA et des octets r‖s bruts pour ECDSA. L’argument d’algorithme utilise les identifiants OpenSSL.
Exemple de code — Démarrage rapide
Section intitulée « Exemple de code — Démarrage rapide »<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;
/** * Sign a byte range with any SignerInterface implementation. * * @param SignerInterface $signer A core or Premium signer. * @param string $byteRange The PDF byte range to sign. * * @return string Hex-encoded CMS SignedData for the PDF /Contents field. */function signByteRange(SignerInterface $signer, string $byteRange): string{ $result = $signer->sign($byteRange);
return $result->toHex();}SignerInterface::sign() renvoie un SignatureResult. toHex() produit la chaîne hexadécimale que le writer place dans le champ /Contents ; les octets DER bruts sont exposés par la propriété publique $cmsSignedData. La fonction dépend du contrat, pas d’une classe concrète. Un signataire de test du core comme un signataire HSM Premium peuvent tous deux satisfaire ce contrat.
Exemple de code — Production
Section intitulée « Exemple de code — Production »<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\CryptoPolicyInterface;use NextPDF\Contracts\SignerInterface;use NextPDF\Contracts\TimestampProviderInterface;use NextPDF\Exception\NextPdfException;use Psr\Log\LoggerInterface;
final readonly class TimestampedSigningService{ public function __construct( private SignerInterface $signer, private TimestampProviderInterface $timestamps, private CryptoPolicyInterface $policy, private LoggerInterface $logger, ) {}
/** * Sign a byte range, then timestamp the CMS structure. * * @param string $byteRange The PDF byte range to sign. * * @return array{cms: string, digest: string, tst: string} */ public function sign(string $byteRange): array { if (!$this->policy->isHashAlgorithmAllowed($this->policy->getPreferredHashAlgorithm())) { throw new \LogicException('Preferred hash rejected by crypto policy.'); }
try { $signature = $this->signer->sign($byteRange); $token = $this->timestamps->getTimestamp($signature->cmsSignedData);
return [ 'cms' => $signature->toHex(), 'digest' => $signature->digestHex, 'tst' => $token, ]; } catch (NextPdfException $e) { $this->logger->error('Signing failed', [ 'policy' => $this->policy->getName(), 'error' => $e->getMessage(), ]);
throw $e; } }}Le service injecte trois contrats. La politique cryptographique est consultée avant l’opération de signature. SignatureResult expose les octets CMS sur la propriété publique $cmsSignedData, l’empreinte SHA-256 sur $digestHex, et toHex() pour la chaîne hexadécimale /Contents. Le fournisseur d’horodatage reçoit les octets CMS et renvoie un jeton encodé en DER. Le bloc catch journalise le nom de la politique et relance l’exception. Il ne masque jamais l’échec.
Cas limites et pièges
Section intitulée « Cas limites et pièges »- L’empreinte de la plage d’octets doit exclure la valeur de signature. Une empreinte qui couvre l’entrée
Contentsproduit une signature qui ne pourra jamais être vérifiée — ISO 32000-2 §12.8.1. SignerInterface::supportsLtv()indique une capacité, pas un état. Un signataire peut prendre en charge la validation à long terme et tout de même produire une signature B-B lorsqu’aucun service d’horodatage n’est configuré.DeferredSignerInterface::retrieveSignature()renvoienulljusqu’à ce que la tâche se termine. Interroge d’abordisComplete()pour éviter de transférer la charge utile à chaque vérification. La récupération est idempotente dès qu’un résultat existe.LtvManagerInterface::addDocumentTimestamp()doit être exécuté après l’écriture du Document Security Store. L’appeler en premier produit une structure B-LTA non valide.CryptoPolicyInterfacerenvoietruepour tout algorithme lorsqu’aucune politique n’est définie. Dans un environnement réglementé, définis une politique explicite ; ne te fie pas à la valeur par défaut ouverte.HsmSignerInterface::getCertificateChainDer()exclut le certificat du signataire. UtilisegetCertificateDer()pour le certificat feuille du signataire et la méthode dédiée à la chaîne pour les intermédiaires.
Performances
Section intitulée « Performances »Le coût de la signature est dominé par l’opération cryptographique et par tout aller-retour réseau, pas par le contrat. Une signature logicielle locale se compte en quelques millisecondes à un chiffre. Une signature HSM ajoute l’aller-retour vers le périphérique. Un horodatage ajoute un aller-retour réseau vers l’autorité d’horodatage. La validation à long terme ajoute une récupération OCSP ou CRL par certificat de la chaîne. Le performance_budget de 1500 ms en temps horloge couvre une seule signature horodatée avec une TSA distante sur une connexion déjà chaude. Face à un point de terminaison de révocation lent, la validation à long terme dépasse ce budget et devrait s’exécuter en dehors du chemin de la requête. Le profil de reproductibilité est structural, pas bitwise. Un horodatage intègre l’instant de signature, si bien que deux exécutions diffèrent par les octets d’horodatage tandis que la structure du document reste identique.
Notes de sécurité
Section intitulée « Notes de sécurité »Les contrats de signature constituent la principale frontière cryptographique du moteur ; le modèle de menace est donc explicite. La protection des clés est la première préoccupation : HsmSignerInterface conserve la clé privée à l’intérieur de la frontière matérielle, et le contrat n’expose jamais de matériel de clé. La rétrogradation d’algorithme est la deuxième : CryptoPolicyInterface bloque les empreintes faibles et les clés courtes avant l’opération, ce qui permet à un déploiement d’imposer un profil FIPS 140-3 ou eIDAS sans forker le moteur. La confiance dans l’horodatage est la troisième : un jeton RFC 3161 n’est digne de confiance que dans la mesure où l’autorité d’horodatage l’est, le contrat du fournisseur est donc injectable et un déploiement épingle sa propre autorité. La validation à long terme est la quatrième : le matériel de révocation est récupéré au moment de la signature et stocké dans le Document Security Store, de sorte que la vérification survive à l’expiration du certificat. Traite toute entrée du signataire comme non fiable. La plage d’octets est calculée par le moteur, jamais acceptée de l’appelant. Cette page est marquée export_control_class: legal-review-required car les contrats régissent la signature cryptographique. La prose paraphrase toutes les sources normatives et ne les cite pas directement, conformément à l’hygiène de citation.
Conformité
Section intitulée « Conformité »| Affirmation | Standard | Clause | Preuve |
|---|---|---|---|
La valeur de signature est stockée avec un encodage DER dans l’entrée Contents du dictionnaire de signature, sous forme de CMS SignedData ou de TimeStampToken. | ISO 32000-2 | §12.8.1 | |
L’empreinte est calculée sur la plage d’octets définie par le tableau ByteRange et exclut la valeur de signature. | ISO 32000-2 | §12.8.1 | , |
| Le matériel de validation à long terme est transporté dans le Document Security Store avec des entrées VRI, OCSP, CRL et de certificats. | ISO 32000-2 | §12.8.4.3 | , |
| La validation à long terme PAdES place les données de validation dans les dictionnaires DSS et VRI. | ETSI EN 319 142-2 | §6.3 | , |
Un jeton d’horodatage RFC 3161 lie une empreinte de la valeur de signature via messageImprint, dans un échange requête-réponse avec une TSA. | RFC 3161 | §2.4.2, §2.4 | , |
| La séquence CMS SignedData porte la version, les algorithmes d’empreinte, le contenu encapsulé et les informations sur le signataire. | RFC 5652 | §5.1 |
Toutes les clauses sont paraphrasées. NextPDF ne reproduit pas le texte normatif. Consulte les standards publiés pour le libellé faisant autorité.
Contexte commercial
Section intitulée « Contexte commercial »Le core publie et fige les contrats de signature. Les implémentations de production derrière HsmSignerInterface, LtvManagerInterface et le signataire différé sont fournies dans les éditions Pro et Enterprise, y compris l’intégration matérielle PKCS#11 ainsi que PAdES B-LT et B-LTA. Le core les résout au moment de l’exécution avec class_exists() et les convertit vers le contrat, de sorte que le moteur open source ne porte aucune dépendance commerciale et que l’API ne change pas lors de la mise à niveau.
Voir aussi
Section intitulée « Voir aussi »- Contrats : 41 interfaces publiques (SPI) — la vue d’ensemble du SPI et les niveaux de stabilité.
- Contrats / Politique de sécurité — contrôle des algorithmes et des clés par
CryptoPolicyInterface. - Contrats / Extraction — application de PDF/A qui va de pair avec l’archivage signé.
- Sécurité — surface d’implémentation du chiffrement et de la signature.
- Audit — journalisation d’audit du nom de la politique et des événements de signature.
- Exception — hiérarchie
NextPdfExceptionlevée par les signataires.