Odborný článok

Trusted listy eIDAS a kvalifikované podpisy PDF

Rozhodnúť, že podpis PDF je kvalifikovaný podľa eIDAS, znamená odpovedať na otázku, ktorá nemá nič s kryptografiou: bol certifikát vydaný službou dôvery, ktorú členský štát vypísal ako kvalifikovanú, v momente, keď bol podpis urobený. Odpoveď býva v trusted liste, XML dokumente publikovanom per územie, a celá hodnota toho dokumentu závisí od jeho autentickosti. Preto komponent PDFium odmieta pozrieť sa dovnútra, kým sa zaň niekto prihovorí. TPdfEuropeanTrustedList.ParseAuthenticated odovzdá kompletné surové bajty volajúcim dodanému IPdfTrustedListAuthenticator skôr, než parsuje jedinú službu, a vytvorí snapshot len vtedy, keď ten autentizátor výslovne prejde

Tok autentizuj-pred-parsovaním pre európsky trusted list v Delphi: surové XML z čerstvého stiahnutia alebo cacheovaného snapshotu prechádza cez IPdfTrustedListAuthenticator skôr, než TPdfEuropeanTrustedList niečo parsuje
Čerstvé aj cacheované listy stretávajú ten istý autentizátor a snapshot existuje až po jeho prejdení

Toto poradie je návrh. Všetko ostatné v tejto funkcii z neho vyplýva, vrátane častí, ktoré vyzerajú nepríjemne

Parseované nie je dôveryhodné

Trusted list, ktorý sa parseuje čisto, vám hovorí, že XML je formálne správne. Nepovie vám nič o tom, kto ho napísal. Keďže list je to, na čom spočíva vaše celé rozhodnutie o kvalifikovanom statuse, prijatie jedného preto, že sa parseoval, by urobilo rozhodnutie bezvýznamným: útočník, ktorý dokáže list vymeniť, môže deklarovať vlastnú certifikačnú autoritu za kvalifikovanú

Toto isté uvažovanie platí pre cacheovanie a toto je pasca hodná pomenovania. Snapshot cache uchováva pôvodné XML spolu s digestom SHA-256 a bolo by ľahké brať zhodný digest pri načítaní ako dôkaz, že list je pravý. Nie je. Digest vypočítaný tým istým procesom, ktorý súbor uložil, bez zapojenia akéhokoľvek kľúča, overuje len to, že bajty sa nezmenili od chvíle, keď ste ich zapísali; ak bol list podvodný v čase cacheovania, digest potvrdzuje, že ide o ten istý podvodný list. Načítanie cacheovaného snapshotu preto beží cez ten istý autentizátor ako parsovanie čerstvého. Integrita a autentickosť sú odlišné vlastnosti a len jedna z nich potrebuje kľúč

uses
  FPdfTrustedList;

type
  TListAuthenticator = class(TInterfacedObject, IPdfTrustedListAuthenticator)
  public
    function Authenticate(const XmlData: TBytes;
      out AuthenticationDetails: string): Boolean;
  end;

function TListAuthenticator.Authenticate(const XmlData: TBytes;
  out AuthenticationDetails: string): Boolean;
begin
  // Vaša politika býva tu: overiť obalený podpis XMLDSIG
  // voči certifikátu podpisujúcemu list, ktorý ste pripinuli mimo pásma,
  // a popísať, čo ste kontrolovali, pre auditnú stopu
  Result := VerifyEnvelopedXmlSignature(XmlData, FPinnedListSigner);
  if Result then
    AuthenticationDetails := 'XMLDSIG verified against pinned LOTL signer';
end;

var
  List: TPdfEuropeanTrustedList;
  Cache: TFileStream;
begin
  List := TPdfEuropeanTrustedList.ParseAuthenticated(RawXml,
    TListAuthenticator.Create, TPdfTrustedListOptions.Default);
  // Snapshot existuje len preto, lebo autentizátor povedal áno
  Cache := TFileStream.Create('tl-de.snapshot', fmCreate);
  try
    List.SaveCache(Cache);
  finally
    Cache.Free;
  end;
