Articol tehnic

Dovede LTV PAdES și valori seed în HotPDF

Un PDF pe care tocmai l-ați semnat este o semnătură B-B și nimic mai mult. Dovedește cine a semnat și că octeții nu s-au mișcat, dar nu poartă nicio dovadă că certificatul semnatarului era valid la momentul semnării, astfel încât un validator peste ani trebuie să caute date de revocare care este posibil să nu mai existe. Închiderea acestei lacune înseamnă scrierea răspunsurilor OCSP și a CRL-urilor în Document Security Store la nivel de document, iar în HotPDF acesta este un singur apel: PopulatePAdESLTVEvidence parcurge fiecare semnătură încărcată, derivă cererile de revocare din setul de certificate, le execută printr-un transport pe care îl furnizați și scrie materialul adus plus lanțul CMS în DSS. Returnează numărul de semnături ale căror dovezi au ajuns la destinație, sau minus unu când documentul nu are deloc un câmp de semnătură

Decizia de design care merită înțeleasă înainte de folosire este că biblioteca nu deschide niciodată un socket. Fiecare octet care sosește din rețea sosește printr-un callback scris de dumneavoastră. Aceasta nu este precauție pentru ea însăși; este singura modalitate prin care această funcție poate funcționa în interiorul mediilor care cer efectiv validare pe termen lung

De ce refuză biblioteca să facă propriul HTTP?

Pentru că locurile care cer semnături B-LT sunt locurile în care unei biblioteci nu i se poate încredința rețeaua. Serviciile de semnare rulează în spatele proxy-urilor cu autentificare și cu rădăcini corporative. Nivelurile de semnare izolate aerian nu au rută către un responder și trebuie hrănite cu dovezi din cache. Regimurile de audit cer ca fiecare cerere de ieșire să fie înregistrată de aplicație, nu îngropată într-o dependență. Iar suitele de test au nevoie de răspunsuri deterministe, ceea ce este imposibil dacă biblioteca sună singură în exterior

Transportul este o referință simplă de funcție cu o formă fixă, deci politica rămâne a dumneavoastră. HotPDF vă înmânează un record de cerere care descrie exact ce să aducă, inclusiv tipul de conținut și o limită de mărime a răspunsului, iar dumneavoastră returnați octeții plus o stare

Fluxul PopulatePAdESLTVEvidence din HotPDF: transportul FetchEvidence furnizat de apelant, câmpurile recordului de cerere și stările per semnătură
Fiecare octet de rețea trece prin callback-ul dumneavoastră FetchEvidence, iar fiecare semnătură primește propria stare, astfel încât un timeout nu anulează niciodată trecerea
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 spune dacă acesta este un OCSP POST sau un CRL GET;
    // Request.ContentType și Request.Body sunt deja pregătite,
    // iar Request.MaxResponseBytes este limita pe care trebuie să o respectați
    Response := HttpExchange(Request.URI, Request.ContentType,
      Request.Body, Request.MaxResponseBytes);
    Result := setsSucceeded;
  except
    on E: Exception do
    begin
      ErrorMessage := E.Message;
      // setsRetry lasă politica de reîncercare să amâne; folosiți
      // setsPermanentFailure pentru un 404 sau un URL greșit
      Result := setsRetry;
    end;
  end;
end;

// Actualizare B-B la B-LT într-un singur apel pentru fiecare semnătură din fișierul încărcat
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
      // Salvare doar prin adăugare: octeții pe care îi acoperă
      // semnăturile existente sunt păstrați întocmai
      Pdf.SaveIncrementalUpdate('signed-lt.pdf');
  finally
    Pdf.Free;
  end;
end;

Eșecurile sunt per semnătură, nu per document. Un responder care expiră pentru un semnatar sare materialul acelui semnatar și lasă restul trecerii intact, ceea ce este comportamentul dorit într-un lot: dovezi parțiale bat o rulare abandonată, iar valoarea de retur vă spune câte semnături s-au îmbunătățit efectiv

Lanțul pe care CMS a uitat să îl includă

Verificarea revocării are nevoie de certificatul emitentului, iar un număr surprinzător de stive de semnare omit intermediarii din containerul CMS. Calea de recuperare este extensia Authority Information Access, metodă de acces 1.3.6.1.5.5.7.48.2, care anunță un URL de unde poate fi descărcat certificatul emitentului. HPDFFetchAIAIntermediates parcurge acele URL-uri prin același transport, extrage DER-ul din fiecare răspuns și returnează doar certificatele pe care CMS nu le purta deja, indexate după hash DER, ca duplicatele și buclele să nu poată cicla

Două detalii decid dacă aceasta funcționează contra autorităților de certificare reale. Primul este codarea: capetele CA servesc certificatul ca DER gol cam la fel de des ca PEM blindat, și nu există un tip de conținut fiabil care să le distingă. Sonda robustă este textuală, apoi structurală. Căutați markerul -----BEGIN CERTIFICATE-----, dezbrăcați armura și decodați base64 dacă este prezent, iar în ambele căi confirmați că primul octet al rezultatului este $30, eticheta DER pentru un SEQUENCE. Al doilea este adâncimea: un intermediar adus poate anunța el însuși un URL AIA pentru propriul emitent, deci parcurgerea adaugă noi candidați în coadă și completează lanțuri care au nevoie de încă două sau trei hop-uri. Aceasta trebuie limitată, și pentru asta este parametrul MaxFetch

