Задания инкрементального подписания PFX

Операция sign поддерживает проверенный инкрементальный профиль, который сохраняет точную исходную ревизию PDF и каждую существующую криптографическую подпись, отдавая отдельно подписанный артефакт

Выбор профиля

{"schemaVersion":1,"type":"sign","profile":"pfx-incremental-document",
 "pfxFile":"C:/keys/signer.pfx","pfxPassword":"password",
 "fieldName":"ApprovalTwo","existingField":true,
 "budget":{"memoryBytes":268435456,"outputBytes":134217728,
           "resultBytes":16777216,"timeMilliseconds":60000,
           "objectCount":1000000,"pageCount":1024}}

Профиль pfx-unsigned-document по умолчанию сохраняет прежнее поведение и принимает источники без полей подписи; он создаёт новое поле по page, x1, y1, x2 и y2 и восстанавливает граф источника перед публикацией

pfx-incremental-document выбирает новый профиль; incremental: true — эквивалентный селектор, если profile опущен, и конфликтует с явно заданным другим профилем

existingField: true заполняет именованное пустое поле подписи, не добавляя ещё одно поле; иначе операция создаёт новое поле, а page и прямоугольник идентифицируют его виджет

По умолчанию fieldName — Signature1 и принимает от 1 до 1024 байт UTF-8; existingField требует инкрементальный профиль, совпадающее поле подписи и отсутствующее или null-значение V

Read-only бит 1 в Ff и некорректные или вне диапазона целочисленные флаги отвергаются до подготовки; унаследованные словари SV и Lock разрешаются по уникальным семантическим именам PDF с ограниченным обходом родителей

Seed-значения и блокировки полей

digestMethod выбирает реальный дайджест CMS SHA256, SHA384 или SHA512; по умолчанию SHA256, а cades: true выбирает ETSI.CAdES.detached и включает атрибут signing-certificate-v2, привязывающий реальный сертификат подписанта

reason, location и contactName — строки UTF-8 в JSON, записываемые как текстовые строки Unicode PDF; обязательные seed-причины сравниваются по их значениям в Unicode, включая специальное значение из одной точки, которое требует опущенного reason

Обязательные ограничения SV проверяют реальный обработчик, SubFilter CMS, поддерживаемую версию подписания, дайджест, причину, разрешение сертификации, юридическую аттестацию и режим LockDocument; обязательный timestamp использует транспорт приложения и workflow явного доверия из таймстампов подписания Windows, обязательные подписанные свидетельства отзыва — аутентифицированное подписание CRL и OCSP, а обязательные именованные appearances — реально генерируемые пресеты appearance подписи

Обязательные свойства SVCert до подписания проверяют реальный листовой сертификат PFX и включённую цепочку издателей, разрешённые байты сертификата, OID политик сертификата, биты key usage и атрибуты subject DN в Unicode

credentialSourceURL передаёт заявленный приложением источник credential для обязательного URL в SVCert; библиотека сравнивает объявленный URL и поддерживаемый URLType, не открывая эту конечную точку и не аутентифицируя транспортную идентичность

Блокировки полей All, Include и Exclude записываются как косвенный словарь SigFieldLock и согласованная ссылка FieldMDP, привязанная к Catalog документа; имена полей — текстовые строки Unicode PDF, и в зашифрованных документах они остаются зашифрованными

Подписанное значение P в Lock ограничивает последующие ревизии по исходной подписанной политике поля, независимо от каких-либо разрешений DocMDP; разрешённые вторые подписи сохраняют точную предыдущую ревизию и CMS, а заблокированное поле или изменение P1 отвергается до публикации

Поиск политики декодирует эскейпы имён PDF ровно один раз, включая унаследованные имена Parent; словари с дублирующимися семантическими именами, невалидные или циклические родители отвергаются до публикации, а валидные эскейпированные имена сохраняют исходные байты

