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 es el backend criptográfico de macOS que consumen FPdfCrypto y FPdfCms, y cubre las dos mitades de la integración con la plataforma: la firma PAdES mediante una identidad de Keychain y la verificación CMS mediante el decodificador CMS del sistema y la evaluación de confianza. Security.framework y CoreFoundation se cargan y resuelven por nombre en tiempo de ejecución en lugar de enlazarse, de modo que la unidad compila para todos los destinos e informa en tiempo de ejecución de si los servicios de la plataforma son realmente accesibles
En el lado de la firma, TPdfKeychainSignerProvider implementa IPadesSignerProvider. Su método Resolve enumera las identidades de Keychain, selecciona la cuyo certificado coincide con la huella SHA-1 que transporta TPadesSignerOptions, lee el DER del certificado y la referencia asociada de clave privada, y devuelve un TPadesResolvedSigner cuyo ICmsSigner firma los atributos firmados CMS a través de Security.framework, de modo que la clave privada nunca sale de Keychain. El esquema de relleno solicitado mediante las opciones se concilia con lo que la clave puede hacer realmente, y los parámetros RSASSA-PSS son los mismos que emiten los otros backends, de modo que un documento firmado en macOS lleva un AlgorithmIdentifier idéntico. ConfigureKeychainSignerProvider construye el proveedor, lo instala como backend de firma PAdES activo y devuelve la interfaz que registró
Para la verificación, TPdfKeychainCmsVerifier implementa IPdfCmsVerifier sobre CMSDecoder y SecTrust. VerifyDetached reúne los dos rangos firmados a ambos lados del hueco de firma en el contenido separado que espera el decodificador y comprueba el valor CMS contra él; VerifyAttached verifica un CMS que lleva su propio contenido, como necesita un token de timestamp. Ambos devuelven un TPdfCmsVerifyResult con estados independientes de firma, confianza y revocación, pueden recoger el certificado del firmante y la cadena evaluada, y respetan las opciones de revocación, recuperación en línea y checkpoints de TPdfCmsVerifyOptions. ConfigureKeychainCmsVerifier crea el verificador y lo instala como backend CMS activo
La validez de la firma y la confianza en el certificado son resultados independientes, de modo que una firma auténtica bajo una cadena que no es de confianza o autofirmada sigue siendo distinguible del contenido manipulado
Para un token RFC 3161 adjunto, el análisis DER acotado entrega al decodificador nativo los octetos originales de TSTInfo encapsulados sin cambiar su tipo de contenido ni sus atributos firmados. La pasada ordinaria de verificación CMS excluye los atributos no firmados de la entrada nativa para impedir que el procesamiento automático de timestamps sustituya el resultado de integridad o cadena de la firma exterior. Esta pasada no valida contrafirmas ni otros atributos no firmados; ValidatePadesTrust verifica por separado cada token de timestamp original, su huella de mensaje, el rol del certificado TSA, la confianza y la revocación
Pase una ruta de fichero Keychain a TPdfKeychainSignerProvider.Create para limitar la búsqueda de identidades a ese Keychain mediante una lista de búsqueda local a la consulta y registre después el proveedor con ConfigurePadesSignerProvider. Una ruta vacía usa el ámbito de búsqueda del usuario actual. Abrir o buscar en el Keychain seleccionado no modifica el Keychain predeterminado, la lista de búsqueda del usuario ni la configuración de confianza del sistema; las rutas inválidas o la falta de símbolos de búsqueda acotada lanzan EPdfKeychainError
Resolve también exporta la cadena de emisores disponible del certificado de firma mediante búsqueda de certificados offline y local a la consulta y construcción nativa de la cadena. Se admiten como máximo 4096 certificados candidatos, de 1 MiB cada uno y 16 MiB en total; la cadena construida se limita a 32 certificados incluida la hoja, que se devuelve separada de ChainCertDer. Exportar certificados no establece confianza ni instala un anclaje de confianza, y no permite inventar un emisor ausente
| Función | Descripción |
|---|---|
KeychainAvailable | Devuelve True cuando Security.framework y CoreFoundation se han cargado y todos los símbolos necesarios para firmar se han resuelto |
KeychainMissingSymbols | Devuelve los nombres que no se pudieron resolver, separados por espacios, o una cadena vacía cuando todo se enlazó |
ConfigureKeychainSignerProvider | Construye un TPdfKeychainSignerProvider, lo instala como backend de firma PAdES y lo devuelve como IPadesSignerProvider |
TPdfKeychainSignerProvider.Create | Selecciona un fichero Keychain existente opcional para buscar identidades dentro de ese ámbito; rechaza caracteres NUL incrustados y rutas de más de 4096 unidades de código de cadena |
TPdfKeychainSignerProvider.BackendName | Devuelve el identificador de backend que se informa para el proveedor de firma |
TPdfKeychainSignerProvider.Resolve | Coteja TPadesSignerOptions con las identidades de Keychain y devuelve un TPadesResolvedSigner con el firmante, el DER del certificado y la cadena |
| Función | Descripción |
|---|---|
KeychainVerificationAvailable | Devuelve True cuando se han resuelto los símbolos del decodificador CMS, de la política de confianza y de la evaluación de confianza |
ConfigureKeychainCmsVerifier | Construye un TPdfKeychainCmsVerifier, lo instala como backend de verificación CMS y lo devuelve como IPdfCmsVerifier |
ConfigureKeychainTrustAnchors | Clona los anclajes DER explícitos para cada evaluación posterior y complementa los anclajes del sistema sin modificar el Keychain; los límites son 64 certificados, 4 MiB por certificado y 16 MiB en total, y un array vacío los elimina |
ConfigureKeychainOcspResponses | Clona la evidencia OCSP DER explícita para su evaluación nativa por Security.framework; los límites son 8 respuestas, 1 MiB por respuesta y 4 MiB en total, y un array vacío las elimina |
TPdfKeychainCmsVerifier.BackendName | Devuelve el identificador de backend que se informa para el backend de verificación |
TPdfKeychainCmsVerifier.VerifyDetached | Verifica un valor CMS desacoplado contra los dos segmentos de contenido propiedad del llamador descritos por Segment1, Segment1Length, Segment2 y Segment2Length, usando las TPdfCmsVerifyOptions suministradas |
TPdfKeychainCmsVerifier.VerifyAttached | Verifica un valor CMS adjunto que transporta su propio contenido firmado, usando las TPdfCmsVerifyOptions suministradas |
| Tipo | Miembros y propósito |
|---|---|
EPdfKeychainError | Excepción que se lanza cuando Security.framework no está disponible, cuando ninguna identidad de Keychain coincide con el firmante solicitado o cuando falla la llamada de firma de la plataforma |
TPdfKeychainSignerProvider | Backend de firma PAdES que implementa IPadesSignerProvider, con BackendName y Resolve |
TPdfKeychainCmsVerifier | Backend de verificación CMS que implementa IPdfCmsVerifier, con BackendName, VerifyDetached y VerifyAttached |
KeychainAvailable y KeychainVerificationAvailable informan por separado de la firma y de la verificación porque las dos mitades necesitan símbolos distintos del framework, de modo que un sistema puede enlazar una y no la otraKeychainMissingSymbols nombra todos los símbolos que no se pudieron resolver, y eso es lo que permite distinguir un framework ausente de un problema de enlazado: un resultado vacío significa que todo se enlazó, un resultado que nombra las rutas de los frameworks significa que los frameworks no se cargaron, y un resultado que nombra puntos de entrada concretos significa que los frameworks se cargaron pero un nombre no se resolvióKeychainAvailable y KeychainVerificationAvailable, un KeychainMissingSymbols vacío y EPdfKeychainError desde las funciones de configuraciónTPadesSignerOptions no transporta ninguna huella de certificado se selecciona la primera identidad utilizable de Keychain, algo apropiado para una prueba más que para una firma de producciónpcvsUnsupported y conservan los diagnósticos nativos, en vez de declarar la integridad válida o inválida. Use el verificador CMS de OpenSSL para esos valores; los diagnósticos con firmantes mixtos conservan el resultado de algoritmo de cada unoFreshOcspResponse y después las comprobaciones nativas de firma del responder, autoridad y certificado. Se admite un desfase de 300 segundos y una antigüedad máxima de un día para producedAt y thisUpdateOnlineRetrieval=False desactiva la recuperación por red del mecanismo de confianza nativo. La evaluación en línea de Security.framework sigue el comportamiento de la plataforma; UrlRetrievalTimeoutMs no proporciona aquí el plazo de transporte acotado del backend OpenSSLCollectSignerDiagnostics=True devuelve instantáneas independientes por firmante, limitadas por MaxSignerCount y un máximo absoluto de 64. El material de certificados devuelto se limita a 4 MiB por certificado y 64 MiB en total; una recogida incompleta devuelve pcvsIndeterminateSignerDiagnosticsStatus=pcvsValid indica que la recogida está completa, incluidos los veredictos de firmantes que han fallado. RevocationError contiene el estado nativo de Security.framework, mientras que RevocationCertificate queda vacío en este backend