Techninis straipsnis

PDFium VCL nuotolinis PAdES pasirašymas su HSM raktais

PDFiumPas padalina PAdES pasirašymą į du iškvietimus, kad privatus raktas niekada neturėtų būti jūsų procese. PreparePadesRemoteSignature parašo prieauginį atnaujinimą su tuščia fiksuoto pločio /Contents vieta ir grąžina užklausos įrašą, nešantį SHA-256 dokumento santrauką, tikslų ByteRange ir paruošto failo kontrolinį atspaudą. CompletePadesRemoteSignature paima atskirtą CMS, kurį grąžina jūsų pasirašymo tarnyba, ir įdeda jį į tą rezervuotą vietą

Tarp šių dviejų iškvietimų gali praeiti minutės ar valandos, procesas gali persileisti iš naujo, o darbas gali persikelti į kitą mašiną. Būtent dėl šios spragos API taip ir suformuotas

Kodėl nuotolinis raktas negali naudoti įprasto pasirašymo iškvietimo?

Todėl, kad SignPadesBytes daro prielaidą, jog pasirašymo operacija vyksta iškvietimo viduje. Ji sukuria prieauginį atnaujinimą, apskaičiuoja santrauką per ByteRange, pasirašo ją ir įrašo rezultatą – visa tai prieš grįžtant. Tai lygiai teisinga, kai raktas gyvena Windows sertifikatų saugykloje arba PKCS#12 faile, kurį įkėlėte

Tai neįmanoma, kai raktas gyvena tinklo HSM, kvalifikuotame parašo kūrimo įrenginyje, kurį valdo patikimų paslaugų teikėjas, arba debesies pasirašymo API, kuriai reikia, kad naudotojas patvirtintų telefone. Tokiais atvejais seka nėra funkcijos iškvietimas, tai pokalbis: siunčiate santrauką, kažkas kitas autentifikuoja žmogų, ir CMS grįžta vėliau. Sinchroninis API negali išreikšti „vėliau" neužblokuodamas gijos operacijai, kuriai gali prireikti antro faktoriaus

Dviejų fazių protokolas

Pirma fazė paruošia dokumentą. PDFiumPas prideda parašo lauką ir reikšmės žodyną, rezervuoja ContentsSize baitų šešioliktainiu koduotos erdvės /Contents, apskaičiuoja ByteRange aplink šią rezervaciją ir sukuria TPadesRemoteSigningRequest, turintį FormatVersion, PreparedFingerprint, DocumentDigest, keturių elementų ByteRange, ContentsHexOffset ir ContentsSize

Vienintelė reikšmė, kurios reikia jūsų pasirašymo tarnybai, yra DocumentDigest: SHA-256, kurią grąžinta CAdES SignedData turi nešti kaip savo pranešimo santrauką. Visa kita įraše egzistuoja tam, kad antra fazė galėtų įrodyti, jog užbaigiamas failas yra tas failas, iš kurio ta santrauka buvo apskaičiuota

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;   // šešioliktainiai baitai, rezervuoti CMS

  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;

  // Išsaugokite sesiją, kad vėlesnis paleidimas - ar kita mašina - galėtų ją užbaigti
  Session := TFileStream.Create('contract.signreq', fmCreate);
  try
    SavePadesRemoteSigningRequest(Session, Request);
  finally
    Session.Free;
  end;

  SendDigestToSigningService(Request.DocumentDigest);
end;

Ką atmeta Complete, ir kodėl kiekviena patikra egzistuoja?

Užbaigimas yra vieta, kur nuotolinio pasirašymo dizainas paprastai suklysta, todėl validacija sąmoningai negailestinga. CompletePadesRemoteSignature atmeta paruoštą PDF, kurio kontrolinis atspaudas nebesutampa su užklausa, ByteRange, nesutampantį su užrašytomis vietos rezervacijos koordinatėmis, pakeistus /Contents skirtukus, vietą, kuri jau nebe tuščia, CMS, didesnį nei rezervacija, CMS, kuris nėra lygiai viena DER reikšmė, nepalaikomą SignedData formą, trūkstamą signing-certificate-v2 atributą, ir CMS, kurio pranešimo santrauka nelygi paruošto dokumento santraukai

Kiekvienas iš jų atitinka realų gedimą. Kontrolinio atspaudo ir ByteRange patikros sugauna atvejį, kai kažkas iš naujo sugeneravo paruoštą failą tarp fazių, o tai sukurtų parašą, kuris patvirtintų baitus, kurių niekas neturi. Tuščios vietos patikra sugauna dvigubą užbaigimą, kai antras CMS įrašomas ant parašo, kuris jau egzistuoja. Pranešimo santraukos patikra sugauna pačią pavojingiausią situaciją: teisingai suformuotą CMS, pasirašytą per kitą dokumentą, o tai gaunama, kai eilė sumaišo dvi vienalaikes pasirašymo sesijas. Be jos gautumėte failą, kuris atrodo pasirašytas ir nepavyksta visur validuojant, arba dar blogiau, kuris neša kažkieno kito patvirtinimą