contentsBytes по умолчанию 16384 и принимает от 1024 до 1048576; reason, location и contactName заполняют новый словарь подписи

Сертификация и юридические аттестации

certificationPermission по умолчанию 0 для подписания утверждения (approval); значения 1, 2 или 3 создают сертифицирующую подпись с запрошенным разрешением DocMDP, привязывают Catalog Perms DocMDP к реальному косвенному словарю подписи и сохраняют любой независимый трансформ FieldMDP

Сертификация должна быть первой подписью, и в документе допустима только одна сертифицирующая подпись; некорректные разрешения Catalog, неразрешённые ссылки и значения DocMDP без привязки к исходному подписанному полю отвергаются

legalAttestation — опциональная строка Unicode для сертифицирующего подписания, записывается в Catalog Legal Attestation; обязательный список LegalAttestation в SV должен содержать выбранный текст, а пустой обязательный список требует его опустить

Существующие сертифицирующие подписи P2 и P3 допускают последующее подписание утверждения, если это позволяют блокировки полей и политика ревизий; подписи P1 и заблокированные поля отвергают изменения до публикации бинарных данных

Контракт источника

Инкрементальный профиль задания принимает сохранённый исходный источник, включая поддерживаемые зашифрованные PDF, и немодифицированный загруженный граф объектов; для зашифрованного источника укажите password в операции sign — отдельно от pfxPassword

Пароль источника аутентифицирует независимый сырой снимок, инициализирует исходный контекст шифрования и заново открывает подписываемого кандидата; полученная инкрементальная ревизия сохраняет исходный префикс шифротекста, словарь безопасности и постоянный ID документа

Расшифровка может пометить объекты dirty или убрать словарь безопасности из расшифрованного графа; операция сверяет эти состояния и ограниченные сериализации объектов со свежей аутентифицированной базой источника, отвергая реальные изменения графа и все сброшенные состояния объектов

Для user-пароля существующее поле подписи требует разрешения form-fill или аннотаций, а новый виджет подписи — разрешения аннотаций; аутентифицированный owner-пароль разрешает любой из вариантов с учётом существующих политик подписей

SaveLoadedDocumentToStream может изменить состояние сериализации; подписывая сохранённый или отредактированный граф, перезагрузите сохранённые байты в новый хэндл и подписывайте эту ревизию

Держите хранилище исходного источника стабильным всё время жизни хэндла; файловые задания запрещают совместную запись, пока загружают и готовят свой снимок

Исходный хэндл сохраняет количество полей, идентичность существующих полей, значения форм, байты источника и прежние настройки запуска и декодирования; любой успешный возврат подписания даёт documentUpdated: false, а неудачи оставляют хэндл пригодным для запросов, сохранения или последующего корректного запроса

Файловые задания отвергают выходной путь, совпадающий с входным файлом или алиасящий его, включая жёсткие ссылки; прямые stream API отвергают распознаваемые алиасы исходного потока и исходного файла, а вызывающий код обязан держать хранилище вывода callback'ов отдельно от входного хранилища

Подготовка и валидация

Операция копирует сырые байты источника в монопольно созданный временный снимок, открывает независимый инкрементальный клон, дописывает placeholder через ограниченный SaveIncrementalUpdate и заполняет detached CMS нативным стримовым подписантом PFX

PFX остаётся открытым с запретом совместной записи от предварительной проверки размера до подписания; временные файлы создаются с CREATE_NEW и удаляются, только если операция сама их создала

Подписанный кандидат должен содержать точный байтовый префикс источника и ожидаемые количества полей формы и подписи; новая подпись должна проверяться в выбранном поле, каждая ранее заполненная подпись должна по-прежнему проверяться, а анализ ревизий каждой старой подписи должен принять ограничения DocMDP, FieldMDP, usage-rights и идентичности

Незаполненные старые поля сохраняются и не учитываются в preservedSignatures; некорректные, невалидные или нарушающие политику существующие подписи приводят к отказу до публикации бинарных данных

