Tehnički članak

eIDAS popisi poverenja i kvalifikovani PDF potpisi

Odlučivanje da je PDF potpis kvalifikovan pod eIDAS znači odgovaranje na pitanje koje nema nikakve veze sa kriptografijom: da li je sertifikat izdat od servisa poverenja koji je država članica navela kao kvalifikovan, u trenutku kada je potpis učinjen. Odgovor živi u popisu poverenja, XML dokumentu objavljenom po teritoriji, i cela vrednost tog dokumenta zavisi od njegove autentičnosti. Pa PDFium komponenta odbija da zagleda unutra dok neko ne jamči za nju. TPdfEuropeanTrustedList.ParseAuthenticated predaje kompletne sirove bajtove IPdfTrustedListAuthenticator-u koji dostavlja pozivalac pre nego što raščlani ijedan servis, i stvara snimak samo ako taj autentikator eksplicitno prolazi

Tok potvrdi-pre-raščlanjivanja za evropski popis poverenja u Delphi-ju: sirovi XML iz svežeg preuzimanja ili keširanog snimka prolazi kroz IPdfTrustedListAuthenticator pre nego što TPdfEuropeanTrustedList raščlani bilo šta
Sveži i keširani popisi susreću isti autentikator, i snimak postoji tek posle što on prolazi

To uređenje je dizajn. Sve ostalo u ovoj funkciji proizlazi iz njega, uključujući delove koji deluju nezgodno

Raščlanjeno nije isto što i povereno

Popis poverenja koji se čisto raščlani kaže vam da je XML dobro oblikovan. Ne kaže vam ništa o tome ko ga je napisao. Pošto je popis ono na čemu počiva cela vaša odluka o kvalifikovanom statusu, prihvatanje jednog zato što se raščlanio učinilo bi odluku besmislenom: napadač koji može zameniti popis može proglasiti sopstveni sertifikatski autoritet kvalifikovanim

Isto rasuđivanje primenjuje se na keširanje, i to je zamka vredna imenovanja. Keš snimaka čuva prvobitni XML zajedno sa SHA-256 sažetkom, i lako bi bilo tretirati poklapajući sažetak pri učitavanju kao dokaz da je popis pravi. Nije. Sažetak izračunat od istog procesa koji je čuvao datoteku, bez uključenog ključa, verifikuje samo da se bajtovi nisu promenili otkako ste ih napisali; ako je popis bio prevaran kada je keširan, sažetak potvrđuje da je isti prevarni popis. Pa učitavanje keširanog snimka ide kroz isti autentikator kao raščlanjivanje svežeg. Celovitost i autentičnost različita su svojstva i samo jedno od njih traži ključ

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 živi ovde: verifikujte XMLDSIG omotani potpis
  // protiv sertifikata potpisivanja popisa koji ste pribili van opsega,
  // i opišite šta ste proverili za revizionu tragu
  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);
  // Snimak postoji samo zato što je autentikator rekao da
  Cache := TFileStream.Create('tl-de.snapshot', fmCreate);
  try
    List.SaveCache(Cache);
  finally
    Cache.Free;
  end;
end;

Validator ne poseduje mrežnu politiku

PAdES validator nema posao odlučivati kako dopreti do popisa popisa poverenja, da li ići kroz proksi, koliko često ponoviti, ili šta činiti kada je teritorija nedostižna. To su odluke aplikacije i raspoređivanja, i u regulisanim okruženjima često su revizionirane. Pa ažuriranja stižu kroz IPdfTrustedListSource, kojem se predaje URI i granica bajtova i koji vraća bajtove

Ono što komponenta sprovodi jesu invarijante koje čine ažuriranje ažuriranjem umesto zamenom. Update traži da je teritorija nepromenjena, da se serijski broj strogo uvećava, i da se vreme izdavanja ne pomera nazad. Te tri provere pobeđuju najočiglednije napade obaranja: ponavljanje starijeg popisa koji još navodi uslugu od tada povučenu, ili ubacivanje popisa druge teritorije čije usluge nikad niste nameravali verovati

Invarijante ažuriranja koje sprovodi PDFium komponenta popisa poverenja: nepromenjena teritorija, strogo rastući serijski broj i vreme izdavanja koje se nikad ne pomera nazad, što zajedno blokira napade obaranja
Tri monotonije provere razdvajaju pravo ažuriranje od ponovljenog ili zamenjenog popisa

Granice parsera, i nikakav DTD

TPdfTrustedListOptions ograničava XML veličinu, broj tokena, dubinu ugrađivanja, broj servisa, broj sertifikata i veličinu pojedinačnog sertifikata, sa klasnom funkcijom Default koja daje upotrebljive vrednosti. Popisi poverenja objavljeni su dokumenti predvidive veličine, pa su granice jeftine za postaviti i nema legitimnog popisa kojem treba prekoračiti ih

