THotPDF.SignPDFWithPFX

THotPDF

 

Previous  Methods  AddPubKeyRecipient

Signs an existing PDF placeholder using a PFX / PKCS#12 file, building a CMS SignedData container and writing the signed PDF in one call.

 

Delphi syntax (file overload):

class function SignPDFWithPFX(

  const InputPDFPath: string;

  const OutputPDFPath: string;

  const PFXFilePath: string;

  const Password: AnsiString): boolean; overload; static;

 

Delphi syntax (stream overload):

class function SignPDFWithPFX(

  InputStream: TStream;

  OutputStream: TStream;

  const PFXFilePath: string;

  const Password: AnsiString): boolean; overload; static;

 

Description

SignPDFWithPFX is the end-to-end PFX signing entry point added in v2.119.27. The input PDF must already contain a signature placeholder emitted by THPDFPage.AddSignedSignatureField (or its PAdES wrapper) with subFilter adbe.pkcs7.detached. The method:

 

1. Loads the input PDF, locates the /ByteRange + /Contents sentinel placeholders, and patches /ByteRange with the actual byte offsets.

2. Loads the PFX file and decrypts it with the supplied password. PBES2 with PBKDF2-HMAC-SHA-256 + AES-256-CBC is supported (this is the default for PFX files exported by OpenSSL 3.0+, Windows 11+ certutil, and macOS Keychain Access). Legacy PBE-SHA1-3DES files raise a diagnostic; re-export with openssl pkcs12 -export ... -keypbe AES-256-CBC -certpbe AES-256-CBC.

3. Computes SHA-256 over the /ByteRange-covered document bytes and builds a CMS SignedData (RFC 5652) DER blob containing the X.509 certificate, the signed attributes (contentType + messageDigest + signingTime), and an RSA + SHA-256 signature over the SET-tagged signed attributes.

4. Hex-encodes the CMS DER, verifies it fits the /Contents budget reserved by AddSignedSignatureField (default 8 KB covers 1024 / 2048-bit RSA), and injects it into the placeholder.

5. Writes the patched bytes to the output path or stream.

 

Returns True on success. Raises EHPDFPFXError on a bad password, unsupported encryption profile, or malformed PFX; EHPDFCMSError when the input PDF lacks the expected placeholder or the CMS DER overflows the reserved /Contents budget; EHPDFRSAError on RSA key mismatch.

 

Typical workflow

 

Doc := THotPDF.Create(nil);

Doc.FileName := 'unsigned.pdf';

Doc.BeginDoc;

Doc.CurrentPage.AddSignedSignatureField(

  'Sig1', Rect(60, 60, 260, 90), 8192,

  'adbe.pkcs7.detached', 'Approved', 'Brussels', '', []);

Doc.EndDoc;

Doc.Free;

THotPDF.SignPDFWithPFX('unsigned.pdf', 'signed.pdf', 'mykey.pfx', 'mypassword');

 

Notes

The signature algorithm is RSA + SHA-256 (1.2.840.113549.1.1.1 + 2.16.840.1.101.3.4.2.1). The signer identifier is IssuerAndSerialNumber extracted from the X.509 certificate. The encapContentInfo is detached (eContent omitted). Signed attributes are sorted by ascending DER byte string per RFC 5652 ยง5.4 before being hashed.

 

For PAdES B-T / B-LT / B-LTA workflows that need RFC 3161 timestamps, DSS dictionaries, or document timestamp signatures, the producer-side helpers (AddPAdESSignatureField, AddPAdESDSSCertificate, AddDocumentTimestampSignature) still apply; SignPDFWithPFX itself emits a basic CMS-only signature (PAdES-B-B equivalent).

 

See also: AddSignedSignatureField, PreparePDFForSigning, InsertSignatureHex, AddPAdESSignatureField