PDFiumPas deler PAdES-signering i to kall, slik at den private nøkkelen aldri trenger å være i prosessen din. PreparePadesRemoteSignature skriver en inkrementell oppdatering med en tom, fastbredde /Contents-plassholder og gir tilbake en forespørselsrecord som bærer SHA-256-dokumentdigesten, den nøyaktige ByteRange og et fingeravtrykk av den forberedte filen. CompletePadesRemoteSignature tar den frakoblede CMS-en signeringstjenesten din returnerer, og legger den inn i den reserverte plassen
Mellom de to kallene kan det gå minutter eller timer, prosessen kan starte på nytt, og arbeidet kan flytte til en annen maskin. Det gapet er hele grunnen til at API-et er formet slik
Hvorfor kan ikke en fjernnøkkel bruke det vanlige signeringskallet?
Fordi SignPadesBytes forutsetter at signeringsoperasjonen skjer inne i kallet. Den bygger den inkrementelle oppdateringen, beregner digesten over ByteRange, signerer den, og skriver resultatet, alt før den returnerer. Det er nøyaktig riktig når nøkkelen bor i Windows-sertifikatlageret eller i en PKCS#12-fil du lastet inn
Det er umulig når nøkkelen bor i en nettverks-HSM, en kvalifisert signaturopprettelsesenhet drevet av en tillitstjenesteleverandør, eller en sky-signerings-API som krever at brukeren bekrefter på en telefon. I de tilfellene er sekvensen ikke et funksjonskall, det er en samtale: du sender en digest, noe annet autentiserer et menneske, og en CMS kommer tilbake senere. Et synkront API kan ikke uttrykke «senere» uten å blokkere en tråd på en operasjon som kan trenge en andre faktor
Toafase-protokollen
Fase én forbereder dokumentet. PDFiumPas legger til signaturfeltet og verdiordboken, reserverer ContentsSize byte med heks-kodet plass i /Contents, beregner ByteRange rundt den reservasjonen, og produserer en TPadesRemoteSigningRequest som inneholder FormatVersion, PreparedFingerprint, DocumentDigest, den fire-elements ByteRange, ContentsHexOffset og ContentsSize
Den eneste verdien signeringstjenesten din trenger, er DocumentDigest: SHA-256-en den returnerte CAdES SignedData må bære som sin meldingsdigest. Alt annet i recorden finnes slik at fase to kan bevise at filen den fullfører, er filen den digesten ble beregnet fra
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; // heks-byte reservert for CMS-en
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;
// Lagre økten slik at en senere kjøring - eller en annen maskin - kan fullføre den
Session := TFileStream.Create('contract.signreq', fmCreate);
try
SavePadesRemoteSigningRequest(Session, Request);
finally
Session.Free;
end;
SendDigestToSigningService(Request.DocumentDigest);
end;
Hva avviser Complete, og hvorfor finnes hver sjekk?
Fullføring er der et fjernsigneringsdesign vanligvis går galt, så valideringen er bevisst ubarmhjertig. CompletePadesRemoteSignature avviser en forberedt PDF hvis fingeravtrykk ikke lenger stemmer med forespørselen, en ByteRange som ikke stemmer med de registrerte plassholderkoordinatene, endrede /Contents-avgrensere, en plassholder som ikke lenger er tom, en CMS større enn reservasjonen, en CMS som ikke er nøyaktig én DER-verdi, en ustøttet SignedData-form, et manglende signing-certificate-v2-attributt, og en CMS hvis meldingsdigest ikke er lik den forberedte dokumentdigesten
Hver av disse svarer til en reell feil. Fingeravtrykk- og ByteRange-sjekkene fanger opp tilfellet der noen regenererte den forberedte filen mellom fasene, noe som ville produsert en signatur som validerer mot byte ingen har. Tom-plassholder-sjekken fanger opp dobbel fullføring, der en andre CMS skrives over en signatur som allerede finnes. Meldingsdigest-sjekken fanger opp det farligste tilfellet av alle: en korrekt formet CMS signert over et annet dokument, som er det du får når en kø blander sammen to samtidige signeringsøkter. Uten den ville du produsert en fil som ser signert ut og feiler validering overalt, eller enda verre, som bærer noen andres godkjenning
Kravet om signing-certificate-v2 er et PAdES-konformitetsspørsmål fremfor et integritetsspørsmål. ETSI EN 319 142 krever at signeringssertifikatet bindes inn i de signerte attributtene, og en CMS som mangler det attributtet, er ikke en PAdES-signatur selv om den verifiserer kryptografisk. Å avvise den ved fullføring betyr at du oppdager det her, ikke i en validatorrapport fra en kunde, et tema utforsket videre i hvorfor validatorer avviser PAdES-signaturer
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; // returnert av HSM-en eller TSP-en
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
// Hver avvisning bærer en spesifikk grunn; logg den ordrett
FailSession(E.Message);
end;
finally
Dest.Free;
Prepared.Free;
end;
end;
Å krysse prosess- og maskingrenser
SavePadesRemoteSigningRequest og LoadPadesRemoteSigningRequest serialiserer økten gjennom et stabilt, versjonert binærformat, som er det som gjør designet praktisk fremfor bare korrekt. En webapplikasjon kan forberede et dokument i én forespørsel, lagre den forberedte PDF-en og øktblobben, returnere en digest til nettleseren for en smartkortsignatur, og fullføre filen i en helt annen forespørselshåndterer
Feltet FormatVersion er det som holder dette trygt på tvers av oppgraderinger. En økt skrevet av et eldre bygg og lastet av et nyere ett, gjenkjennes eller avvises eksplisitt, fremfor å bli feillest som en annerledes formet record. Hvis køen din kan holde på økter i flere dager, bør du behandle formatversjonen som et driftsfaktum verdt å logge, ikke en implementasjonsdetalj
Å dimensjonere plassholderen
ContentsSize er den ene parameteren du må tenke på, fordi den fastsettes før CMS-en finnes. Den teller den heks-kodede reservasjonen, så en DER CMS på 6 KB trenger minst 12 KB med plass, og implementasjonen setter et tak på reservasjonen på 64 MiB
Reserver for lite, og fullføringen feiler med en for-stor-CMS-feil etter at signeringstjenesten din allerede har gjort jobben sin, noe som på en målt kvalifisert-signatur-tjeneste betyr en bortkastet operasjon. Reserver for mye, og hvert signerte dokument bærer utfyllingen for alltid. Den fornuftige tilnærmingen er å måle: signer ett dokument med den reelle sertifikatkjeden din, se på DER-lengden, doble den for heks, og legg deretter til en raus margin for tidsstempeltokenet hvis du har til hensikt å oppgradere til en T-nivå-signatur. Kjeder med flere mellomledd og et langt OCSP-svar vokser raskere enn folk forventer
Hva kommer etter signaturen
En fullført fjernsignatur er PAdES B-B. Langtidsvalidering trenger et tidsstempel og valideringsmaterialet, som er en separat inkrementell oppdatering som legger til en DSS og dens per-signatur VRI-ordbøker, beskrevet i langtidssignaturer med RFC 3161-tidsstempler og DSS. Det trinnet er lokalt: det legger til sertifikater, OCSP-svar og CRL-er, hvorav ingen trenger den private nøkkelen
Før du sender ut, verifiser det du produserte med den samme kodestien en tillitspart ville brukt, dekket i inspeksjon av digitale signaturer og PAdES-nivåer. Signering og verifisering er forskjellig kode, og en fjernsigneringspipeline er nøyaktig stedet der de to kan drive fra hverandre uten at noen legger merke til det før en ekstern validator sier ifra
PDFiumPas er en komponent for Delphi og Lazarus bygget rundt PDFium-motoren med en nativ Pascal PAdES-stakk, slik at signering, tidsstempling og validering fungerer uten eksterne kommandolinjeverktøy. Full API-dokumentasjon og en prøvebygg finnes på PDFium sin side for Delphi-komponent