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 de 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 vincularse, 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
Del lado de la firma, TPdfKeychainSignerProvider implementa IPadesSignerProvider. Su método Resolve enumera las identidades de Keychain, selecciona la que tiene un certificado que coincide con la huella digital 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ó
Del lado de la verificación, TPdfKeychainCmsVerifier implementa IPdfCmsVerifier sobre CMSDecoder y SecTrust. VerifyDetached une los dos rangos de bytes firmados a ambos lados del hueco de la firma en el contenido separado que espera el decodificador, y después verifica el valor CMS contra él; VerifyAttached verifica un valor CMS que transporta su propio contenido, que es lo que necesita un token de marca de tiempo. Ambos devuelven un TPdfCmsVerifyResult que informa por separado del estado de la firma, de la confianza y de la revocación, opcionalmente recogen el certificado del firmante y la cadena evaluada, y ambos respetan los ajustes de revocación, obtención en línea y puntos de control de TPdfCmsVerifyOptions. ConfigureKeychainCmsVerifier construye el verificador y lo instala como backend de verificación de 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 alterado
Para un token RFC 3161 adjunto, el análisis DER con límites proporciona al decodificador nativo los octetos originales de TSTInfo encapsulado sin cambiar su tipo de contenido ni los atributos firmados; la verificación CMS ordinaria excluye los atributos no firmados de su entrada nativa para que el procesamiento automático de sellos de tiempo no reemplace el resultado de integridad o cadena de la firma externa; esta pasada no valida contrafirmas ni otros atributos no firmados; ValidatePadesTrust verifica por separado cada token original, su huella, la función del certificado TSA, la confianza y la revocación
Pase una ruta de archivo Keychain a TPdfKeychainSignerProvider.Create para limitar la búsqueda a ese Keychain mediante una lista local a la consulta, y registre 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 confianza del sistema; las rutas inválidas y los símbolos de búsqueda acotada no disponibles lanzan EPdfKeychainError
Resolve también exporta la cadena emisora disponible del certificado de firma mediante búsqueda de certificados offline local a la consulta y construcción nativa de cadena; los candidatos se limitan a 4096 certificados, 1 MiB cada uno y 16 MiB en total; la cadena construida admite hasta 32 certificados incluida la hoja, que se devuelve por separado de ChainCertDer; exportar certificados no establece confianza ni instala anclas, y un emisor no disponible no puede sintetizarse
| Función | Descripción |
|---|---|
KeychainAvailable | Devuelve True cuando Security.framework y CoreFoundation se cargaron y todos los símbolos necesarios para firmar se resolvieron |
KeychainMissingSymbols | Devuelve los nombres que no se pudieron resolver, separados por espacios, o una cadena vacía cuando todo se vinculó |
ConfigureKeychainSignerProvider | Construye un TPdfKeychainSignerProvider, lo instala como backend de firma PAdES y lo devuelve como IPadesSignerProvider |
TPdfKeychainSignerProvider.Create | Selecciona un archivo Keychain existente opcional para limitar la búsqueda de identidades; 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 resolvieron 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 de CMS y lo devuelve como IPdfCmsVerifier |
ConfigureKeychainTrustAnchors | Clona anclas DER explícitas para las evaluaciones de confianza posteriores, complementando las anclas del sistema sin modificar Keychain; los límites son 64 certificados, 4 MiB cada uno y 16 MiB en total; un arreglo vacío las elimina |
ConfigureKeychainOcspResponses | Clona evidencia OCSP DER explícita para la evaluación nativa de Security.framework; los límites son 8 respuestas, 1 MiB cada una y 4 MiB en total; un arreglo 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 separado contra los dos segmentos de contenido propiedad de quien llama 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 de 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 vincular 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 vinculación: un resultado vacío significa que todo se vinculó, 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, una cadena vacía en KeychainMissingSymbols y lanzan EPdfKeychainError desde las funciones de configuraciónTPadesSignerOptions no transporta ninguna huella digital 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 diagnósticos nativos, en vez de marcar la integridad como válida o inválida; use el verificador CMS OpenSSL para esos valores; los diagnósticos de varios firmantes conservan por separado el resultado de algoritmo de cada unoFreshOcspResponse, seguido de comprobaciones nativas de firma y autorización del respondedor y del certificado; el desfase permitido es 300 segundos, y producedAt y thisUpdate admiten como máximo un día de antigüedadOnlineRetrieval=False deshabilita la recuperación de confianza por red; la evaluación online de Security.framework sigue el comportamiento de plataforma; UrlRetrievalTimeoutMs no proporciona en este backend el plazo de transporte limitado de OpenSSLCollectSignerDiagnostics=True devuelve instantáneas separadas, 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 recopilación incompleta informa pcvsIndeterminateSignerDiagnosticsStatus=pcvsValid indica recopilación completa, incluso con veredictos de firma fallidos; RevocationError contiene el estado nativo de Security.framework y RevocationCertificate queda vacío en este backend