EPdfKeychainError = class(Exception);
TPdfKeychainSignerProvider = class(TInterfacedObject, IPadesSignerProvider)
constructor Create(const KeychainPath: string = '');
function BackendName: string;
function Resolve(const Options: TPadesSignerOptions): TPadesResolvedSigner;
end;
TPdfKeychainCmsVerifier = class(TInterfacedObject, IPdfCmsVerifier)
function BackendName: string;
function VerifyDetached(const CmsDer: TBytes; Segment1: Pointer; Segment1Length: Cardinal; Segment2: Pointer; Segment2Length: Cardinal; const Options: TPdfCmsVerifyOptions): TPdfCmsVerifyResult;
function VerifyAttached(const CmsDer: TBytes; const Options: TPdfCmsVerifyOptions): TPdfCmsVerifyResult;
end;
function KeychainAvailable: Boolean;
function KeychainMissingSymbols: string;
function KeychainVerificationAvailable: Boolean;
function ConfigureKeychainSignerProvider: IPadesSignerProvider;
function ConfigureKeychainCmsVerifier: IPdfCmsVerifier;
procedure ConfigureKeychainTrustAnchors(const Anchors: TPadesChainCertArray);
procedure ConfigureKeychainOcspResponses(const Responses: TPadesChainCertArray);
FPdfCryptoMac is the macOS crypto backend consumed by FPdfCrypto and FPdfCms, and it covers both halves of the platform integration: PAdES signing through a Keychain identity, and CMS verification through the system CMS decoder and trust evaluation. Security.framework and CoreFoundation are loaded and resolved by name at run time rather than linked, so the unit compiles on every target and reports at run time whether the platform services are actually reachable
On the signing side, TPdfKeychainSignerProvider implements IPadesSignerProvider. Its Resolve method enumerates the Keychain identities, selects the one whose certificate matches the SHA-1 thumbprint carried by TPadesSignerOptions, reads the certificate DER and the matching private key reference, and returns a TPadesResolvedSigner whose ICmsSigner signs the CMS signed attributes through Security.framework, so the private key never leaves the Keychain. The padding scheme requested through the options is reconciled with what the key can actually do, and the RSASSA-PSS parameters are the same ones the other backends emit, so a document signed on macOS carries an identical AlgorithmIdentifier. ConfigureKeychainSignerProvider builds the provider and installs it as the active PAdES signing backend, returning the interface it registered
On the verification side, TPdfKeychainCmsVerifier implements IPdfCmsVerifier on top of CMSDecoder and SecTrust. VerifyDetached joins the two signed byte ranges either side of the signature hole into the detached content the decoder expects, then verifies the CMS value against it; VerifyAttached verifies a CMS value that carries its own content, which is what a timestamp token needs. Both return a TPdfCmsVerifyResult that reports signature status, trust status and revocation status separately, optionally collecting the signer certificate and the evaluated chain, and both honor the revocation, online retrieval and checkpoint settings in TPdfCmsVerifyOptions. ConfigureKeychainCmsVerifier builds the verifier and installs it as the active CMS verification backend
Signature validity and certificate trust stay independent results, so an authentic signature under an untrusted or self-signed chain remains distinguishable from tampered content
For an attached RFC 3161 token, bounded DER parsing supplies the original encapsulated TSTInfo octets to the native decoder without changing their content type or signed attributes. The ordinary CMS verification pass excludes unsigned attributes from its native input so automatic timestamp processing cannot replace the outer signature's own integrity or chain result. This pass does not validate countersignatures or other unsigned attributes; ValidatePadesTrust separately verifies each original timestamp token, message imprint, TSA certificate role, trust, and revocation result
Pass a Keychain file path to TPdfKeychainSignerProvider.Create to restrict identity lookup to that Keychain through a query-local search list, then register the provider with ConfigurePadesSignerProvider. An empty path uses the current user search scope. Opening or searching the selected Keychain does not modify the default Keychain, user search list, or system trust configuration; invalid paths and unavailable scoped-search symbols raise EPdfKeychainError
Resolve also exports the signing certificate's available issuer chain through an offline, query-local certificate lookup and native chain construction. Candidate certificates are limited to 4096 items, 1 MiB each and 16 MiB in total; the constructed chain is limited to 32 certificates including the leaf, which is returned separately from ChainCertDer. Exporting certificate material does not establish trust or install a trust anchor, and an unavailable issuer cannot be synthesized
| Function | Description |
|---|---|
KeychainAvailable | Returns True when Security.framework and CoreFoundation loaded and every symbol required for signing resolved |
KeychainMissingSymbols | Returns the names that failed to resolve, separated by spaces, or an empty string when everything bound |
ConfigureKeychainSignerProvider | Builds a TPdfKeychainSignerProvider, installs it as the PAdES signing backend, and returns it as an IPadesSignerProvider |
TPdfKeychainSignerProvider.Create | Selects an optional existing Keychain file for scoped identity lookup, rejecting embedded NUL characters and paths longer than 4096 string code units |
TPdfKeychainSignerProvider.BackendName | Returns the backend identifier reported for the signing provider |
TPdfKeychainSignerProvider.Resolve | Matches TPadesSignerOptions against the Keychain identities and returns a TPadesResolvedSigner holding the signer, the certificate DER and the chain |
| Function | Description |
|---|---|
KeychainVerificationAvailable | Returns True when the CMS decoder, trust policy and trust evaluation symbols resolved |
ConfigureKeychainCmsVerifier | Builds a TPdfKeychainCmsVerifier, installs it as the CMS verification backend, and returns it as an IPdfCmsVerifier |
ConfigureKeychainTrustAnchors | Clones explicit DER anchors for each later trust evaluation, supplementing system anchors without modifying the Keychain; limits are 64 certificates, 4 MiB each, and 16 MiB total, and an empty array clears them |
ConfigureKeychainOcspResponses | Clones explicit DER OCSP evidence for native Security.framework evaluation; limits are 8 responses, 1 MiB each, and 4 MiB total, and an empty array clears them |
TPdfKeychainCmsVerifier.BackendName | Returns the backend identifier reported for the verification backend |
TPdfKeychainCmsVerifier.VerifyDetached | Verifies a detached CMS value against the two caller-owned content segments described by Segment1, Segment1Length, Segment2 and Segment2Length, using the supplied TPdfCmsVerifyOptions |
TPdfKeychainCmsVerifier.VerifyAttached | Verifies an attached CMS value that carries its own signed content, using the supplied TPdfCmsVerifyOptions |
| Type | Members and purpose |
|---|---|
EPdfKeychainError | Exception raised when Security.framework is unavailable, when no Keychain identity matches the requested signer, or when the platform signing call fails |
TPdfKeychainSignerProvider | PAdES signing backend implementing IPadesSignerProvider, with BackendName and Resolve |
TPdfKeychainCmsVerifier | CMS verification backend implementing IPdfCmsVerifier, with BackendName, VerifyDetached and VerifyAttached |
KeychainAvailable and KeychainVerificationAvailable report signing and verification separately because the two halves need different framework symbols, so a system can bind one and not the otherKeychainMissingSymbols names every symbol that failed to resolve, which is what makes an absent framework distinguishable from a binding problem: an empty result means everything bound, a result naming the framework paths means the frameworks did not load, and a result naming individual entry points means the frameworks loaded but a name did not resolveKeychainAvailable and KeychainVerificationAvailable, return an empty KeychainMissingSymbols, and raise EPdfKeychainError from the configure functionsTPadesSignerOptions carries no certificate thumbprint the first usable identity in the Keychain is selected, which suits a test rather than a production signaturepcvsUnsupported, retaining native diagnostics, rather than reporting valid or invalid integrity. Use the OpenSSL CMS verifier for those values; mixed signer diagnostics retain each signer's separate algorithm resultFreshOcspResponse time and DER prefilter, followed by native responder-signature, authority, and certificate checks. The permitted skew is 300 seconds, and producedAt and thisUpdate are limited to one day of ageOnlineRetrieval=False disables native trust-network fetching. Native Security.framework online evaluation follows platform behavior; UrlRetrievalTimeoutMs does not provide the bounded OpenSSL transport deadline on this backendCollectSignerDiagnostics=True returns separate signer snapshots, capped by MaxSignerCount and a hard limit of 64. Returned certificate material is limited to 4 MiB per certificate and 64 MiB in total; incomplete collection reports pcvsIndeterminateSignerDiagnosticsStatus=pcvsValid means collection is complete, including failed signer verdicts. RevocationError carries native Security.framework status, while RevocationCertificate remains empty on this backend