end;

Validátor nevlastní sieťovú politiku

Validátor PAdES nemá čo rozhodovať, ako sa dostať k listu trusted listov, či ísť cez proxy, ako často opakovať, alebo čo robiť, keď je územie nedosiahnuteľné. Toto sú rozhodnutia aplikácie a nasadenia a v regulovaných prostrediach sú často auditované. Aktualizácie preto prichádzajú cez IPdfTrustedListSource, ktorému sa odovzdá URI a bajtový strop a ktorý vracia bajty

To, čo komponent vynucuje, sú invarianty, ktoré robia z aktualizácie aktualizáciu, nie zámenu. Update vyžaduje, že územie je nezmenené, že číslo sekvencie prísne rastie a že čas vydania sa nepohne dozadu. Tieto tri kontroly porazia najzjavnejšie downgrade útoky: prehrávanie staršieho listu, ktorý stále vypisuje odvtedy stiahnutú službu, alebo zapojenie listu iného územia, ktorého služby ste nikdy nechceli brať za dôveryhodné

Invarianty aktualizácie vynucované komponentom trusted listov PDFium: nezmenené územie, prísne rastúce číslo sekvencie a čas vydania, ktorý sa nikdy nepohne dozadu, čo spolu blokujú downgrade útoky
Tri monotonické kontroly oddeľujú skutočnú aktualizáciu od prehranej alebo zamenej listy

Limity parsera a žiadne DTD vôbec

TPdfTrustedListOptions stropuje veľkosť XML, počet tokenov, hĺbku zanorenia, počet služieb, počet certifikátov a veľkosť jednotlivého certifikátu, pričom triedová funkcia Default dodáva použiteľné hodnoty. Trusted listy sú publikované dokumenty predvídateľnej veľkosti, takže hranice sa nastavujú lacno a neexistuje legitímny list, ktorý by ich potreboval presiahnuť

Osobitne a bezpodmienečne parser odmieta deklarácie DTD a entít. Tým zatvára v jednom odmietnutí aj zamietnutie služby expanziou entít aj cestu prezrádzania externými entitami a nestojí to nič, pretože trusted listy nepoužívajú entity. Akýkoľvek XML parser dosiahnuteľný z nedôveryhodného vstupu by mal byť takto nakonfigurovaný; rozdiel tu je, že odmietnutie nie je konfigurovateľné, takže ho nemožno vypnúť dobre mínenej zmenou voľby

Kvalifikovaný status sa zaznamenáva vedľa dôvery reťaze, neslučuje sa do nej

Strana vyhodnocovania je zámerne osobitná. TPadesTrustValidationOptions.QualifiedTrustEvaluator berie IPdfQualifiedTrustEvaluator, ktorý snapshot trusted listu implementuje. Počas validácie prijíma evaluátor listový certifikát, reťaz a čas validácie, zhoduje certifikáty služieb presným DER porovnaním voči podpisovateľovi a reťazi, kombinuje status služby, identifikátor typu služby a URI kvalifikátorov v tom okamihu a vracia záznam vyhodnotenia

Výsledok pristane na dvoch miestach na každom podpise: QualifiedTrustStatus ako hrubý status a QualifiedTrust ako úplné vyhodnotenie s územím, menom poskytovateľa, menom služby, identifikátorom typu, statusom a časom začiatku statusu. To, čo nespraví, je zmena CertificateTrustStatus. Systémová dôvera reťaze a kvalifikovaný status odpovedajú na odlišné otázky a správa, ktorá ich zrúti, nedokáže rozlíšiť „dôveryhodný, ale nie kvalifikovaný“ od „kvalifikovaný, ale reťaz nevaliduje“, pričom oba sú reálne a oba potrebujú odlišné zaobchádzanie

