Sprendimas, kad PDF parašas yra kvalifikuotas pagal eIDAS, reiškia atsakymą į klausimą, neturintį nieko bendro su kriptografija: ar sertifikatą išdavė pasitikėjimo tarnyba, kurią valstybė narė įtraukė į sąrašą kaip kvalifikuotą, parašo padarymo momentu. Atsakymas gyvena patikimajame sąraše — XML dokumente, skelbiamame pagal teritoriją, ir visą to dokumento vertę nulemia jo autentiškumas. Todėl PDFium komponentė atsisako žiūrėti į jo vidų, kol kas nors už jo negarantavo. TPdfEuropeanTrustedList.ParseAuthenticated perduoda visus žalius baitus iškviečiančiojo pateiktai IPdfTrustedListAuthenticator prieš analizuodama bent vieną tarnybą, ir sukuria momentinę kopiją tik tada, jei tas autentifikatorius aiškiai praeina
Tas eiliškumas yra projektas. Visa kita šioje savybėje kyla iš jo, įskaitant dalis, atrodančias nepatogiai
Išanalizuota nereiškia patikima
Patikimas sąrašas, švariai išanalizuotas, sako, kad XML gerai suformuotas. Jis nesako nieko apie tai, kas jį parašė. Kadangi sąrašas yra tai, ant ko ilsisi visas jūsų kvalifikuotos būsenos sprendimas, jo priėmimas vien todėl, kad jis išanalizuotas, paverstų sprendimą beprasmiu: užpuolikas, galintis pakeisti sąrašą, gali paskelbti savo sertifikatų centrą kvalifikuotu
Tas pats samprotavimas taikomas podėliavimui, ir tai spąstai, verti įvardinti. Momentinių kopijų podėlis saugo pradinį XML kartu su SHA-256 maiša, ir būtų lengva traktuoti sutampantį maišą įkėlimo metu kaip įrodymą, kad sąrašas tikras. Tai nėra. Maiša, apskaičiuota to paties proceso, kuris saugojo failą, be jokio rakto, patvirtina tik tai, kad baitai nepasikeitė nuo jų rašymo; jeigu sąrašas buvo apgaulingas, kai buvo podėliuotas, maiša patvirtina, kad tai tas pats apgaulingas sąrašas. Todėl podėlio momentinės kopijos įkėlimas eina per tą patį autentifikatorių kaip šviežio analizavimas. Sveikumas ir autentiškumas yra skirtingos savybės, ir tik vienai jų reikia rakto
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
// Jūsų politika gyvena čia: patikrinkite XMLDSIG įvyniotąjį parašą
// pagal sąrašą pasirašantį sertifikatą, kurį užfiksavote už srauto
// ribų, ir aprašykite, ką tikrinote audito pėdsakui
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);
// Momentinė kopija egzistuoja tik todėl, kad autentifikatorius tarė taip
Cache := TFileStream.Create('tl-de.snapshot', fmCreate);
try
List.SaveCache(Cache);
finally
Cache.Free;
end;
end;
Tikrintojas nesavaldo tinklo politikos
PAdES tikrintojas neturi verslo spręsti, kaip pasiekti patikimų sąrašų sąrašą, ar eiti per įgaliotąjį serverį, kaip dažnai kartoti, ar ką daryti, kai teritorija nepasiekiama. Tie yra programos ir diegimo sprendimai, ir reguliuojamose aplinkose jie dažnai audituojami. Todėl atnaujinimai atkeliauja per IPdfTrustedListSource, kuriam perduodamas URI ir baitų riba, ir kuris grąžina baitus
Ko komponentė iš tikrųjų reikalauja — invariantai, darantys atnaujinimą atnaujinimu, o ne pakeitimu. Update reikalauja, kad teritorija būtų nepakitusi, kad sekos numeris griežtai didėtų ir kad išleidimo laikas nejudėtų atgal. Tie trys patikrinimai įveikia akivaizdžiausius pažeminimo atakas: senesnio sąrašo atkūrimą, vis dar įrašiusio nuo tada atšauktą tarnybą, arba kitos teritorijos sąrašo įmaišymą, kurio tarnybų niekada neketinote pasitikėti
Analizatoriaus ribos ir jokio DTD
TPdfTrustedListOptions riboja XML dydį, simbolių žetonų skaičių, vidinio įdėjimo gylį, tarnybų skaičių, sertifikatų skaičių ir atskiro sertifikato dydį, o Default klasės funkcija teikia tinkamus naudoti dydžius. Patikimi sąrašai yra skelbiami nuspėjamo dydžio dokumentai, todėl ribas pigu nustatyti ir nėra teisėto sąrašo, kurio reikėtų jas viršyti
Atskirai ir besąlygiškai analizatorius atmeta DTD ir esybės (entity) deklaracijas. Tai uždaro ir esybių išplėtimo paslaugų atsisakymą, ir išorinių esybių atskleidimo kelią vienu atmetimu, ir tai nieko nekainuoja, nes patikimi sąrašai nesinaudoja esybėmis. Bet kuris XML analizatorius, pasiekiamas iš nepatikimos įvesties, turėtų būti taip sukonfigūruotas; skirtumas čia tas, kad atmetimas nesukonfigūruojamas, todėl jo negalima išjungti gerašaudišku parinkties pakeitimu
Kvalifikuota būsena užrašoma greta grandinės pasitikėjimo, o ne į ją susiliejama
Vertinimo pusė sąmoningai atskira. TPadesTrustValidationOptions.QualifiedTrustEvaluator priima IPdfQualifiedTrustEvaluator, kurį įgyvendina patikimų sąrašų momentinė kopija. Tikros metu vertintojas gauna lapinį sertifikatą, grandinę ir tikros laiką, gretina tarnybų sertifikatus tikslia DER lyginimu prieš pasirašiusįjį ir grandinę, sujungia tarnybos būseną, tarnybos tipo identifikatorių ir kvalifikatorių URI tuo laiko momentu ir grąžina vertinimo įrašą
Rezultatas atsiduria dvejose kiekvieno parašo vietose: QualifiedTrustStatus kaip stambiabūdė būsena, ir QualifiedTrust kaip pilnas vertinimas su teritorija, teikėjo vardu, tarnybos vardu, tipo identifikatoriumi, būsena ir būsenos pradžios laiku. Ko jis nedaro — nekeičia CertificateTrustStatus. Sisteminis grandinės pasitikėjimas ir kvalifikuota būsena atsako skirtingus klausimus, ir ataskaita, juos suskleidžianti, negali atskirti „patikima, bet ne kvalifikuota“ nuo „kvalifikuota, bet grandinė netikrinama“, — abi realios ir abi reikalaujančios skirtingo tvarkymo
var
Options: TPadesTrustValidationOptions;
Report: TPadesValidationResult;
I: Integer;
begin
Options := TPadesTrustValidationOptions.Default;
Options.CheckRevocation := True;
Options.QualifiedTrustEvaluator := List; // patvirtinta momentinė kopija
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
// Nėra atitinkančios tarnybos, arba momentinė kopija negali atsakyti už šį laiką
Writeln(Format('signature %d: qualified status undetermined', [I]));
end;
Kodėl tikros laikas nėra dabar
Nes kvalifikacija yra momento savybė. Pasitikėjimo tarnybai gali būti suteikta kvalifikuota būsena, vėliau ji gali būti atšaukta, o dar vėliau atstatyta, ir kiekvienas tų perėjimų neša pradžios laiką sąraše. Parašas, padarytas, kai tarnyba buvo kvalifikuota, ir po to lieka kvalifikuotas; parašas, padarytas prieš suteikimą, neįgauna kvalifikacijos atgaline data. Vertinimas pagal esamą laiką todėl duoda neteisingą atsakymą abiem kryptimis
Sąrašas neša tai, ko tam reikia: kiekvienas tarnybos įrašas turi būsenos pradžios laiką ir vėliavėlę, atskiriančią istorinius įrašus nuo esamųjų, o vertintojas juos sujungia pagal jūsų pateiktą laiką. Praktikoje tas laikas ateina iš patikimo laiko žymos ant parašo, o ne iš CMS teikiamos pasirašymo laiko, todėl ilgalaikio tikrinimo medžiaga svarbi net klausimui, kuris atrodo kaip politikos paieška; laiko žymos ir DSS pusė dengiama ilgalaikio parašo straipsnyje
Ką vis dar turite pastatyti
Trys dalykai, ir nė vienas nepriklauso PDF bibliotekai. Autentifikatorius — tikra XMLDSIG patikra pagal sąrašą pasirašantį sertifikatą, gautą kanalu, kuriuo pasitikite. Gavimo politika — kaip ir kaip dažnai atnaujinate ir ką jūsų programa daro, kai atnaujinimas nepavyksta. Ir teritorinė apimtis — kuriuos sąrašus apskritai nešate, kas yra verslo sprendimas, kuriuose valstybėse narėse pasirašo jūsų kontrahentai
Ko gaunate iš komponentės — dalis, kurioje lengva subtiliai suklysti: pirmiausia patvirtinti, paskui analizuoti eiliškumas, ribotas ir be esybių XML analizavimas, monotoniniai atnaujinimų invariantai, tikslus DER tarnybų gretinimas, istorinė būsenos vertė ir rezultatas, liekantis atskiras nuo paprasto grandinės pasitikėjimo. Jeigu jūsų tiesioginė problema elementariau — tikrintojas atmeta parašą, kurį manote teisėtu, — įprastos priežastys surūšiuotos kodėl tikrintojai atmeta PAdES parašus, o parašų apžiūros paviršius aprašytas parašų ir PAdES lygių apžiūroje. Komponentės galimybės išvardytos PDFium Delphi component produkto puslapyje