Sen päättäminen, että PDF-allekirjoitus on kvalifioitu eIDAS:n mukaan, tarkoittaa kysymykseen vastaamista, jolla ei ole mitään tekemistä kryptografian kanssa: myönsikö jäsenvaltion kvalifioiduksi luettelu luottamuspalvelu sertifikaatin sillä hetkellä, kun allekirjoitus tehtiin. Vastaus asuu luottamusluettelossa, alueittain julkaistussa XML-dokumentissa, ja koko kyseisen dokumentin arvo riippuu sen aitoudesta. Niinpä PDFium-komponentti kieltäytyy katsomasta sellaisen sisään, kunnes joku on taannut sen. TPdfEuropeanTrustedList.ParseAuthenticated ojittaa täydet raakatavut kutsujan toimittamalle IPdfTrustedListAuthenticatorille ennen kuin se jäsentää yhtään palvelua, ja se luo snapshotin vain, jos kyseinen autentikoija hyväksyy eksplisiittisesti
Tuo järjestys on suunnittelu. Kaikki muu tässä ominaisuudessa seuraa siitä, mukaan lukien osat, jotka näyttävät hankalilta
Jäsennetty ei ole luotettu
Luottamusluettelo, joka jäsentyy puhtaasti, kertoo, että XML on hyvin muodostettu. Se ei kerro mitään siitä, kuka sen kirjoitti. Koska luettelo on se, mihin koko kvalifioidun tilan päätöksesi nojaa, yhden hyväksyminen sen vuoksi, että se jäsentyi, tekisi päätöksestä merkityksettömän: hyökkääjä, joka voi korvata luettelon, voi julistaa oman sertifikaattiviranomaisensa kvalifioiduksi
Sama päättely pätee välimuistitukseen, ja tämä on ansa, joka kannattaa nimetä. Snapshot-välimuisti tallentaa alkuperäisen XML:n yhdessä SHA-256-tiivisteen kanssa, ja olisi helppo käsitellä täsmäävää tiivistettä ladattaessa todisteena siitä, että luettelo on aito. Se ei ole. Tiiviste, jonka laski sama prosessi, joka tallensi tiedoston, ilman avainta, varmistaa vain, että tavut eivät ole muuttuneet sen jälkeen, kun kirjoitit ne; jos luettelo oli vilpillinen välimuistitettaessa, tiiviste vahvistaa, että kyseessä on sama vilpillinen luettelo. Niinpä välimuistin snapshotin lataaminen kulkee saman autentikoijan kautta kuin tuoreen jäsentäminen. Eheys ja aitous ovat eri ominaisuuksia, ja vain toinen niistä tarvitsee avaimen
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
// Politiikkasi asuu tässä: varmista XMLDSIG-kääreallekirjoitus
// pinnaamaasi luetteloiden allekirjoitussertifikaattia vastaan,
// ja kuvaa, mitä tarkistit auditointijäljelle
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 on olemassa vain siksi, että autentikoija sanoi kyllä
Cache := TFileStream.Create('tl-de.snapshot', fmCreate);
try
List.SaveCache(Cache);
finally
Cache.Free;
end;
end;
Validoija ei omista verkkopolitiikkaa
PAdES-validoijalla ei ole asiaa päättää, miten luetteloiden luettelo tavoitetaan, käydäänkö välikäsen kautta, kuinka usein yritetään uudelleen tai mitä tehdään, kun alue on saavuttamaton. Nuo ovat sovellus- ja jakelupäätöksiä, ja säännellyissä ympäristöissä ne auditoidaan usein. Niinpä päivitykset saapuvat kohteen IPdfTrustedListSource kautta, jolle annetaan URI ja tavukatto ja joka palauttaa tavuja
Sen, mitä komponentti valvoo, ovat invariantit, jotka tekevät päivityksestä päivityksen eivät korvikkeita. Update vaatii, että alue on muuttumaton, että sarjanumero kasvaa tiukasti ja että myöntämisaika ei liiku taaksepäin. Nuo kolme tarkistusta kukistavat ilmeisimmät alennushyökkäykset: vanhemman luettelon toistaminen, joka yhä luetteloi sittemmin peruutetun palvelun, tai toisen alueen luettelon vaihtaminen paikalleen, jonka palveluihin et koskaan aikonut luottaa
Jäsentimen rajat, ei DTD:tä lainkaan
TPdfTrustedListOptions rajoittaa XML:n koon, tokenien määrän, sisäkkäisyyssyvyyden, palveluiden määrän, sertifikaattien määrän ja yksittäisen sertifikaatin koon, ja luokkafunktio Default toimittaa käytettäviä arvoja. Luottamusluettelot ovat julkaistuja dokumentteja, joiden koko on ennustettava, joten rajat on halpaa asettaa, eikä mikään laillinen luettelo tarvitse ylittää niitä
Erikseen ja ehdottomasti jäsentin hylkää DTD- ja entiteettideklaraatiot. Se sulkee sekä entiteetin laajennuksen palvelunestohyökkäyksen että ulkoisen entiteetin paljastusreitin yhdellä kieltäytymisellä, eikä se maksa mitään, koska luottamusluettelot eivät käytä entiteettejä. Mikä tahansa XML-jäsentin, joka on saavutettavissa luotamattomasta syötteestä, pitäisi konfiguroida tällä tavalla; ero tässä on, ettei kieltäytyminen ole konfiguroitavissa, joten sitä ei voi kytkeä pois hyväntahtoisella asetusmuutoksella
Kvalifioitu tila tallennetaan ketjuluottamuksen viereen, ei sulauteta siihen
Arviointipuoli on tarkoituksella erillinen. TPadesTrustValidationOptions.QualifiedTrustEvaluator ottaa vastaan kohteen IPdfQualifiedTrustEvaluator, jonka luottamusluettelon snapshot toteuttaa. Validoinnin aikana arvioija vastaanottaa lehtisertifikaatin, ketjun ja validointiajan, täsmäyttää palvelusertifikaatit tarkalla DER-vertailulla allekirjoittajaan ja ketjuun, yhdistää palvelun tilan, palvelutyyppitunnisteen ja määrittelijä-URI:t sillä hetkellä ja palauttaa arviointitietueen
Tulos laskeutuu kahteen paikkaan jokaisella allekirjoituksella: QualifiedTrustStatus karkeana tilana ja QualifiedTrust täytenä arviointina alueella, palveluntarjoajan nimellä, palvelun nimellä, tyyppitunnisteella, tilalla ja tilan alkamisajalla. Se, mitä se ei tee, on muuttaa CertificateTrustStatusia. Järjestelmän ketjuluottamus ja kvalifioitu tila vastaavat eri kysymyksiin, ja raportti, joka yhdistää ne, ei voi erottaa toisistaan ”luotettu mutta ei kvalifioitu” ja ”kvalifioitu mutta ketju ei validoidu”, joista kumpikin on todellinen ja joista kummankin käsittely on erilainen
var
Options: TPadesTrustValidationOptions;
Report: TPadesValidationResult;
I: Integer;
begin
Options := TPadesTrustValidationOptions.Default;
Options.CheckRevocation := True;
Options.QualifiedTrustEvaluator := List; // autentikoitu snapshot
Options.QualifiedValidationTime := SigningTime; // ei 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
// Ei täsmäävää palvelua tai snapshot ei voi vastata tälle ajalle
Writeln(Format('signature %d: qualified status undetermined', [I]));
end;
Miksi validointiaika ei ole nyt
Koska kvalifiointi on hetken ominaisuus. Luottamuspalvelulle voidaan myöntää kvalifioitu tila, se voidaan myöhemmin peruuttaa ja vielä myöhemmin palauttaa, ja jokainen kyseisistä siirtymistä kantaa alkamisaikaa luettelossa. Allekirjoitus, joka tehtiin sillä aikaa, kun palvelu oli kvalifioitu, pysyy kvalifioituna jälkeenpäin; allekirjoitus, joka tehtiin ennen myöntämistä, ei tule kvalifioiduksi takautuvasti. Arviointi nykyhetkeen siksi antaa väärän vastauksen molempiin suuntiin
Luettelo kantaa sen, mitä tähän tarvitaan: jokaisella palvelutietueella on tilan alkamisaika ja lippu, joka erottaa historialliset merkinnät nykyisistä, ja arvioija yhdistää ne toimittamaasi aikaa vasten. Käytännössä tuo aika tulee luotetusta aikaleimasta allekirjoituksessa eikä CMS:ssä väitetystä allekirjoitusajasta, mistä syystä pitkän aikavälin validointimateriaali merkitsee jopa kysymykselle, joka näyttää politiikkahaulta; aikaleiman ja DSS:n puoli käsitellään artikkelissa pitkän aikavälin allekirjoitus
Mitä sinun pitää yhä rakentaa
Kolme asiaa, eikä mikään niistä kuulu PDF-kirjastoon. Autentikoija, tarkoittaen todellista XMLDSIG-varmennusta luettelon allekirjoitussertifikaattia vastaan, jonka hankit kanavan kautta, johon luotat. Hakupolitiikka, tarkoittaen sitä, miten ja kuinka usein päivität, ja mitä sovelluksesi tekee, kun päivitys epäonnistuu. Ja alueellinen laajuus, tarkoittaen sitä, mitkä luettelot kannat ylipäätään, mikä on liiketoimintapäätös siitä, missä jäsenvaltioissa vastapuolesi allekirjoittavat
Se, mitä saat komponentilta, on se osa, jonka voi saada hienovaraisesti väärin: autentikoi ennen jäsentämistä -järjestys, rajattu ja entiteettivapaa XML-jäsennys, monotoniset päivitysinvariantit, tarkka DER-palvelutäsmäytys, historiallinen tilan arviointi ja tulos, joka pysyy erillään tavallisesta ketjuluottamuksesta. Jos välitön ongelmasi on perustavampi, se, että validoija hylkää allekirjoituksen, jonka uskot olevan kunnossa, tavalliset syyt on lueteltu artikkelissa miksi validoijat hylkäävät PAdES-allekirjoitukset, ja allekirjoitusten tarkastuspinta on kuvattu artikkelissa allekirjoitusten ja PAdES-tasojen tarkastaminen. Komponentin kyvykkyydet on lueteltu PDFium Delphi -komponentin tuotesivulla