Diagrama completării lanțului AIA pentru HotPDF: aducere URL caIssuers, sondă PEM contra DER, deduplicare după hash DER și limita de adâncime MaxFetch
HPDFFetchAIAIntermediates parcurge URL-urile caIssuers prin același transport, sondând armura PEM și limitând coada cu MaxFetch

Ce este o valoare seed de semnătură și de ce eșuează în tăcere?

O valoare seed este o restricție pe care autorul documentului o atașează unui câmp de semnătură pentru a-i spune semnatarului ce fel de semnătură este acceptabilă: care SubFilter, care algoritm de digest, care motive, care versiune minimă de PDF, dacă informația de revocare trebuie înglobată. Trăiește într-un dicționar /SV pe câmp și este definită în ISO 32000-1 §12.7.5.5. HotPDF o scrie cu AttachPAdESSeedValue și o verifică cu CheckLoadedSignatureSeedValue, care returnează True când câmpul nu are restricții sau când fiecare restricție prezentă trece, iar la False numește prima restricție eșuată printr-un parametru de ieșire pe care îl puteți pune direct într-un mesaj de eroare

Mecanismul care face valorile seed ușor de greșit este intrarea de fanioane /Ff descrisă în §12.7.5.5.3. Un bit setat își marchează restricția ca obligatorie: o nepotrivire este o eroare, iar semnatarul trebuie să refuze. Un bit curat marchează aceeași restricție drept preferință: valoarea filtrează ce ar trebui să ofere UI-ul și nimic mai mult. Două capcane decurg de aici. Prima, /Ff trăiește în interiorul dicționarului /SV, nu pe adnotarea widget, deci codul care citește /Ff de la nivelul câmpului primește pentru totdeauna un răspuns gol și concluzionează că nimic nu este forțat. A doua, atribuirea biților nu este un simplu șirag de unu, doi, patru, opt; în HotPDF scriitorul emite 2 pentru SubFilter, 4 pentru MinVersion, 32 pentru AddRevInfo și 64 pentru DigestMethod. Un cititor care presupune biți secvențiali decodează fiecare restricție ca opțională și trece fiecare test în afară de cel care contează

Tabelul biților de fanion ai valorii seed pentru semnarea PAdES în HotPDF, arătând biții Ff 2, 4, 32 și 64 și tratarea restricțiilor obligatorii contra preferate
Intrarea /Ff trăiește în interiorul /SV, iar fiecare poziție de bit decide dacă o nepotrivire este un refuz ferm sau o preferință de UI
var
  Violation: AnsiString;
begin
  // Întrebați câmpul dacă profilul cu care urmează să semnăm este permis
  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));
  // Restricție satisfăcută: continuați cu trecerea de semnare
end;

Testul care a expus eroarea originală de decodare nu a fost un test pozitiv. A fost aserțiunea că o nepotrivire forțată trebuie respinsă, iar acesta este singurul tip de test care poate prinde această clasă de defecte: un decoder care citește dicționarul greșit sau pozițiile greșite de biți produce „nicio restricție încălcată" pentru fiecare intrare, ceea ce arată exact ca un comportament corect până încălcați deliberat una

Unde se situează aceasta pe scara LTV

Patru trepte, iar fiecare are nevoie de cea de sub ea. B-B este semnătura nudă. B-T adaugă un marcaj temporal de încredere, care fixează momentul semnării astfel încât un validator știe la ce moment să evalueze revocarea. B-LT adaugă dovezile de revocare în DSS, iar asta automatizează PopulatePAdESLTVEvidence. B-LTA adaugă marcaje temporale de document care sunt reînnoite înainte ca cel anterior să slăbească, prelungind validitatea nelimitat; HotPDF expune aceasta ca RenewPAdESLTATimestamp, care adaugă un marcaj temporal nou ca revizie incrementală și păstrează fiecare semnătură, marcaj temporal și intrare DSS anterioare neatinse

Modelul de update incremental este singura cale corectă de a adăuga dovezi unui document semnat, deoarece rescrierea fișierului ar rupe intervalele de octeți pe care le acoperă semnăturile existente. Dacă trebuie să raționați despre ce s-a schimbat între revizii și dacă acele schimbări sunt de felul pe care o semnătură îl permite, analiza aceea este tratată separat în analiza reviziilor DocMDP și FieldMDP. Pipeline-ul de semnare în sine, inclusiv sursele de certificate și capcanele de ordine a octeților, este în ghidul de semnare PAdES, iar partea de validare este în verificarea semnăturilor pe documente încărcate

Un avertisment practic privind ordinea. Adunați dovezile cât mai curând după semnare, ideal în aceeași sarcină. Respondenții care pot răspunde pentru un certificat sunt online cât timp certificatul este curent și dispăr peste ani, deci un document care vă părăsește pipeline-ul ca B-B s-ar putea să nu mai fie actualizabil vreodată. HotPDF rulează ca o componentă VCL nativă pentru Delphi și C++Builder, iar întreaga trecere de dovezi este în proces, în afara transportului propriu; profilele suportate sunt listate pe pagina de produs HotPDF Delphi PDF component