Проверка существующих подписей сверяет целостность CMS с подписанными байтами и нативной политикой ревизий; если для новой подписи запрошен timestamp, его ответ отдельно проверяет явное доверие к TSA и настроенные свидетельства отзыва до публикации

Бюджеты и публикация

Фактический потолок вывода — min(outputBytes, memoryBytes / 8), включая весь префикс источника, дописанные объекты, xref и резерв под подпись; effectiveOutputLimit сообщает применённый потолок

Неподписанный кандидат и подписанный вывод ограничиваются этим потолком по отдельности, байты PFX — потолком memoryBytes / 8, а бюджеты декодирования базы источника, клона и кандидата отдельно ограничены memoryBytes / 8 с порогами сброса в файл не выше 1 МиБ

Это бюджеты операции и буферов, а не жёсткая гарантия RSS процесса; криптография, метаданные объектов, анализ ревизий и уже загруженный вызывающим источник могут потребовать дополнительной резидентной памяти

Проверки отмены и затраченного времени покрывают копирование источника, сериализацию и копирование дельты, чтения кандидата, чтения при проверке подписей, чтения при анализе ревизий и публикацию через callback; «липкие» сбои нативных потоков сохраняют свою категорию бюджета или отмены на границе задания

Бинарный вывод подготавливается и проверяется до первого output callback'а, а размер JSON-результата проверяется до публикации бинарных данных; сам вывод callback'ов не атомарен, поэтому неудавшийся callback бинарных данных или результата может оставить байты, которые вызывающий обязан отбросить

Файловые задания пишут в собственный кандидат в том же каталоге, сбрасывают его на диск, закрывают хэндлы источника и вывода и атомарно заменяют отдельный целевой файл после успешной валидации; при сбоях существующее назначение сохраняется

Успех возвращает mediaType: application/pdf, fieldName, profile, incremental, existingField, certificationPermission, revocationInfo, appearanceProfile, preservedSignatures, effectiveOutputLimit, outputBytes и documentUpdated: false

Приёмочный replay

$env:HOTPDF_SUPPRESS_AUTO_LAUNCH = '1'
./Tests/CABI/Run-IncrementalSigningAcceptance.ps1 -BuildDLL -CheckFPC

Раннер находит RAD Studio через её реестровый RootDir, принимает переопределения RADStudioRoot и PythonExecutable и использует настроенный тулчейн FPC при выбранном CheckFPC; FPCOnly повторяет только нативные цели, а OpenSSLWin32Library и OpenSSLWin64Library выбирают соответствующие рантайм-библиотеки для каждой архитектуры

Не-GUI раннер проверяет нативные API Win32 и Win64 и реальные C ABI DLL: частичные callback'и, существующие пустые поля, прежние подписи, обязательные seed-значения, реальные CAdES SHA384 и SHA512, метаданные в Unicode, разрешённые и заблокированные вторые подписи, реальные свойства сертификата PFX, трансформы блокировки полей AES-128 и AES-256, ограничения разрешений и owner-креденшалы, неверные пароли, dirty-графы после расшифровки, точные снимки зашифрованных источников, восстановление шифрованной записи на месте, реальные CMS-фикстуры DocMDP P1 и P2, бюджеты, отмену, сбои callback'ов и повторное использование источника после сбоев

Независимые проверки pypdf, MuPDF и OpenSSL доказывают точность прежних префиксов и диапазонов байтов, неизменность шифрования и постоянных ID, поисковость исходного текста, валидность старых и новых значений CMS, исключение шифрования для Contents подписи и отвержение изменённого подписанного содержимого; independent-proof.json записывает диапазоны байтов и результаты доказательств

Смежные темы

Операции документа, CopyLoadedSourceToStream, SaveIncrementalUpdate, EHPDFIncrementalOutputBudget