Техническа статия

PAdES LTV доказателства и seed стойности в HotPDF

PDF, който току-що сте подписали, е B-B подпис и нищо повече; Той доказва кой е подписал и че байтовете не са се местили, но не носи доказателство, че сертификатът на подписващия е бил валиден в момента на подписване, така че валидатор години по-късно трябва да търси revocation данни, които може вече да не съществуват; Затварянето на тази дупка означава писане на OCSP отговори и CRL в document-level Document Security Store, а в HotPDF това е едно извикване: PopulatePAdESLTVEvidence обхожда всеки зареден подпис, извежда revocation заявките от набора сертификати, изпълнява ги чрез transport, който вие доставяте, и записва изтегления материал плюс CMS веригата в DSS; Той връща броя на подписите, чиито доказателства са кацнали, или минус едно, когато документът изобщо няма поле за подпис

Дизайн решението, което си заслужава да се разбере, преди да го използвате, е, че библиотеката никога не отваря socket; Всеки байт, който пристига от мрежата, пристига през callback, който вие сте написали; Това не е предпазливост заради самата нея; това е единственият начин тази функция да работи вътре в средите, които действително изискват дългосрочна валидация

Защо библиотеката отказва да прави собствения си HTTP?

Защото местата, които изискват B-LT подписи, са местата, където на библиотека не може да се вярва с мрежата; Услуги за подписване тичат зад автентикиращи proxy-та с корпоративни root-ове; Air-gapped подписващи слоеве нямат маршрут до responder и трябва да бъдат хранени с кеширани доказателства; Audit режими изискват всяка изходяща заявка да бъде логвана от приложението, а не закопана в зависимост; И тестови набори се нуждаят от детерминистични отговори, което е невъзможно, ако библиотеката звъни навън сама

Transport-ът е обикновена функция референция с фиксирана форма, така че политиката остава ваша; HotPDF ви подава request запис, описващ точно какво да се изтегли, включително content типа и таван за размера на отговора, а вие връщате байтовете плюс статус

Поток на PopulatePAdESLTVEvidence в HotPDF: доставеният от извикващия FetchEvidence transport, полетата на request записа и статусите за всеки подпис
Всеки мрежов байт минава през вашия FetchEvidence callback и всеки подпис получава собствен статус, така че един timeout никога не прекратява прохода
function FetchEvidence(const Request: THPDFSignatureEvidenceRequest;
  Attempt: Integer; CancellationToken: THPDFCancellationToken;
  out Response: TBytes; out RetryAfterMS: Cardinal;
  out ErrorMessage: UnicodeString): THPDFSignatureEvidenceTransportStatus;
begin
  RetryAfterMS := 0;
  try
    // Request.Kind казва дали това е OCSP POST или CRL GET;
    // Request.ContentType и Request.Body са вече подготвени,
    // а Request.MaxResponseBytes е таванът, който трябва да спазвате
    Response := HttpExchange(Request.URI, Request.ContentType,
      Request.Body, Request.MaxResponseBytes);
    Result := setsSucceeded;
  except
    on E: Exception do
    begin
      ErrorMessage := E.Message;
      // setsRetry позволява на retry политиката да се отдръпне;
      // използвайте setsPermanentFailure за 404 или лош URL
      Result := setsRetry;
    end;
  end;
end;

// Надграждане с едно извикване от B-B към B-LT за всеки подпис
// в заредения файл
var
  Pdf: THotPDF;
  Upgraded: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.BeginIncrementalUpdate('signed.pdf');
    Upgraded := Pdf.PopulatePAdESLTVEvidence(FetchEvidence,
      THPDFSignatureEvidenceRetryPolicy.Default);
    if Upgraded > 0 then
      // Append-only запис: байтовете, които съществуващите подписи
      // покриват, се запазват дословно
      Pdf.SaveIncrementalUpdate('signed-lt.pdf');
  finally
    Pdf.Free;
  end;
end;

Отказите са за подпис, не за документ; Responder, който отнема timeout за един подписващ, прескача материала на този подписващ и оставя остатъка от прохода непокътнат, което е поведението, което искате в пакет: частични доказателства бият прекъснато изпълнение, а return стойността ви казва колко подписа действително са се подобрили

Веригата, която CMS забрави да включи

Revocation проверката се нуждае от сертификата на издателя и изненадващ брой подписващи стекове пропускат intermediates от CMS контейнера; Маршрутът за възстановяване е разширението Authority Information Access, access метод 1.3.6.1.5.5.7.48.2, който рекламира URL, откъдето сертификатът на издателя може да бъде изтеглен; HPDFFetchAIAIntermediates обхожда тези URL-и през същия transport, парсва DER от всеки отговор и връща само сертификатите, които CMS вече не носеше, ключувани по DER hash, така че дубликати и цикли не могат да се въртят

Два детайла решават дали това работи срещу реални сертификатни авторитети; Първият е кодирането: CA крайните точки сервират сертификата като гол DER приблизително толкова често, колкото го сервират PEM облечен и няма надежден content тип, който да ги разграничи; Здравата сонда е текстова, после структурна; Потърсете маркера -----BEGIN CERTIFICATE-----, съблечете бронята и декодирайте base64, ако е налична, и в двата пътя потвърдете, че първият байт на резултата е $30, DER тагът за SEQUENCE; Вторият е дълбочината: изтеглен intermediate може сам да рекламира AIA URL за собствения си издател, така че обходът добавя нови кандидати към опашката и доизгражда вериги, които са с две-три стъпки къси; Това трябва да бъде ограничено, за което е параметърът MaxFetch

