* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD * @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE) * @link https://github.com/tecnickcom/tc-lib-pdf * * This file is part of tc-lib-pdf software library. */ // NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of // trusted paths that covers this package tree, so run the examples in place. To read assets // from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor // parameter (see E047_remote_resources_security.php). // NOTE: run make fonts in the project root to generate the dependencies and example fonts. require __DIR__ . '/../vendor/autoload.php'; define('K_PATH_FONTS', (string) realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts')); $pdf = new \Com\Tecnick\Pdf\Tcpdf( unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter, isunicode: true, subsetfont: false, compress: true, mode: \Com\Tecnick\Pdf\PdfConformance::None, objEncrypt: null, ); $pdf->setCreator('tc-lib-pdf'); $pdf->setAuthor('Nicola Asuni'); $pdf->setSubject('tc-lib-pdf example: 075'); $pdf->setTitle('External Signature Injection Workflow'); $pdf->setKeywords('TCPDF tc-lib-pdf example external signature remote pkcs7 byterange'); $pdf->setPDFFilename('E075_signed_external_signature_injection.pdf'); $pdf->enableDefaultPageContent(); $page = $pdf->addPage(['format' => 'A4']); $basefont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10); $pdf->page->addContent($basefont['out']); $pdf->setSignatureForExternalSigning([ 'cert_type' => 2, 'info' => [ 'ContactInfo' => 'https://github.com/tecnickcom/tc-lib-pdf', 'Location' => 'Remote signing service', 'Name' => 'External Signer', 'Reason' => 'Remote detached CMS signature injection demo', ], 'password' => '', 'privkey' => '', 'signcert' => '', ]); $sigPosX = 100.0; $sigPosY = 220.0; $sigWidth = 80.0; $sigHeight = 20.0; $pdf->setSignatureAppearance( posx: $sigPosX, posy: $sigPosY, width: $sigWidth, height: $sigHeight, page: $page['pid'], name: 'Remote Approval', ); // Custom /AP stream to make the signature widget visually obvious. $sigStamp = \gmdate('Y-m-d H:i:s') . ' UTC'; $sigTopY = $page['height'] - $sigHeight; // Build the signature appearance stream directly from HTML table markup. $sigAppearance = $basefont['out']; $sigTableHtml = <<
This example demonstrates a full remote-signing flow where the private key never lives in your
application. The signature field uses the ISO 32000-1 /adbe.pkcs7.detached sub-filter.
/Contents bytes using
setSignatureForExternalSigning() and setSignatureAppearance().getExternalSignaturePreparation('sha256') to receive:
/ByteRange,byte_range tuple,hash_base64) to your external provider,
such as HSM/KMS or gov.br signing API, and receive CMS/PKCS#7 detached signature bytes.applyExternalSignature(preparedPdf, byteRange, cmsSignature, encoding)
with encoding = binary|base64|hex to produce the final signed PDF bytes.To keep the example self-contained and offline, it injects a simulated CMS payload
(DEMO-REMOTE-CMS: followed by the raw digest) instead of calling a real signer. The injection
reuses the reserved /Contents placeholder without re-hashing the document, so the PDF proves
the ByteRange / placeholder / injection mechanics but is cryptographically invalid and will not pass
signature validation. applyExternalSignature() throws if the returned CMS is larger than the
reserved placeholder, so size the placeholder for your provider's real CMS.
save mode writes both prepared and signed files under target/.php examples/E075_external_signature_injection.php save or render.?mode=save or ?mode=render.