Technický článek

Seznamy důvěry eIDAS a kvalifikované podpisy PDF

Usoudit, že PDF podpis je kvalifikovaný podle eIDAS, znamená odpovědět na otázku, která s kryptografií nemá nic společného: byl certifikát vydán službou důvěry, kterou členský stát uvedl jako kvalifikovanou, v okamžiku, kdy podpis vznikl. Odpověď žije v seznamu důvěry, XML dokumentu publikovaném na území, a celá hodnota toho dokumentu závisí na jeho autenticitě. Proto komponenta PDFium odmítá nahlédnout dovnitř, dokud se za ni někdo nepřimluví. TPdfEuropeanTrustedList.ParseAuthenticated podá kompletní surové bajty volajícím dodanému IPdfTrustedListAuthenticator dříve, než parsuje jedinou službu, a snímek vytvoří, jen pokud ten autentizátor explicitně projde

Tok autentizuj-před-parsováním pro evropský seznam důvěry v Delphi: surové XML z čerstvého stažení nebo cachovaného snímku projde IPdfTrustedListAuthenticator, než TPdfEuropeanTrustedList cokoli parsuje
Čerstvé i cachované seznamy potkají týž autentizátor a snímek existuje jen po tom, co projde

To pořadí je návrh. Všechno ostatní v této funkci z něj plyne, včetně částí, které vypadají neobvykle nepohodlně

Naparsováno není důvěryhodné

Seznam důvěry, který se čistě naparsuje, vám řekne, že XML je dobře utvářené. Neřekne vám nic o tom, kdo jej napsal. Protože seznam je to, na čem spočívá vaše celé rozhodnutí o kvalifikovaném stavu, přijmout jeden proto, že se naparsoval, by rozhodnutí učinilo nesmyslným: útočník, který dokáže seznam vyměnit, může prohlásit vlastní certifikační autoritu za kvalifikovanou

Tatáž úvaha platí pro cachování a to je past hodná pojmenování. Snímková cache ukládá původní XML spolu s otiskem SHA-256 a snadno by se dalo brát shodný otisk při načtení jako důkaz, že seznam je pravý. Není. Otisk spočítaný tím samým procesem, který soubor uložil, bez zapojení klíče, ověřuje jen to, že se bajty od zapsání nezměnily; byl-li seznam podvodný v okamžiku cachování, otisk potvrzuje, že jde o tentýž podvodný seznam. Načtení cachovaného snímku proto prochází týmž autentizátorem jako parsování čerstvého. Integrita a autenticita jsou různé vlastnosti a jen jedna z nich potřebuje klíč

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še politika žije zde: ověřte obálkový podpis XMLDSIG
  // proti certifikátu podepisujícímu seznam, který jste si připnuli
  // mimo kanál, a popište, co jste zkontrolovali pro 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);
  // Snímek existuje jen proto, že autentizátor řekl ano
  Cache := TFileStream.Create('tl-de.snapshot', fmCreate);
  try
    List.SaveCache(Cache);
  finally
    Cache.Free;
  end;
end;

Validátor nevlastní síťovou politiku

PAdES validátor nemá co rozhodovat o tom, jak se dostat k seznamu seznamů důvěry, zda jít přes proxy, jak často opakovat nebo co dělat, když je území nedostupné. To jsou rozhodnutí aplikace a nasazení a v regulovaných prostředích se často auditují. Aktualizace proto přicházejí přes IPdfTrustedListSource, kterému se podá URI a bajtový strop a jenž vrací bajty

To, co komponenta vynucuje, jsou invarianty, které činí z aktualizace aktualizaci, nikoli záměnu. Update vyžaduje, že území se nezměnilo, že číslo sekvence přísně roste a že čas vydání se nepohne zpět. Tyto tři kontroly porazí nejzjevnější downgrade útoky: přehrání staršího seznamu, který stále uvádí mezitím staženou službu, nebo vyměnění seznamu jiného území, jehož službám jste nikdy nechtěli důvěřovat

Invarianty aktualizace vynucované komponentou seznamů důvěry PDFium: nezměněné území, přísně rostoucí číslo sekvence a čas vydání, který se nikdy nepohne zpět, což dohromady blokuje downgrade útoky
Tři monotonní kontroly oddělují skutečnou aktualizaci od přehraného nebo vyměněného seznamu

Limity parseru a žádné DTD vůbec

TPdfTrustedListOptions omezuje velikost XML, počet tokenů, hloubku zanoření, počet služeb, počet certifikátů a velikost jednotlivého certifikátu a třídní funkce Default podává použitelné hodnoty. Seznamy důvěry jsou publikované dokumenty předvídatelné velikosti, takže meze se nastavují levně a neexistuje legitimní seznam, který by je potřeboval překročit