Vyhodnocovanie kvalifikovanej dôvery PAdES v Delphi: IPdfQualifiedTrustEvaluator zhoduje certifikáty služieb presným DER porovnaním a vyplní QualifiedTrustStatus a QualifiedTrust, kým CertificateTrustStatus zostáva nedotknutý
Dôvera reťaze a kvalifikovaný status eIDAS sa zaznamenávajú vedľa seba, takže oba nálezy zostávajú viditeľné
var
  Options: TPadesTrustValidationOptions;
  Report: TPadesValidationResult;
  I: Integer;
begin
  Options := TPadesTrustValidationOptions.Default;
  Options.CheckRevocation := True;
  Options.QualifiedTrustEvaluator := List;      // autentizovaný snapshot
  Options.QualifiedValidationTime := SigningTime; // nie Now
  Report := Pdf.ValidatePadesTrust(Options);

  for I := 0 to High(Report.Signatures) do
    if Report.Signatures[I].QualifiedTrustStatus = pcsValid then
      Writeln(Format('signature %d qualified by %s / %s (%s)',
        [I, Report.Signatures[I].QualifiedTrust.Territory,
         Report.Signatures[I].QualifiedTrust.ProviderName,
         Report.Signatures[I].QualifiedTrust.ServiceName]))
    else if Report.Signatures[I].QualifiedTrustStatus = pcsIndeterminate then
      // Žiadna zhodná služba, alebo snapshot nedokáže odpovedať za tento čas
      Writeln(Format('signature %d: qualified status undetermined', [I]));
end;

Prečo čas validácie nie je teraz

Pretože kvalifikácia je vlastnosť okamihu. Službe dôvery môže byť priznaný kvalifikovaný status, neskôr odobratý a ešte neskôr obnovený a každý z týchto prechodov nesie v liste čas začiatku. Podpis urobený, kým bola služba kvalifikovaná, zostáva kvalifikovaný aj potom; podpis urobený pred priznaním sa nestráva kvalifikovaným spätne. Vyhodnocovanie voči aktuálnemu času preto dáva zlú odpoveď oboma smermi

List nesie to, čo je na to potrebné: každý záznam služby má čas začiatku statusu a príznak rozlišujúci historické záznamy od aktuálnych a evaluátor ich kombinuje voči času, ktorý dodáte. V praxi ten čas pochádza z dôveryhodnej časovej pečiatky na podpise, nie z času podpisovania tvrdeného v CMS, čo je dôvod, prečo materiál dlhodobej validácie má význam aj pre otázku, ktorá vyzerá ako dohľadanie politiky; strana pečiatky a DSS je pokrytá v článku o dlhodobých podpisoch

Čo ešte musíte postaviť

Tri veci a žiadna z nich nepatrí do PDF knižnice. Autentizátor, teda skutočné overenie XMLDSIG voči certifikátu podpisujúcemu list, ktorý ste získali kanálom, ktorému veríte. Politika sťahovania, teda ako a ako často obnovujete a čo vaša aplikácia robí, keď obnovenie zlyhá. A územný rozsah, teda ktoré listy vôbec nosíte, čo je obchodné rozhodnutie o tom, v ktorých členských štátoch podpisujú vaše protistrany

To, čo od komponentu dostanete, je časť, ktorá sa ľahko pokazí jemne: poradie autentizuj-pred-parsovaním, ohraničené parsovanie XML bez entít, monotonické invarianty aktualizácie, zhodovanie služieb presným DER, historické vyhodnocovanie statusu a výsledok, ktorý zostáva oddelený od bežnej dôvery reťaze. Ak je váš bezprostredný problém základnejší, že validátor odmieta podpis, o ktorom veríte, že je v poriadku, obvyklé príčiny sú skatalogizované v prečo validátory odmietajú podpisy PAdES a povrch inšpekcie podpisov popisuje inšpekcia podpisov a úrovní PAdES. Schopnosti komponentu sú uvedené na produktovej stránke PDFium Delphi component