Tehnični članak

PDFium VCL: oddaljeno podpisovanje PAdES s HSM

PDFiumPas razdeli podpisovanje PAdES na dva klica, tako da zasebni ključ nikoli ne rabi biti v vašem procesu. PreparePadesRemoteSignature zapiše prirastno posodobitev s praznim rezerviranim mestom fiksne širine /Contents in vrne zapis zahteve, ki nosi povzetek dokumenta SHA-256, natančen ByteRange in prstni odtis pripravljene datoteke. CompletePadesRemoteSignature vzame ločen CMS, ki ga vrne vaša storitev za podpisovanje, in ga vstavi v to rezervirano mesto

Med tema dvema klicema lahko minejo minute ali ure, proces se lahko ponovno zažene, delo pa se lahko preseli na drugo napravo. Ta vrzel je celoten razlog, da je API oblikovan tako

Zakaj oddaljen ključ ne more uporabiti navadnega klica za podpisovanje?

Ker SignPadesBytes predvideva, da se operacija podpisovanja zgodi znotraj klica. Zgradi prirastno posodobitev, izračuna povzetek prek ByteRange, ga podpiše in zapiše rezultat, vse to pred vrnitvijo. To je natanko pravilno, kadar ključ živi v shrambi certifikatov Windows ali v datoteki PKCS#12, ki ste jo naložili

Nemogoče je, kadar ključ živi v omrežnem HSM, kvalificirani napravi za ustvarjanje podpisa, ki jo upravlja ponudnik storitev zaupanja, ali v storitvi za podpisovanje v oblaku, ki zahteva, da uporabnik potrdi na telefonu. V teh primerih zaporedje ni klic funkcije, temveč pogovor: pošljete povzetek, nekaj drugega avtenticira človeka, CMS pa pride nazaj kasneje. Sinhroni API ne more izraziti "kasneje", ne da bi blokiral nit na operaciji, ki morda potrebuje drugi dejavnik

Dvofazni protokol

Prva faza pripravi dokument. PDFiumPas doda polje in slovar vrednosti podpisa, rezervira ContentsSize bajtov šestnajstiško kodiranega prostora v /Contents, izračuna ByteRange okoli te rezervacije in ustvari TPadesRemoteSigningRequest, ki vsebuje FormatVersion, PreparedFingerprint, DocumentDigest, štirielementni ByteRange, ContentsHexOffset in ContentsSize

Edina vrednost, ki jo vaša storitev za podpisovanje potrebuje, je DocumentDigest: SHA-256, ki ga mora vrnjeni CAdES SignedData nositi kot svoj povzetek sporočila. Vse ostalo v zapisu obstaja, da lahko druga faza dokaže, da je datoteka, ki jo dokončuje, tista datoteka, iz katere je bil ta povzetek izračunan

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;   // šestnajstiških bajtov, rezerviranih za 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;

  // Shranite sejo, da jo lahko kasnejši zagon - ali druga naprava - dokonča
  Session := TFileStream.Create('contract.signreq', fmCreate);
  try
    SavePadesRemoteSigningRequest(Session, Request);
  finally
    Session.Free;
  end;

  SendDigestToSigningService(Request.DocumentDigest);
end;

Kaj Complete zavrne, in zakaj obstaja vsako preverjanje?

Dokončanje je mesto, kjer zasnova oddaljenega podpisovanja običajno zaide, zato je preverjanje namerno neizprosno. CompletePadesRemoteSignature zavrne pripravljen PDF, katerega prstni odtis se ne ujema več z zahtevo, ByteRange, ki se ne ujema z zabeleženimi koordinatami rezerviranega mesta, spremenjene ločila /Contents, rezervirano mesto, ki ni več prazno, CMS, večji od rezervacije, CMS, ki ni natanko ena vrednost DER, nepodprto obliko SignedData, manjkajoč atribut signing-certificate-v2 in CMS, katerega povzetek sporočila ni enak povzetku pripravljenega dokumenta

Vsako od tega ustreza resnični napaki. Preverjanji prstnega odtisa in ByteRange zajameta primer, ko je nekdo med fazama znova ustvaril pripravljeno datoteko, kar bi ustvarilo podpis, ki se preveri glede na bajte, ki jih nihče nima. Preverjanje praznega rezerviranega mesta zajame dvojno dokončanje, kjer je drugi CMS zapisan čez podpis, ki že obstaja. Preverjanje povzetka sporočila zajame najbolj nevaren primer od vseh: pravilno oblikovan CMS, podpisan nad drugim dokumentom, kar dobite, kadar čakalna vrsta pomeša dve sočasni seji podpisovanja. Brez njega bi ustvarili datoteko, ki izgleda podpisana in povsod odpove pri preverjanju, ali še slabše, ki nosi odobritev nekoga drugega