Odvojeno i bezuslovno, parser odbacuje DTD i deklaracije entiteta. To zatvara i uskraćenje usluge širenjem entiteta i put otkrivanja spoljašnjim entitetom u jedno odbijanje, i ne košta ništa jer popisi poverenja ne koriste entitete. Svaki XML parser dostižan iz nepoverljivog ulaza trebao bi biti tako konfigurisan; razlika ovde je što odbijanje nije konfigurabilno, pa ga ne može isključiti dobronamerna izmena opcije

Kvalifikovani status beleži se pored poverenja lanca, ne stapa u njega

Strana evaluacije namerno je odvojena. TPadesTrustValidationOptions.QualifiedTrustEvaluator prima IPdfQualifiedTrustEvaluator, koji snimak popisa poverenja implementira. Tokom validacije evaluator prima listni sertifikat, lanac i vreme validacije, poklapa sertifikate servisa tačnim DER poređenjem protiv potpisnika i lanca, kombinuje status servisa, identifikator tipa servisa i URI-je kvalifikatora u tom trenutku, i vraća zapis evaluacije

Rezultat sleće na dva mesta na svakom potpisu: QualifiedTrustStatus kao grubi status, i QualifiedTrust kao puna evaluacija sa teritorijom, imenom pružaoca, imenom servisa, identifikatorom tipa, statusom i vremenom početka statusa. Ono što ne radi jeste promena CertificateTrustStatus. Sistemsko poverenje lanca i kvalifikovani status odgovaraju različitim pitanjima, i izveštaj koji ih skupi ne može razlikovati "poverljivo ali ne kvalifikovano" od "kvalifikovano ali lanac se ne validira", od kojih su oba stvarna i oba traže različito rukovanje

PAdES evaluacija kvalifikovanog poverenja u Delphi-ju: IPdfQualifiedTrustEvaluator poklapa sertifikate servisa tačnim DER poređenjem i puni QualifiedTrustStatus i QualifiedTrust dok CertificateTrustStatus ostaje netaknut
Poverenje lanca i eIDAS kvalifikovani status beleže se uporedo pa oba nalaza ostaju vidljiva
var
  Options: TPadesTrustValidationOptions;
  Report: TPadesValidationResult;
  I: Integer;
begin
  Options := TPadesTrustValidationOptions.Default;
  Options.CheckRevocation := True;
  Options.QualifiedTrustEvaluator := List;      // autentikovani snimak
  Options.QualifiedValidationTime := SigningTime; // ne 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
      // Nema poklapajućeg servisa, ili snimak ne može odgovoriti za ovo vreme
      Writeln(Format('signature %d: qualified status undetermined', [I]));
end;

Zašto vreme validacije nije sada

Zato je kvalifikacija svojstvo trenutka. Servisu poverenja može biti dodeljen kvalifikovani status, kasnije povučen, i kasnije još vraćen, i svaki od tih prelaza nosi vreme početka u popisu. Potpis učinjen dok je servis bio kvalifikovan ostaje kvalifikovan posle; potpis učinjen pre dodele ne postaje kvalifikovan retroaktivno. Evaluacija protiv trenutnog vremena dakle daje pogrešan odgovor u oba smera

Popis nosi ono što je potrebno za ovo: svaki zapis servisa ima vreme početka statusa i zastavicu koja razlikuje istorijske unose od tekućih, i evaluator ih kombinuje protiv vremena koje vi dostavite. U praksi to vreme dolazi iz poverljive vremenske oznake na potpisu umesto iz vremena potpisivanja tvrđenog u CMS-u, što je razlog zašto materijal dugoročne validacije važi čak i za pitanje koje deluje kao upit politike; strana vremenske oznake i DSS-a pokrivena je u članku o dugoročnim potpisima

Šta još morate izgraditi

Tri stvari, i nijedna ne pripada PDF biblioteci. Autentikator, značeći stvarnu XMLDSIG verifikaciju protiv sertifikata potpisivanja popisa kojeg ste nabavili kanalom kome verujete. Politika preuzimanja, značeći kako i koliko često osvežavate, i šta vaša aplikacija radi kada osvežavanje otkazuje. I teritorijalni obuhvat, značeći koje popise uopšte nosite, što je poslovna odluka o državama članicama u kojima vaši partneri potpisuju

Ono što dobijate od komponente jeste deo koji je lako pogrešiti suptilno: uređenje potvrdi-pre-raščlanjivanja, ograničeno i entitetima-slobodno XML parsiranje, monotonije invarijante ažuriranja, poklapanje servisa tačnim DER-om, istorijska evaluacija statusa, i rezultat koji ostaje odvojen od običnog poverenja lanca. Ako je vaš neposredan problem osnovniji, da validator odbija potpis za koji verujete da je u redu, uobičajeni uzroci katalogizovani su u zašto validatori odbijaju PAdES potpise, a površina pregleda potpisa opisana je u pregledu potpisa i PAdES nivoa. Mogućnosti komponente navedene su na stranici proizvoda PDFium Delphi component