Signing-certificate-v2 reikalavimas yra PAdES atitikties, ne vientisumo, klausimas. ETSI EN 319 142 reikalauja, kad pasirašymo sertifikatas būtų susietas su pasirašytais atributais, o CMS be šio atributo nėra PAdES parašas, net jei jis kriptografiškai patvirtinamas. Atmesdami jį užbaigimo metu, jūs tai sužinote čia, ne validatoriaus ataskaitoje iš kliento – tema, toliau nagrinėjama straipsnyje apie kodėl validatoriai atmeta PAdES parašus

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;   // grąžina HSM arba TSP

  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
        // Kiekvienas atmetimas turi konkrečią priežastį; registruokite ją pažodžiui
        FailSession(E.Message);
    end;
  finally
    Dest.Free;
    Prepared.Free;
  end;
end;

Peržengiant proceso ir mašinos ribas

SavePadesRemoteSigningRequest ir LoadPadesRemoteSigningRequest serializuoja sesiją per stabilų versijuotą dvejetainį formatą, o būtent tai daro šį dizainą praktišką, ne tik teisingą. Žiniatinklio aplikacija gali paruošti dokumentą vienoje užklausoje, saugoti paruoštą PDF ir sesijos duomenų bloką, grąžinti santrauką naršyklei pasirašymui su lustine kortele ir užbaigti failą visiškai kitame užklausos apdorojiklyje

FormatVersion laukas yra tai, kas tai išlaiko saugu per atnaujinimus. Sesija, parašyta senesnės versijos ir įkelta naujesnės, atpažįstama arba aiškiai atmetama, o ne neteisingai perskaitoma kaip kitaip suformuotas įrašas. Jei jūsų eilė gali laikyti sesijas dienų dienas, traktuokite formato versiją kaip eksploatacinį faktą, vertą registruoti, ne kaip įgyvendinimo detalę

Vietos dydžio nustatymas

ContentsSize yra vienintelis parametras, apie kurį turite pagalvoti, nes jis fiksuojamas prieš CMS atsirandant. Jis skaičiuoja šešioliktainiu koduotą rezervaciją, todėl 6 KB DER CMS reikalauja bent 12 KB erdvės, o realizacija riboja rezervaciją iki 64 MiB

Rezervavus per mažai, užbaigimas nepavyksta su per didelio CMS klaida jau po to, kai jūsų pasirašymo tarnyba atliko savo darbą, o tai matuojamoje kvalifikuoto parašo paslaugoje reiškia švaistytą operaciją. Rezervavus per daug, kiekvienas pasirašytas dokumentas amžinai nešios užpildą. Protingas požiūris yra išmatuoti: pasirašykite vieną dokumentą su tikru sertifikatų grandine, pažiūrėkite DER ilgį, padvigubinkite jį šešioliktainiam, tada pridėkite dosnią atsargą laiko žymos žetonui, jei ketinate atnaujinti iki T lygio parašo. Grandinės su keliais tarpiniais sertifikatais ir ilgu OCSP atsakymu auga greičiau, nei žmonės tikisi

Kas nutinka po parašo

Užbaigtas nuotolinis parašas yra PAdES B-B. Ilgalaikiam patvirtinimui reikia laiko žymos ir patvirtinimo medžiagos, o tai yra atskiras prieauginis atnaujinimas, pridedantis DSS ir jo per parašą VRI žodynus, aprašytas straipsnyje apie ilgalaikius parašus su RFC 3161 laiko žymomis ir DSS. Šis žingsnis vietinis: jis prideda sertifikatus, OCSP atsakymus ir CRL sąrašus, kuriems nė vienam nereikia privataus rakto

Prieš pristatydami, patikrinkite, ką sukūrėte, tuo pačiu kodo keliu, kurį naudotų pasitikinti šalis, aprašytu straipsnyje apie skaitmeninių parašų ir PAdES lygių tikrinimą. Pasirašymas ir patvirtinimas yra skirtingas kodas, ir nuotolinio pasirašymo konvejeris yra tiksliai ta vieta, kur šie du gali išsiskirti, kol išorinis validatorius apie tai nepraneša

PDFiumPas yra Delphi ir Lazarus komponentas aplink PDFium variklį su natyviu Pascal PAdES steku, todėl pasirašymas, laiko žymėjimas ir validacija veikia be išorinių komandinės eilutės įrankių. Pilna API dokumentacija ir bandomoji versija pateikta PDFium Delphi komponento puslapyje