PDFiumPas jakaa PAdES-allekirjoituksen kahteen kutsuun, jotta yksityisen avaimen ei koskaan tarvitse olla prosessissasi. PreparePadesRemoteSignature kirjoittaa inkrementaalisen päivityksen, jossa on tyhjä kiinteäleveyksinen /Contents-paikkamerkki, ja palauttaa pyyntötietueen, joka kantaa SHA-256-asiakirjatiivisteen, täsmällisen ByteRange-arvon ja valmistellun tiedoston sormenjäljen. CompletePadesRemoteSignature ottaa allekirjoituspalvelusi palauttaman irrotetun CMS:n ja pudottaa sen tuohon varattuun paikkaan
Näiden kahden kutsun välillä voi kulua minuutteja tai tunteja, prosessi voi käynnistyä uudelleen, ja työ voi siirtyä toiselle koneelle. Tuo aukko on koko syy siihen, miksi API on muotoiltu tällä tavalla
Miksi etäavain ei voi käyttää tavallista allekirjoituskutsua?
Koska SignPadesBytes olettaa, että allekirjoitusoperaatio tapahtuu kutsun sisällä. Se rakentaa inkrementaalisen päivityksen, laskee tiivisteen ByteRange-alueen yli, allekirjoittaa sen ja kirjoittaa tuloksen, kaiken tämän ennen paluuta. Tämä on täsmälleen oikein, kun avain asuu Windowsin varmennevarastossa tai lataamassasi PKCS#12-tiedostossa
Se on mahdotonta, kun avain asuu verkko-HSM:ssä, luottamuspalvelun tarjoajan käyttämässä pätevässä allekirjoituksenluontilaitteessa tai pilviallekirjoitus-API:ssa, joka vaatii käyttäjää vahvistamaan puhelimella. Näissä tapauksissa sekvenssi ei ole funktiokutsu, se on keskustelu: lähetät tiivisteen, jokin muu todentaa ihmisen, ja CMS palaa myöhemmin. Synkroninen API ei voi ilmaista "myöhemmin" ilman, että se lukitsee säikeen operaatioon, joka saattaa tarvita toisen tekijän
Kaksivaiheinen protokolla
Vaihe yksi valmistelee asiakirjan. PDFiumPas liittää allekirjoituskentän ja arvosanakirjan, varaa ContentsSize tavua heksakoodattua tilaa kentässä /Contents, laskee ByteRange-arvon tuon varauksen ympärille ja tuottaa TPadesRemoteSigningRequest-tietueen, joka sisältää FormatVersion-, PreparedFingerprint-, DocumentDigest-arvot, nelosaisen ByteRange-arvon sekä ContentsHexOffset- ja ContentsSize-arvot
Ainoa arvo, jonka allekirjoituspalvelusi tarvitsee, on DocumentDigest: SHA-256, jonka palautetun CAdES SignedData -rakenteen täytyy kantaa viestitiivisteenään. Kaikki muu tietueessa on olemassa, jotta vaihe kaksi voi todistaa, että tiedosto, jota se viimeistelee, on se tiedosto, josta tuo tiiviste laskettiin
uses
FPdfPades;
var
Options: TPadesRemoteSignOptions;
Request: TPadesRemoteSigningRequest;
Source, Prepared, Session: TFileStream;
begin
Options := TPadesRemoteSignOptions.Default;
Options.Reason := 'Approved by finance';
Options.Location := 'Lisbon';
Options.Name := 'A. Moreira';
Options.SigningTimeUtc := NowUtc;
Options.ContentsSize := 16384; // CMS:lle varatut heksatavut
Source := TFileStream.Create('contract.pdf', fmOpenRead or fmShareDenyWrite);
Prepared := TFileStream.Create('contract.prepared.pdf', fmCreate);
try
PreparePadesRemoteSignature(Source, Prepared, Options, Request);
finally
Prepared.Free;
Source.Free;
end;
// Tallenna istunto, jotta myöhempi ajo - tai toinen kone - voi viimeistellä sen
Session := TFileStream.Create('contract.signreq', fmCreate);
try
SavePadesRemoteSigningRequest(Session, Request);
finally
Session.Free;
end;
SendDigestToSigningService(Request.DocumentDigest);
end;
Minkä Complete hylkää, ja miksi jokainen tarkistus on olemassa?
Viimeistely on kohta, jossa etäallekirjoitussuunnittelu yleensä menee pieleen, joten validointi on tarkoituksella anteeksiantamaton. CompletePadesRemoteSignature hylkää valmistellun PDF:n, jonka sormenjälki ei enää täsmää pyynnön kanssa, ByteRange-arvon, joka ei täsmää tallennettujen paikkamerkin koordinaattien kanssa, muokatut /Contents-rajaimet, paikkamerkin, joka ei ole enää tyhjä, varausta suuremman CMS:n, CMS:n, joka ei ole täsmälleen yksi DER-arvo, tuetun ulkopuolisen SignedData-muodon, puuttuvan signing-certificate-v2-attribuutin, sekä CMS:n, jonka viestitiiviste ei vastaa valmistellun asiakirjan tiivistettä
Jokainen niistä vastaa todellista virhetilaa. Sormenjälki- ja ByteRange-tarkistukset havaitsevat tapauksen, jossa joku on generoinut valmistellun tiedoston uudelleen vaiheiden välissä, mikä tuottaisi allekirjoituksen, joka varmentuu tavuja vasten, joita kellään ei ole. Tyhjän paikkamerkin tarkistus havaitsee kaksinkertaisen viimeistelyn, jossa toinen CMS kirjoitetaan jo olemassa olevan allekirjoituksen päälle. Viestitiivisteen tarkistus havaitsee kaikkein vaarallisimman tapauksen: oikein muodostetun CMS:n, joka on allekirjoitettu eri asiakirjan yli, mikä on se, mitä saat, kun jono sekoittaa kaksi samanaikaista allekirjoitusistuntoa. Ilman sitä tuottaisit tiedoston, joka näyttää allekirjoitetulta ja epäonnistuu validoinnissa kaikkialla, tai pahempaa, joka kantaa jonkun muun hyväksyntää
Signing-certificate-v2-vaatimus on PAdES-yhteensopivuusasia eikä eheysasia. ETSI EN 319 142 vaatii, että allekirjoitusvarmenne sidotaan allekirjoitettuihin attribuutteihin, ja CMS, josta tuo attribuutti puuttuu, ei ole PAdES-allekirjoitus, vaikka se varmentuisikin kryptografisesti. Sen hylkääminen viimeistelyssä tarkoittaa, että saat tietää tämän täällä, et validaattoriraportista asiakkaalta, aihetta käsitellään laajemmin artikkelissa miksi validaattorit hylkäävät PAdES-allekirjoituksia
var
Request: TPadesRemoteSigningRequest;
Session, Prepared, Dest: TFileStream;
CmsDer: TBytes;
begin
Session := TFileStream.Create('contract.signreq', fmOpenRead);
try
Request := LoadPadesRemoteSigningRequest(Session);
finally
Session.Free;
end;
CmsDer := FetchDetachedCmsFromService; // HSM:n tai TSP:n palauttama
Prepared := TFileStream.Create('contract.prepared.pdf', fmOpenRead);
Dest := TFileStream.Create('contract.signed.pdf', fmCreate);
try
try
CompletePadesRemoteSignature(Prepared, Dest, Request, CmsDer);
except
on E: EPadesCrypto do
// Jokainen hylkäys kantaa täsmällisen syyn; kirjaa se sellaisenaan
FailSession(E.Message);
end;
finally
Dest.Free;
Prepared.Free;
end;
end;
Prosessi- ja konerajojen ylitys
SavePadesRemoteSigningRequest ja LoadPadesRemoteSigningRequest serialisoivat istunnon vakaan versioidun binäärimuodon kautta, mikä on se, mikä tekee suunnittelusta käytännöllisen eikä vain oikean. Web-sovellus voi valmistella asiakirjan yhdessä pyynnössä, tallentaa valmistellun PDF:n ja istuntoblobin, palauttaa tiivisteen selaimelle älykorttiallekirjoitusta varten ja viimeistellä tiedoston täysin eri pyyntökäsittelijässä
FormatVersion-kenttä on se, mikä pitää tämän turvallisena päivitysten yli. Vanhemman buildin kirjoittama ja uudemman lataama istunto tunnistetaan tai hylätään eksplisiittisesti sen sijaan, että se luettaisiin väärin toisenmuotoisena tietueena. Jos jonosi voi pitää istuntoja päiviä, käsittele muotoversiota operatiivisena faktana, joka kannattaa kirjata lokiin, ei toteutusyksityiskohtana
Paikkamerkin mitoitus
ContentsSize on se yksi parametri, jota täytyy miettiä, koska se on kiinnitetty ennen kuin CMS on olemassa. Se laskee heksakoodatun varauksen, joten 6 kt:n DER-CMS tarvitsee vähintään 12 kt tilaa, ja toteutus rajaa varauksen 64 MiB:iin
Varaa liian vähän, ja viimeistely epäonnistuu liian-suuri-CMS-virheeseen sen jälkeen, kun allekirjoituspalvelusi on jo tehnyt työnsä, mikä mitatulla pätevän allekirjoituksen palvelulla tarkoittaa hukattua operaatiota. Varaa liikaa, ja jokainen allekirjoitettu asiakirja kantaa täytettä ikuisesti. Järkevä lähestymistapa on mitata: allekirjoita yksi asiakirja todellisella varmenneketjullasi, katso DER-pituus, kaksinkertaista se heksaa varten, ja lisää sitten runsaasti tilaa aikaleimatunnukselle, jos aiot päivittää T-tason allekirjoitukseen. Ketjut, joissa on useita välivarmenteita ja pitkä OCSP-vastaus, kasvavat nopeammin kuin odotetaan
Mitä allekirjoituksen jälkeen tapahtuu
Valmis etäallekirjoitus on PAdES B-B. Pitkäaikainen validointi tarvitsee aikaleiman ja validointimateriaalin, mikä on erillinen inkrementaalinen päivitys, joka lisää DSS:n ja sen allekirjoituskohtaiset VRI-sanakirjat, kuvattu artikkelissa pitkäaikaiset allekirjoitukset RFC 3161 -aikaleimoilla ja DSS:llä. Tuo vaihe on paikallinen: se lisää varmenteita, OCSP-vastauksia ja CRL-listoja, joista mikään ei tarvitse yksityistä avainta
Ennen toimitusta varmenna se, mitä tuotit, samalla koodipolulla, jota luottava osapuoli käyttäisi, käsitelty artikkelissa digitaalisten allekirjoitusten ja PAdES-tasojen tarkastelu. Allekirjoitus ja varmennus ovat eri koodia, ja etäallekirjoitusputki on juuri se paikka, jossa nämä kaksi voivat ajautua erilleen kenenkään huomaamatta, ennen kuin ulkoinen validaattori kertoo siitä
PDFiumPas on Delphi- ja Lazarus-komponentti PDFium-moottorin ympärillä natiivilla Pascal-PAdES-pinolla, joten allekirjoitus, aikaleimaus ja validointi toimivat ilman ulkoisia komentorivityökaluja. Täydellinen API-dokumentaatio ja kokeiluversio löytyvät sivulta PDFium Delphi component page