THotPDF.SignPDFWithPFX

THotPDF

 

Previous  Methods  AddPubKeyRecipient

Signs an existing PDF placeholder using a PFX / PKCS#12 file, deterministically selects one credential identity, builds a CMS SignedData container with its available certificate chain, and writes 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. Copies the input through a bounded 256 KB buffer, or reuses the same seekable readable/writable stream, locates the /ByteRange + /Contents placeholders, and seek-patches the fixed-width /ByteRange field with the actual byte offsets

2. Loads the PFX file and decrypts it with the supplied password. PBES2 accepts AES-128-CBC, AES-192-CBC, and AES-256-CBC with the default HMAC-SHA-1 or explicit HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512 PBKDF2 PRFs. An optional PBKDF2 keyLength must match the selected AES cipher, and legacy PBE-SHA1-3DES files remain supported for older certificate exports. Other encryption profiles raise a diagnostic with the offending OID

3. Pairs RSA, named-curve ECDSA, Ed25519, or Ed448 private keys with certificates by public-key material and exact RFC 2985 localKeyId values, then follows issuer / subject names and Authority Key Identifier / Subject Key Identifier extensions to preserve the available intermediate and root chain

4. Selects the signing scheme from the matched key, computes the required document digest, and builds a CMS SignedData (RFC 5652) DER blob containing the signer certificate, its matching chain without duplicate DER certificates, and signed attributes. RSA and ECDSA sign the attribute digest; Ed25519 and Ed448 sign the complete DER SET OF attributes in PureEdDSA mode. Ed25519 uses SHA-512 and Ed448 uses SHAKE256 with 512-bit output and id-shake256-len

5. 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

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

 

Returns True on success. Raises EHPDFPFXError on a bad password, unsupported encryption or private-key profile, malformed PFX, ambiguous identity, ambiguous issuer, or certificate-chain cycle; EHPDFCMSError when the input PDF lacks the expected placeholder, an optional EdDSA provider is unavailable, signing fails, 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');

 

Multi-identity PFX files

The convenience overload intentionally rejects a PFX that contains more than one matching certificate and private key. Call HPDFEnumeratePFXIdentities to inspect the deterministic identity list and its LocalKeyID and FriendlyName fields, or call HPDFParsePFXByLocalKeyID when only the selected key material is required

For end-to-end signing, initialize THPDFCMSSignOptions with HPDFCMSDefaultSignOptions, copy the selected exact octets into Options.PFXLocalKeyID, and call the HPDFCMSSignPDFStream overload that accepts those options. The selected leaf, available intermediate certificates, and available root are embedded automatically; caller-supplied Options.AdditionalCertsDER values are merged with exact DER deduplication

 

Notes

RSA and ECDSA PFX signing use the native HotPDF and Windows cryptography paths. Ed25519 and Ed448 PFX signing require OpenSSL 3 libcrypto; direct HPDFCMSSignPDFStream callers may set THPDFCMSSignOptions.OpenSSLLibraryPath, while the convenience overload uses the normal platform library search path

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 section 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)

The stream overload never retains a complete second PDF in memory. It hashes the patched output in bounded ranges and seek-patches the hexadecimal CMS value without changing file length. Fixed-width decimal offsets support prepared PDFs smaller than 10,000,000,000 bytes

 

See also: AddSignedSignatureField, PreparePDFForSigning, InsertSignatureHex, AddPAdESSignatureField