PDFiumPas opdeler PAdES-signering i to kald, så den private nøgle aldrig behøver at være i din proces. PreparePadesRemoteSignature skriver en inkrementel opdatering med en tom, fast bredde /Contents-pladsholder og returnerer en anmodningsrecord, der bærer SHA-256-dokumentdigestet, det præcise ByteRange og et fingeraftryk af den forberedte fil. CompletePadesRemoteSignature tager den frakoblede CMS, din signeringstjeneste returnerer, og lægger den ind i det reserverede felt
Mellem de to kald kan der gå minutter eller timer, processen kan genstarte, og arbejdet kan flytte til en anden maskine. Det gab er hele grunden til, at API'en er formet på denne måde
Hvorfor kan en fjernnøgle ikke bruge det almindelige signeringskald?
Fordi SignPadesBytes antager, at signeringsoperationen sker inde i kaldet. Den bygger den inkrementelle opdatering, beregner digestet over ByteRange, signerer det og skriver resultatet, alt sammen før den returnerer. Det er præcis rigtigt, når nøglen bor i Windows-certifikatlageret eller i en PKCS#12-fil, du har indlæst
Det er umuligt, når nøglen bor i en netværks-HSM, en kvalificeret signaturoprettelsesenhed, drevet af en trust service provider, eller en cloud-signeringsAPI, der kræver, at brugeren bekræfter på en telefon. I de tilfælde er sekvensen ikke et funktionskald, det er en samtale: du sender et digest, noget andet autentificerer et menneske, og en CMS kommer tilbage senere. En synkron API kan ikke udtrykke "senere" uden at blokere en tråd på en operation, der måske kræver en anden faktor
Den to-fasede protokol
Fase et forbereder dokumentet. PDFiumPas tilføjer signaturfeltet og værdi-ordbogen, reserverer ContentsSize byte af hex-kodet plads i /Contents, beregner ByteRange omkring den reservation og producerer en TPadesRemoteSigningRequest, der indeholder FormatVersion, PreparedFingerprint, DocumentDigest, det fire-elements ByteRange, ContentsHexOffset og ContentsSize
Den eneste værdi, din signeringstjeneste har brug for, er DocumentDigest: SHA-256'en, den returnerede CAdES SignedData skal bære som sit besked-digest. Alt andet i recorden findes, så fase to kan bevise, at den fil, den fuldfører, er den fil, det digest blev beregnet ud 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; // hex-byte reserveret til 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;
// Gem sessionen, så en senere kørsel - eller en anden maskine - kan fuldføre den
Session := TFileStream.Create('contract.signreq', fmCreate);
try
SavePadesRemoteSigningRequest(Session, Request);
finally
Session.Free;
end;
SendDigestToSigningService(Request.DocumentDigest);
end;
Hvad afviser Complete, og hvorfor findes hvert tjek?
Fuldførelse er der, hvor et fjernsigneringsdesign normalt går galt, så valideringen er bevidst ubarmhjertig. CompletePadesRemoteSignature afviser en forberedt PDF, hvis fingeraftryk ikke længere matcher anmodningen, et ByteRange, der ikke matcher de registrerede pladsholderkoordinater, ændrede /Contents-afgrænsere, en pladsholder, der ikke længere er tom, en CMS, der er større end reservationen, en CMS, der ikke er præcis én DER-værdi, en ikke-understøttet SignedData-form, et manglende signing-certificate-v2-attribut og en CMS, hvis besked-digest ikke er lig med det forberedte dokumentdigest
Hver af dem afspejler en reel fejl. Fingeraftryks- og ByteRange-tjekkene fanger tilfældet, hvor nogen har genereret den forberedte fil igen mellem faserne, hvilket ville producere en signatur, der validerer mod bytes, ingen har. Det tomme-pladsholder-tjek fanger dobbelt fuldførelse, hvor en anden CMS skrives oven på en signatur, der allerede findes. Besked-digest-tjekket fanger det farligste tilfælde af alle: en korrekt formet CMS, signeret over et andet dokument, hvilket er, hvad du får, når en kø blander to samtidige signeringssessioner sammen. Uden det ville du producere en fil, der ser signeret ud og fejler validering overalt, eller værre, som bærer en andens godkendelse
Kravet om signing-certificate-v2 er et PAdES-konformitetsanliggende snarere end et integritetsanliggende. ETSI EN 319 142 kræver, at signeringscertifikatet er bundet ind i de signerede attributter, og en CMS uden det attribut er ikke en PAdES-signatur, selv om den verificerer kryptografisk. At afvise det ved fuldførelse betyder, at du finder ud af det her, ikke i en validatorrapport fra en kunde, et emne udforsket yderligere i hvorfor validatorer afviser 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; // returneret af 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 afvisning bærer en specifik årsag; log den verbatim
FailSession(E.Message);
end;
finally
Dest.Free;
Prepared.Free;
end;
end;
At krydse proces- og maskingrænser
SavePadesRemoteSigningRequest og LoadPadesRemoteSigningRequest serialiserer sessionen gennem et stabilt versioneret binært format, hvilket er det, der gør designet praktisk frem for blot korrekt. En webapplikation kan forberede et dokument i én anmodning, gemme den forberedte PDF og session-blobben, returnere et digest til browseren til en smartkort-signatur og fuldføre filen i en helt anden anmodningshandler
FormatVersion-feltet er det, der holder det sikkert på tværs af opgraderinger. En session, skrevet af en ældre build og indlæst af en nyere, genkendes eller afvises eksplicit, frem for at blive fejlfortolket som en anderledes formet record. Hvis din kø kan holde sessioner i dage, bør du behandle formatversionen som en driftsmæssig kendsgerning, det er værd at logge, ikke en implementeringsdetalje
Dimensionering af pladsholderen
ContentsSize er den ene parameter, du skal tænke over, fordi den er fastsat, før CMS'en eksisterer. Den tæller den hex-kodede reservation, så en 6 KB DER CMS kræver mindst 12 KB plads, og implementeringen loftfæster reservationen ved 64 MiB
Reservér for lidt, og fuldførelse fejler med en for-stor-CMS-fejl, efter din signeringstjeneste allerede har udført sit arbejde, hvilket på en målt kvalificeret signaturtjeneste betyder en spildt operation. Reservér for meget, og hvert signeret dokument bærer polstringen for evigt. Den fornuftige tilgang er at måle: signér ét dokument med din rigtige certifikatkæde, se på DER-længden, dobbelt den for hex, og læg derefter rigelig margin til for tidsstemplingstokenet, hvis du agter at opgradere til en T-niveau-signatur. Kæder med flere mellemled og et langt OCSP-svar vokser hurtigere, end folk forventer
Hvad kommer efter signaturen
En fuldført fjernsignatur er PAdES B-B. Langtidsvalidering kræver et tidsstempel og valideringsmaterialet, hvilket er en separat inkrementel opdatering, der tilføjer en DSS og dens per-signatur VRI-ordbøger, beskrevet i langtidssignaturer med RFC 3161-tidsstempler og DSS. Det trin er lokalt: det tilføjer certifikater, OCSP-svar og CRL'er, hvoraf ingen kræver den private nøgle
Før udsendelse, verificér det, du producerede, med den samme kodesti, en relying party ville bruge, dækket i inspektion af digitale signaturer og PAdES-niveauer. Signering og verifikation er forskellig kode, og en fjernsigneringspipeline er præcis det sted, hvor de to kan drive fra hinanden, uden at nogen bemærker det, før en ekstern validator siger det
PDFiumPas er en Delphi- og Lazarus-komponent omkring PDFium-motoren med en native Pascal PAdES-stak, så signering, tidsstempling og validering fungerer uden eksterne kommandolinjeværktøjer. Fuld API-dokumentation og en trial-build findes på PDFium's produktside for Delphi-komponenten