Диаграма на доизграждане на верига чрез AIA за HotPDF: изтегляне на caIssuers URL, сонда PEM срещу DER, DER hash дедупликация и таванът на дълбочина MaxFetch
HPDFFetchAIAIntermediates обхожда caIssuers URL-и през същия transport, сондирайки PEM броня и ограничавайки опашката с MaxFetch

Какво е seed стойност на подпис и защо се проваля мълшиво?

Seed стойност е ограничение, което авторът на документа прикрепя към поле за подпис, за да каже на подписващия какъв вид подпис е приемлив: кой SubFilter, кой digest алгоритъм, кои причини, коя минимална PDF версия, дали revocation информация трябва да бъде вграждана; Тя живее в речник /SV на полето и е дефинирана в ISO 32000-1 §12.7.5.5; HotPDF я записва с AttachPAdESSeedValue и я проверява с CheckLoadedSignatureSeedValue, която връща True, когато полето е без ограничения или всяко налично ограничение минава, а при False назова първото провалящо се ограничение чрез output параметър, който можете да сложите направо в съобщение за грешка

Механизмът, който прави seed стойностите лесни за объркване, е записът с флагове /Ff, описан в §12.7.5.5.3; Установен бит маркира неговото ограничение като задължително: разминаване е грешка и подписващият трябва да откаже; Изчистен бит маркира същото ограничение като предпочитание: стойността филтрира какво UI-то трябва да предлага и нищо повече; Оттам следват два капана; Първо, /Ff живее вътре в речника /SV, не върху widget анотацията, така че код, който чете field-ниво /Ff, получава празен отговор завинаги и заключава, че нищо не е наложено; Второ, разпределението на битовете не е проста поредица едно, две, четири, осем; в HotPDF writer-ът излъчва 2 за SubFilter, 4 за MinVersion, 32 за AddRevInfo и 64 за DigestMethod; Четец, който предполага последователни битове, декодира всяко ограничение като опционално и минава всеки тест освен онзи, който има значение

Таблица с флаг битове на seed стойност за PAdES подписване в HotPDF, показваща Ff битове 2, 4, 32 и 64 и обработка на ограничения задължително срещу предпочитано
Записът /Ff живее вътре в /SV и всяка битова позиция решава дали разминаване е твърд отказ или UI предпочитание
var
  Violation: AnsiString;
begin
  // Попитайте полето дали профилът, с който ще подписваме, е позволен
  if not Pdf.CheckLoadedSignatureSeedValue(0, 'ETSI.CAdES.detached',
       'SHA256', 'Approved for payment', 1, Violation) then
    raise Exception.Create('Signature field rejects this profile: ' +
      String(Violation));
  // Ограничението е удовлетворено: продължете с подписващия проход
end;

Тестът, който извади оригиналния декодиращ дефект, не беше позитивен тест; Той беше предположението, че наложено разминаване трябва да бъде отхвърлено и е единственият вид тест, който може да хване този клас дефекти: декодер, четещ грешния речник или грешните битови позиции, произвежда „нищо не е нарушено“ за всеки вход, което изглежда точно като правилно поведение, докато нарочно не нарушите едно

Къде това стои на LTV стълбата

Четири степени и всяка се нуждае от долната; B-B е голият подпис; B-T добавя доверено времево клеймо, което фиксира времето на подписване, така че валидатор знае към кой момент да оцени revocation; B-LT добавя revocation доказателствата към DSS, което е това, което PopulatePAdESLTVEvidence автоматизира; B-LTA добавя документни времеви клейма, които се подновяват, преди предишното да отслабне, удължавайки валидността неопределено; HotPDF излага това като RenewPAdESLTATimestamp, който добавя ново времево клеймо като инкрементална ревизия и запазва всеки по-ранен подпис, времево клеймо и DSS запис недокоснати

Моделът инкрементална актуализация е единственият правилен начин да се добавят доказателства към подписан документ, защото преписването на файла би счупило байтовите диапазони, които съществуващите подписи покриват; Ако трябва да разсъждавате какво се е променило между ревизии и дали тези промени са от рода, който подпис позволява, този анализ е разгледан отделно в анализа на ревизии DocMDP и FieldMDP; Самият подписващ конвейер, включително източници на сертификати и капани с байтов ред, е в прошетката за PAdES подписване, а страната за валидация е в верифициране на подписи върху заредени документи

Едно практично предупреждение за подредбата; Събирайте доказателствата възможно най-скоро след подписването, в идеалния случай в същата задача; Responders, които могат да отговорят за сертификат, са онлайн, докато сертификатът е текущ и изчезват години по-късно, така че документ, който напуска вашия конвейер като B-B, може никога повече да не може да бъде надграден; HotPDF тича като нативен VCL компонент за Delphi и C++Builder и целият проход за доказателства е in-process, освен вашия собствен transport; поддържаните профили са изброени на продуктовата страница HotPDF Delphi PDF component