Zahteva po signing-certificate-v2 je vprašanje skladnosti s PAdES in ne vprašanje celovitosti. ETSI EN 319 142 zahteva, da je certifikat podpisnika vezan v podpisane atribute, CMS brez tega atributa pa ni podpis PAdES, tudi če se kriptografsko preveri. Zavrnitev ob dokončanju pomeni, da to odkrijete tukaj in ne v poročilu validatorja od stranke, kar je tema, nadalje raziskana v zakaj validatorji zavrnejo podpise PAdES

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;   // vrne ga HSM ali 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
        // Vsaka zavrnitev nosi natančen razlog; zabeležite ga dobesedno
        FailSession(E.Message);
    end;
  finally
    Dest.Free;
    Prepared.Free;
  end;
end;

Prehod čez meje procesov in naprav

SavePadesRemoteSigningRequest in LoadPadesRemoteSigningRequest serializirata sejo prek stabilne, različico nosečega binarnega formata, kar zasnovo naredi praktično in ne le pravilno. Spletna aplikacija lahko pripravi dokument v eni zahtevi, shrani pripravljen PDF in blob seje, vrne povzetek brskalniku za podpis s pametno kartico in dokonča datoteko v povsem drugem obravnavalcu zahtev

Polje FormatVersion je tisto, kar to ohranja varno čez nadgradnje. Seja, ki jo je zapisala starejša gradnja in jo naloži novejša, je izrecno prepoznana ali zavrnjena, namesto da bi bila napačno prebrana kot drugače oblikovan zapis. Če vaša čakalna vrsta lahko hrani seje dneve, obravnavajte različico formata kot operativno dejstvo, ki ga velja beležiti

Določanje velikosti rezerviranega mesta

ContentsSize je edini parameter, o katerem morate razmišljati, ker je določen, preden CMS sploh obstaja. Šteje šestnajstiško kodirano rezervacijo, tako da 6 KB CMS v DER potrebuje vsaj 12 KB prostora, izvedba pa omeji rezervacijo na 64 MiB

Rezervirajte premalo in dokončanje odpove z napako prevelikega CMS, potem ko je vaša storitev za podpisovanje že opravila svoje delo, kar pri merjeni kvalificirani storitvi podpisovanja pomeni zapravljeno operacijo. Rezervirajte preveč in vsak podpisan dokument za vedno nosi to polnilo. Smiseln pristop je meriti: podpišite en dokument s svojo pravo verigo certifikatov, poglejte dolžino DER, jo podvojite za šestnajstiški zapis, nato dodajte velikodušno rezervo za žeton časovnega žiga, če nameravate nadgraditi na podpis ravni T. Verige z več vmesnimi certifikati in dolgim odzivom OCSP rastejo hitreje, kot ljudje pričakujejo

Kaj sledi po podpisu

Dokončan oddaljen podpis je PAdES B-B. Dolgoročna veljavnost potrebuje časovni žig in gradivo za preverjanje, kar je ločena prirastna posodobitev, ki doda DSS in njegove slovarje VRI za posamezen podpis, opisano v dolgoročnih podpisih s časovnimi žigi RFC 3161 in DSS. Ta korak je lokalen: doda certifikate, odzive OCSP in sezname CRL, pri čemer noben ne potrebuje zasebnega ključa

Pred pošiljanjem preverite, kar ste ustvarili, z isto potjo kode, ki bi jo uporabila stranka, ki se zanaša na podpis, obravnavano v pregledovanju digitalnih podpisov PDF in ravni PAdES. Podpisovanje in preverjanje sta različna koda, cevovod za oddaljeno podpisovanje pa je natanko mesto, kjer lahko oba zaideta narazen, ne da bi kdo opazil, dokler tega ne pove zunanji validator

PDFiumPas je komponenta za Delphi in Lazarus okoli pogona PDFium z izvornim skladom PAdES v Pascalu, tako da podpisovanje, žigosanje s časom in preverjanje delujejo brez zunanjih orodij ukazne vrstice. Celotna dokumentacija API in preizkusna gradnja sta na strani izdelka PDFium