Zvlášť a bezpodmínečně parser odmítá deklarace DTD a entit. To zavírá jak odmítnutí služby expanzí entit, tak cestu prozrazení externí entitou jediným odmítnutím a nic to nestojí, protože seznamy důvěry entity nepoužívají. Jakýkoli XML parser dosažitelný z nedůvěryhodného vstupu by měl být takto nakonfigurován; rozdíl zde je v tom, že odmítnutí není konfigurovatelné, takže jej nelze vypnout dobře míněnou změnou volby

Kvalifikovaný stav se zaznamenává vedle důvěry řetězce, neslučuje se do ní

Vyhodnocovací strana je záměrně oddělená. TPadesTrustValidationOptions.QualifiedTrustEvaluator přebírá IPdfQualifiedTrustEvaluator, který snímek seznamu důvěry implementuje. Během validace obdrží vyhodnocovač listový certifikát, řetězec a čas validace, páruje certifikáty služeb přesnou DER srovnávací metodou proti podepisujícímu a řetězci, spojuje stav služby, identifikátor typu služby a URI kvalifikátorů v tom okamžiku a vrací vyhodnocovací záznam

Výsledek dopadá na dvě místa u každého podpisu: QualifiedTrustStatus jako hrubý stav a QualifiedTrust jako plné vyhodnocení s územím, názvem poskytovatele, názvem služby, identifikátorem typu, stavem a počátečním časem stavu. To, co nedělá, je změna CertificateTrustStatus. Systémová důvěra řetězce a kvalifikovaný stav odpovídají na různé otázky a hlášení, které je slejí dohromady, nedokáže rozlišit „důvěryhodný, ale nekvalifikovaný“ od „kvalifikovaný, ale řetězec nevaliduje“, přičemž obojí je skutečné a obojí potřebuje jinou obsluhu

Vyhodnocení kvalifikované důvěry PAdES v Delphi: IPdfQualifiedTrustEvaluator páruje certifikáty služeb přesnou DER srovnávací metodou a vyplní QualifiedTrustStatus a QualifiedTrust, zatímco CertificateTrustStatus zůstává nedotčen
Důvěra řetězce a kvalifikovaný stav eIDAS se zaznamenávají vedle sebe, takže obě zjištění zůstávají viditelná
var
  Options: TPadesTrustValidationOptions;
  Report: TPadesValidationResult;
  I: Integer;
begin
  Options := TPadesTrustValidationOptions.Default;
  Options.CheckRevocation := True;
  Options.QualifiedTrustEvaluator := List;      // autentizovaný snímek
  Options.QualifiedValidationTime := SigningTime; // nikoli 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
      // Žádná odpovídající služba, nebo snímek nemůže odpovědět za tento čas
      Writeln(Format('signature %d: qualified status undetermined', [I]));
end;

Proč čas validace není právě teď

Protože kvalifikace je vlastnost okamžiku. Služba důvěry může být oceněna kvalifikovaným stavem, později jej může ztratit a později ještě být obnovena a každý z těch přechodů nese ve seznamu počáteční čas. Podpis učiněný, dokud byla služba kvalifikovaná, zůstává kvalifikovaný i poté; podpis učiněný před udělením se nekvalifikuje dodatečně. Vyhodnocení proti aktuálnímu času proto dává špatnou odpověď oběma směry

Seznam nese to, co je k tomu potřeba: každý záznam služby má počáteční čas stavu a příznak rozlišující historické položky od aktuálních a vyhodnocovač je kombinuje proti času, který dodáte. V praxi ten čas pochází z důvěryhodného časového razítka na podpisu, nikoli z času podpisu tvrzeného v CMS, což je důvod, proč materiál dlouhodobého ověřování záleží i u otázky, která vypadá jako dohledání politiky; strana razítka a DSS je předmětem článku o dlouhodobých podpisech

Co ještě musíte postavit

Tři věci a žádná z nepatří do PDF knihovny. Autentizátor, tedy skutečné ověření XMLDSIG proti certifikátu podepisujícímu seznam, který jste získali kanálem, kterému věříte. Politika stahování, tedy jak a jak často obnovujete a co dělá vaše aplikace, když obnovení selže. A územní rozsah, tedy které seznamy vůbec nesete, což je byznys rozhodnutí o tom, v kterých členských státech podepisují vaše protistrany

Co od komponenty dostáváte, je ta část, kterou je snadné jemně pokazit: pořadí autentizuj-před-parsováním, ohraničené parsování XML bez entit, monotonní invarianty aktualizace, párování služeb přesným DER, historické vyhodnocování stavu a výsledek, který zůstává oddělený od obyčejné důvěry řetězce. Je-li váš bezprostřední problém základnější, že validátor odmítá podpis, o němž jste přesvědčeni, že je v pořádku, obvyklé příčiny jsou katalogizovány v proč validátory odmítají podpisy PAdES a povrch inspekce podpisů popisuje inspekce podpisů a úrovní PAdES. Schopnosti komponenty jsou uvedeny na stránce produktu PDFium Delphi component