Digitally Sign PDF Files - DigitalSignatures

Sample code to use Apryse SDK's high-level digital signature API for digitally signing and/or certifying PDF files; provided in Python, C++, C#, Java, Node.js (JavaScript), PHP, Ruby and VB.. Learn more about our Server SDK and PDF Digital Signature Library.

1//---------------------------------------------------------------------------------------
2// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
3// Consult legal.txt regarding legal and license information.
4//---------------------------------------------------------------------------------------
5
6
7const { PDFNet } = require('@pdftron/pdfnet-node');
8const PDFTronLicense = require('../LicenseKey/LicenseKey');
9
10((exports) => {
11 'use strict';
12
13 exports.runDigitalSignatureTest = () => {
14
15 const input_path = '../TestFiles/';
16 const output_path = '../TestFiles/Output/';
17
18 const VerifySimple = async (in_docpath, in_public_key_file_path) => {
19 const doc = await PDFNet.PDFDoc.createFromFilePath(in_docpath);
20 doc.initSecurityHandler();
21 console.log('==========');
22 const opts = await PDFNet.VerificationOptions.create(PDFNet.VerificationOptions.SecurityLevel.e_compatibility_and_archiving);
23
24 // Add trust root to store of trusted certificates contained in VerificationOptions.
25 await opts.addTrustedCertificateUString(in_public_key_file_path,
26 PDFNet.VerificationOptions.CertificateTrustFlag.e_default_trust + PDFNet.VerificationOptions.CertificateTrustFlag.e_certification_trust);
27
28 const result = await doc.verifySignedDigitalSignatures(opts);
29 switch (result) {
30 case PDFNet.PDFDoc.SignaturesVerificationStatus.e_unsigned:
31 console.log('Document has no signed signature fields.');
32 return false;
33 /* e_failure == bad doc status, digest status, or permissions status
34 (i.e. does not include trust issues, because those are flaky due to being network/config-related) */
35 case PDFNet.PDFDoc.SignaturesVerificationStatus.e_failure:
36 console.log('Hard failure in verification on at least one signature.');
37 return false;
38 case PDFNet.PDFDoc.SignaturesVerificationStatus.e_untrusted:
39 console.log('Could not verify trust for at least one signature.');
40 return false;
41 case PDFNet.PDFDoc.SignaturesVerificationStatus.e_unsupported:
42 /* If necessary, call GetUnsupportedFeatures on VerificationResult to check which
43 unsupported features were encountered (requires verification using 'detailed' APIs) */
44 console.log('At least one signature contains unsupported features.');
45 return false;
46 // unsigned sigs skipped; parts of document may be unsigned (check GetByteRanges on signed sigs to find out)
47 case PDFNet.PDFDoc.SignaturesVerificationStatus.e_verified:
48 console.log('All signed signatures in document verified.');
49 return true;
50 }
51
52 return false;
53 }
54
55 const VerifyAllAndPrint = async (in_docpath, in_public_key_file_path) => {
56 const doc = await PDFNet.PDFDoc.createFromFilePath(in_docpath);
57 doc.initSecurityHandler();
58 console.log('==========');
59 const opts = await PDFNet.VerificationOptions.create(PDFNet.VerificationOptions.SecurityLevel.e_compatibility_and_archiving);
60
61 // Add trust root to store of trusted certificates contained in VerificationOptions.
62 // Use trust level corresponding to an identity trusted even for certification signatures.
63 await opts.addTrustedCertificateUString(in_public_key_file_path,
64 PDFNet.VerificationOptions.CertificateTrustFlag.e_default_trust + PDFNet.VerificationOptions.CertificateTrustFlag.e_certification_trust);
65
66 // Iterate over the signatures and verify all of them.
67 const digsig_fitr = await doc.getDigitalSignatureFieldIteratorBegin();
68 var verification_status = true;
69 for (; await digsig_fitr.hasNext(); await digsig_fitr.next()) {
70 const curr = await digsig_fitr.current();
71 const result = await curr.verify(opts);
72 if (await result.getVerificationStatus()) {
73 console.log('Signature verified, objnum: ' + await (await curr.getSDFObj()).getObjNum());
74 } else {
75 console.log('Signature verification failed, objnum: ' + await (await curr.getSDFObj()).getObjNum());
76 verification_status = false;
77 }
78
79 switch (await result.getDigestAlgorithm()) {
80 case PDFNet.DigestAlgorithm.Type.e_SHA1:
81 console.log('Digest algorithm: SHA-1');
82 break;
83 case PDFNet.DigestAlgorithm.Type.e_SHA256:
84 console.log('Digest algorithm: SHA-256');
85 break;
86 case PDFNet.DigestAlgorithm.Type.e_SHA384:
87 console.log('Digest algorithm: SHA-384');
88 break;
89 case PDFNet.DigestAlgorithm.Type.e_SHA512:
90 console.log('Digest algorithm: SHA-512');
91 break;
92 case PDFNet.DigestAlgorithm.Type.e_RIPEMD160:
93 console.log('Digest algorithm: RIPEMD-160');
94 break;
95 case PDFNet.DigestAlgorithm.Type.e_unknown_digest_algorithm:
96 console.log('Digest algorithm: unknown');
97 break;
98 }
99
100 console.log('Detailed verification result: \n\t'
101 + await result.getDocumentStatusAsString() + '\n\t'
102 + await result.getDigestStatusAsString() + '\n\t'
103 + await result.getTrustStatusAsString() + '\n\t'
104 + await result.getPermissionsStatusAsString());
105
106 const changes = await result.getDisallowedChanges();
107 for (var i = 0; i < changes.length; ++i) {
108 const change = changes[i];
109 console.log('\tDisallowed change: ' + await change.getTypeAsString() + ', objnum: ' + await change.getObjNum());
110 }
111
112 // Get and print all the detailed trust-related results, if they are available.
113 if (await result.hasTrustVerificationResult()) {
114 const trust_verification_result = await result.getTrustVerificationResult();
115 console.log(await trust_verification_result.wasSuccessful() ? 'Trust verified.' : 'Trust not verifiable.');
116 console.log(await trust_verification_result.getResultString());
117
118 const tmp_time_t = await trust_verification_result.getTimeOfTrustVerification();
119 switch (await trust_verification_result.getTimeOfTrustVerificationEnum()) {
120 case PDFNet.VerificationOptions.TimeMode.e_current:
121 console.log('Trust verification attempted with respect to current time (as epoch time):' + tmp_time_t);
122 break;
123 case PDFNet.VerificationOptions.TimeMode.e_signing:
124 console.log('Trust verification attempted with respect to signing time (as epoch time): ' + tmp_time_t);
125 break;
126 case PDFNet.VerificationOptions.TimeMode.e_timestamp:
127 console.log('Trust verification attempted with respect to secure embedded timestamp (as epoch time): ' + tmp_time_t);
128 break;
129 }
130
131 const cert_path = await trust_verification_result.getCertPath();
132 if (cert_path.length == 0) {
133 console.log('Could not print certificate path.');
134 } else {
135 console.log('Certificate path:');
136 for (var i = 0; i < cert_path.length; i++) {
137 console.log('\tCertificate:');
138 const full_cert = cert_path[i];
139 console.log('\t\tIssuer names:');
140 const issuer_dn = await (await full_cert.getIssuerField()).getAllAttributesAndValues();
141 for (var j = 0; j < issuer_dn.length; j++) {
142 console.log('\t\t\t' + await issuer_dn[j].getStringValue());
143 }
144 console.log('\t\tSubject names:');
145 const subject_dn = await (await full_cert.getSubjectField()).getAllAttributesAndValues();
146 for (var j = 0; j < subject_dn.length; j++) {
147 console.log('\t\t\t' + await subject_dn[j].getStringValue());
148 }
149 console.log('\t\tExtensions:');
150 const extension_dn = await full_cert.getExtensions();
151 for (var j = 0; j < extension_dn.length; j++) {
152 console.log('\t\t\t' + await extension_dn[j].toString());
153 }
154 }
155 }
156 }
157 else {
158 console.log('No detailed trust verification result available.');
159 }
160
161 console.log('==========');
162 }
163
164 return verification_status;
165 }
166
167 const CertifyPDF = async (in_docpath, in_cert_field_name, in_private_key_file_path, in_keyfile_password, in_appearance_image_path, in_outpath) => {
168 console.log('================================================================================');
169 console.log('Certifying PDF document');
170
171 // Open existing PDF.
172 const doc = await PDFNet.PDFDoc.createFromFilePath(in_docpath);
173 doc.initSecurityHandler();
174
175 console.log('PDFDoc has ' + (await doc.hasSignatures() ? 'signatures' : 'no signatures'));
176
177 const page1 = await doc.getPage(1);
178
179 // Create a text field that we can lock using the field permissions feature.
180 const annot1 = await PDFNet.TextWidget.create(doc, new PDFNet.Rect(143, 440, 350, 460), 'asdf_test_field');
181 await page1.annotPushBack(annot1);
182
183 /* Create a new signature form field in the PDFDoc. The name argument is optional;
184 leaving it empty causes it to be auto-generated. However, you may need the name for later.
185 Acrobat doesn't show digsigfield in side panel if it's without a widget. Using a
186 Rect with 0 width and 0 height, or setting the NoPrint/Invisible flags makes it invisible. */
187 const certification_sig_field = await doc.createDigitalSignatureField(in_cert_field_name);
188 const widgetAnnot = await PDFNet.SignatureWidget.createWithDigitalSignatureField(doc, new PDFNet.Rect(143, 287, 219, 306), certification_sig_field);
189 await page1.annotPushBack(widgetAnnot);
190
191 // (OPTIONAL) Add an appearance to the signature field.
192 const img = await PDFNet.Image.createFromFile(doc, in_appearance_image_path);
193 await widgetAnnot.createSignatureAppearance(img);
194
195 // Prepare the document locking permission level. It will be applied upon document certification.
196 console.log('Adding document permissions.');
197 await certification_sig_field.setDocumentPermissions(PDFNet.DigitalSignatureField.DocumentPermissions.e_annotating_formfilling_signing_allowed);
198
199 // Prepare to lock the text field that we created earlier.
200 console.log('Adding field permissions.');
201 var fields_to_lock = ['asdf_test_field'];
202 await certification_sig_field.setFieldPermissions(PDFNet.DigitalSignatureField.FieldPermissions.e_include, fields_to_lock);
203
204 await certification_sig_field.certifyOnNextSave(in_private_key_file_path, in_keyfile_password);
205
206 // (OPTIONAL) Add more information to the signature dictionary.
207 await certification_sig_field.setLocation('Vancouver, BC');
208 await certification_sig_field.setReason('Document certification.');
209 await certification_sig_field.setContactInfo('www.pdftron.com');
210
211 // Save the PDFDoc. Once the method below is called, PDFNet will also sign the document using the information provided.
212 await doc.save(in_outpath, 0);
213
214 console.log('================================================================================');
215 }
216
217 const SignPDF = async (in_docpath, in_approval_field_name, in_private_key_file_path, in_keyfile_password, in_appearance_img_path, in_outpath) => {
218 console.log('================================================================================');
219 console.log('Signing PDF document');
220
221 // Open an existing PDF
222 const doc = await PDFNet.PDFDoc.createFromFilePath(in_docpath);
223 doc.initSecurityHandler();
224
225 // Retrieve the unsigned approval signature field.
226 const found_approval_field = await doc.getField(in_approval_field_name);
227 const found_approval_signature_digsig_field = await PDFNet.DigitalSignatureField.createFromField(found_approval_field);
228
229 // (OPTIONAL) Add an appearance to the signature field.
230 const img = await PDFNet.Image.createFromFile(doc, in_appearance_img_path);
231 const found_approval_signature_widget = await PDFNet.SignatureWidget.createFromObj(await found_approval_field.getSDFObj());
232 await found_approval_signature_widget.createSignatureAppearance(img);
233
234 // Prepare the signature and signature handler for signing.
235 await found_approval_signature_digsig_field.signOnNextSave(in_private_key_file_path, in_keyfile_password);
236
237 // The actual approval signing will be done during the following incremental save operation.
238 await doc.save(in_outpath, PDFNet.SDFDoc.SaveOptions.e_incremental);
239
240 console.log('================================================================================');
241 }
242
243 const ClearSignature = async (in_docpath, in_digsig_field_name, in_outpath) => {
244 console.log('================================================================================');
245 console.log('Clearing certification signature');
246
247 const doc = await PDFNet.PDFDoc.createFromFilePath(in_docpath);
248 doc.initSecurityHandler();
249
250 const digsig = await PDFNet.DigitalSignatureField.createFromField(await doc.getField(in_digsig_field_name));
251
252 console.log('Clearing signature: ' + in_digsig_field_name);
253 await digsig.clearSignature();
254
255 if (!(await digsig.hasCryptographicSignature())) {
256 console.log('Cryptographic signature cleared properly.');
257 }
258
259 // Save incrementally so as to not invalidate other signatures from previous saves.
260 await doc.save(in_outpath, PDFNet.SDFDoc.SaveOptions.e_incremental);
261
262 console.log('================================================================================');
263 }
264
265 const PrintSignaturesInfo = async (in_docpath) => {
266 console.log('================================================================================');
267 console.log('Reading and printing digital signature information');
268
269 const doc = await PDFNet.PDFDoc.createFromFilePath(in_docpath);
270 doc.initSecurityHandler();
271 if (!(await doc.hasSignatures())) {
272 console.log('Doc has no signatures.');
273 console.log('================================================================================');
274 return;
275 } else {
276 console.log('Doc has signatures.');
277 }
278
279
280 for (const fitr = await doc.getFieldIteratorBegin(); await fitr.hasNext(); await fitr.next()) {
281 const field = await fitr.current();
282 (await field.isLockedByDigitalSignature()) ? console.log('==========\nField locked by a digital signature') :
283 console.log('==========\nField not locked by a digital signature');
284
285 console.log('Field name: ' + await field.getName());
286 console.log('==========');
287 }
288
289 console.log('====================\nNow iterating over digital signatures only.\n====================');
290
291 const digsig_fitr = await doc.getDigitalSignatureFieldIteratorBegin();
292 for (; await digsig_fitr.hasNext(); await digsig_fitr.next()) {
293 console.log('==========');
294 const digsigfield = await digsig_fitr.current();
295 console.log('Field name of digital signature: ' + await (await PDFNet.Field.create(await digsigfield.getSDFObj())).getName());
296
297 if (!(await digsigfield.hasCryptographicSignature())) {
298 console.log('Either digital signature field lacks a digital signature dictionary, ' +
299 'or digital signature dictionary lacks a cryptographic Contents entry. ' +
300 'Digital signature field is not presently considered signed.\n' +
301 '==========');
302 continue;
303 }
304
305 const cert_count = await digsigfield.getCertCount();
306 console.log('Cert count: ' + cert_count);
307 for (var i = 0; i < cert_count; i++) {
308 const cert = await digsigfield.getCert(i);
309 console.log('Cert #' + i + ' size: ' + cert.byteLength);
310 }
311
312 const subfilter = await digsigfield.getSubFilter();
313
314 console.log('Subfilter type: ' + subfilter);
315
316 if (subfilter != PDFNet.DigitalSignatureField.SubFilterType.e_ETSI_RFC3161) {
317 console.log("Signature's signer: " + await digsigfield.getSignatureName());
318
319 const signing_time = await digsigfield.getSigningTime();
320 if (await signing_time.isValid()) {
321 console.log('Signing time is valid.');
322 }
323
324 console.log('Location: ' + await digsigfield.getLocation());
325 console.log('Reason: ' + await digsigfield.getReason());
326 console.log('Contact info: ' + await digsigfield.getContactInfo());
327 } else {
328 console.log('SubFilter == e_ETSI_RFC3161 (DocTimeStamp; no signing info)');
329 }
330
331 console.log((await digsigfield.hasVisibleAppearance()) ? 'Visible' : 'Not visible');
332
333 const digsig_doc_perms = await digsigfield.getDocumentPermissions();
334 const locked_fields = await digsigfield.getLockedFields();
335 for (var i = 0; i < locked_fields.length; i++) {
336 console.log('This digital signature locks a field named: ' + locked_fields[i]);
337 }
338
339 switch (digsig_doc_perms) {
340 case PDFNet.DigitalSignatureField.DocumentPermissions.e_no_changes_allowed:
341 console.log('No changes to the document can be made without invalidating this digital signature.');
342 break;
343 case PDFNet.DigitalSignatureField.DocumentPermissions.e_formfilling_signing_allowed:
344 console.log('Page template instantiation, form filling, and signing digital signatures are allowed without invalidating this digital signature.');
345 break;
346 case PDFNet.DigitalSignatureField.DocumentPermissions.e_annotating_formfilling_signing_allowed:
347 console.log('Annotating, page template instantiation, form filling, and signing digital signatures are allowed without invalidating this digital signature.');
348 break;
349 case PDFNet.DigitalSignatureField.DocumentPermissions.e_unrestricted:
350 console.log('Document not restricted by this digital signature.');
351 break;
352 }
353 console.log('==========');
354 }
355
356 console.log('================================================================================');
357 }
358
359 const CustomSigningAPI = async (doc_path, cert_field_name, private_key_file_path, keyfile_password, public_key_file_path, appearance_image_path, digest_algorithm_type, PAdES_signing_mode, output_path) => {
360 console.log('================================================================================');
361 console.log('Custom signing PDF document');
362
363 const doc = await PDFNet.PDFDoc.createFromFilePath(doc_path);
364 doc.initSecurityHandler();
365
366 const page1 = await doc.getPage(1);
367
368 const digsig_field = await doc.createDigitalSignatureField(cert_field_name);
369 const widgetAnnot = await PDFNet.SignatureWidget.createWithDigitalSignatureField(doc, new PDFNet.Rect(143, 287, 219, 306), digsig_field);
370 await page1.annotPushBack(widgetAnnot);
371
372 // (OPTIONAL) Add an appearance to the signature field.
373 const img = await PDFNet.Image.createFromFile(doc, appearance_image_path);
374 await widgetAnnot.createSignatureAppearance(img);
375
376 // Create a digital signature dictionary inside the digital signature field, in preparation for signing.
377 await digsig_field.createSigDictForCustomSigning('Adobe.PPKLite',
378 PAdES_signing_mode ? PDFNet.DigitalSignatureField.SubFilterType.e_ETSI_CAdES_detached : PDFNet.DigitalSignatureField.SubFilterType.e_adbe_pkcs7_detached,
379 7500); // For security reasons, set the contents size to a value greater than but as close as possible to the size you expect your final signature to be, in bytes.
380 // ... or, if you want to apply a certification signature, use CreateSigDictForCustomCertification instead.
381
382 // (OPTIONAL) Set the signing time in the signature dictionary, if no secure embedded timestamping support is available from your signing provider.
383 const current_date = new PDFNet.Date();
384 await current_date.setCurrentTime();
385 await digsig_field.setSigDictTimeOfSigning(current_date);
386
387 await doc.save(output_path, PDFNet.SDFDoc.SaveOptions.e_incremental);
388
389 // Digest the relevant bytes of the document in accordance with ByteRanges surrounding the signature.
390 const pdf_digest = await digsig_field.calculateDigest(digest_algorithm_type);
391
392 const signer_cert = await PDFNet.X509Certificate.createFromFile(public_key_file_path);
393
394 // Optionally, you can add a custom signed attribute at this point, such as one of the PAdES ESS attributes.
395 // The function we provide takes care of generating the correct PAdES ESS attribute depending on your digest algorithm.
396 const pades_versioned_ess_signing_cert_attribute = await PDFNet.DigitalSignatureField.generateESSSigningCertPAdESAttribute(signer_cert, digest_algorithm_type);
397
398 // Generate the signedAttrs component of CMS, passing any optional custom signedAttrs (e.g. PAdES ESS).
399 // The signedAttrs are certain attributes that become protected by their inclusion in the signature.
400 const signedAttrs = await PDFNet.DigitalSignatureField.generateCMSSignedAttributes(pdf_digest, pades_versioned_ess_signing_cert_attribute);
401
402 // Calculate the digest of the signedAttrs (i.e. not the PDF digest, this time).
403 const signedAttrs_digest = await PDFNet.DigestAlgorithm.calculateDigest(digest_algorithm_type, signedAttrs);
404
405 //////////////////////////// custom digest signing starts ////////////////////////////
406 // At this point, you can sign the digest (for example, with HSM). We use our own SignDigest function instead here as an example,
407 // which you can also use for your purposes if necessary as an alternative to the handler/callback APIs (i.e. Certify/SignOnNextSave).
408 const signature_value = await PDFNet.DigestAlgorithm.signDigest(
409 signedAttrs_digest,
410 digest_algorithm_type,
411 private_key_file_path,
412 keyfile_password);
413 //////////////////////////// custom digest signing ends //////////////////////////////
414
415 // Then, load all your chain certificates into a container of X509Certificate.
416 const chain_certs = [];
417
418 // Then, create ObjectIdentifiers for the algorithms you have used.
419 // Here we use digest_algorithm_type (usually SHA256) for hashing, and RSAES-PKCS1-v1_5 (specified in the private key) for signing.
420 const digest_algorithm_oid = await PDFNet.ObjectIdentifier.createFromDigestAlgorithm(digest_algorithm_type);
421 const signature_algorithm_oid = await PDFNet.ObjectIdentifier.createFromPredefined(PDFNet.ObjectIdentifier.Predefined.e_RSA_encryption_PKCS1);
422
423 // Then, put the CMS signature components together.
424 const cms_signature = await PDFNet.DigitalSignatureField.generateCMSSignature(
425 signer_cert, chain_certs, digest_algorithm_oid, signature_algorithm_oid, signature_value, signedAttrs);
426
427 // Write the signature to the document.
428 await doc.saveCustomSignature(cms_signature, digsig_field, output_path);
429
430 console.log('================================================================================');
431 };
432
433 const TimestampAndEnableLTV = async (in_docpath, in_tsa_url, in_trusted_cert_path, in_appearance_img_path, in_outpath) => {
434 const doc = await PDFNet.PDFDoc.createFromFilePath(in_docpath);
435 doc.initSecurityHandler();
436 const doctimestamp_signature_field = await doc.createDigitalSignatureField();
437 const tst_config = await PDFNet.TimestampingConfiguration.createFromURL(in_tsa_url);
438 const opts = await PDFNet.VerificationOptions.create(PDFNet.VerificationOptions.SecurityLevel.e_compatibility_and_archiving);
439 /* It is necessary to add to the VerificationOptions a trusted root certificate corresponding to
440 the chain used by the timestamp authority to sign the timestamp token, in order for the timestamp
441 response to be verifiable during DocTimeStamp signing. It is also necessary in the context of this
442 function to do this for the later LTV section, because one needs to be able to verify the DocTimeStamp
443 in order to enable LTV for it, and we re-use the VerificationOptions opts object in that part. */
444 await opts.addTrustedCertificateUString(in_trusted_cert_path);
445 /* By default, we only check online for revocation of certificates using the newer and lighter
446 OCSP protocol as opposed to CRL, due to lower resource usage and greater reliability. However,
447 it may be necessary to enable online CRL revocation checking in order to verify some timestamps
448 (i.e. those that do not have an OCSP responder URL for all non-trusted certificates). */
449 await opts.enableOnlineCRLRevocationChecking(true);
450
451 const widgetAnnot = await PDFNet.SignatureWidget.createWithDigitalSignatureField(doc, new PDFNet.Rect(0, 100, 200, 150), doctimestamp_signature_field);
452 await (await doc.getPage(1)).annotPushBack(widgetAnnot);
453
454 // (OPTIONAL) Add an appearance to the signature field.
455 const img = await PDFNet.Image.createFromFile(doc, in_appearance_img_path);
456 await widgetAnnot.createSignatureAppearance(img);
457
458 console.log('Testing timestamping configuration.');
459 const config_result = await tst_config.testConfiguration(opts);
460 if (await config_result.getStatus()) {
461 console.log('Success: timestamping configuration usable. Attempting to timestamp.');
462 } else {
463 // Print details of timestamping failure.
464 console.log(await config_result.getString());
465 if (await config_result.hasResponseVerificationResult()) {
466 const tst_result = await config_result.getResponseVerificationResult();
467 console.log('CMS digest status: ' + await tst_result.getCMSDigestStatusAsString());
468 console.log('Message digest status: ' + await tst_result.getMessageImprintDigestStatusAsString());
469 console.log('Trust status: ' + await tst_result.getTrustStatusAsString());
470 }
471 return false;
472 }
473
474 await doctimestamp_signature_field.timestampOnNextSave(tst_config, opts);
475
476 // Save/signing throws if timestamping fails.
477 await doc.save(in_outpath, PDFNet.SDFDoc.SaveOptions.e_incremental);
478
479 console.log('Timestamping successful. Adding LTV information for DocTimeStamp signature.');
480
481 // Add LTV information for timestamp signature to document.
482 const timestamp_verification_result = await doctimestamp_signature_field.verify(opts);
483 if (!(await doctimestamp_signature_field.enableLTVOfflineVerification(timestamp_verification_result))) {
484 console.log('Could not enable LTV for DocTimeStamp.');
485 return false;
486 }
487 await doc.save(in_outpath, PDFNet.SDFDoc.SaveOptions.e_incremental);
488 console.log('Added LTV information for DocTimeStamp signature successfully.');
489
490 return true;
491 }
492
493 const main = async () => {
494 var ret = 0;
495
496 //////////////////// TEST 0:
497 /* Create an approval signature field that we can sign after certifying.
498 (Must be done before calling CertifyOnNextSave/SignOnNextSave/WithCustomHandler.) */
499 try {
500 const doc = await PDFNet.PDFDoc.createFromFilePath(input_path + 'waiver.pdf');
501 doc.initSecurityHandler();
502 const approval_signature_field = await doc.createDigitalSignatureField('PDFTronApprovalSig');
503 const widgetAnnotApproval = await PDFNet.SignatureWidget.createWithDigitalSignatureField(doc, new PDFNet.Rect(300, 287, 376, 306), approval_signature_field);
504 const page1 = await doc.getPage(1);
505 await page1.annotPushBack(widgetAnnotApproval);
506 await doc.save(output_path + 'waiver_withApprovalField_output.pdf', PDFNet.SDFDoc.SaveOptions.e_remove_unused);
507 } catch (err) {
508 console.log(err);
509 ret = 1;
510 }
511
512 //////////////////// TEST 1: certify a PDF.
513 try {
514 await CertifyPDF(input_path + 'waiver_withApprovalField.pdf',
515 'PDFTronCertificationSig',
516 input_path + 'pdftron.pfx',
517 'password',
518 input_path + 'pdftron.bmp',
519 output_path + 'waiver_withApprovalField_certified_output.pdf');
520 await PrintSignaturesInfo(output_path + 'waiver_withApprovalField_certified_output.pdf');
521 } catch (err) {
522 console.log(err);
523 ret = 1;
524 }
525
526 //////////////////// TEST 2: approval-sign an existing, unsigned signature field in a PDF that already has a certified signature field.
527 try {
528 await SignPDF(input_path + 'waiver_withApprovalField_certified.pdf',
529 'PDFTronApprovalSig',
530 input_path + 'pdftron.pfx',
531 'password',
532 input_path + 'signature.jpg',
533 output_path + 'waiver_withApprovalField_certified_approved_output.pdf');
534 await PrintSignaturesInfo(output_path + 'waiver_withApprovalField_certified_approved_output.pdf');
535 } catch (err) {
536 console.log(err);
537 ret = 1;
538 }
539
540 //////////////////// TEST 3: Clear a certification from a document that is certified and has an approval signature.
541 try {
542 await ClearSignature(input_path + 'waiver_withApprovalField_certified_approved.pdf',
543 'PDFTronCertificationSig',
544 output_path + 'waiver_withApprovalField_certified_approved_certcleared_output.pdf');
545 await PrintSignaturesInfo(output_path + 'waiver_withApprovalField_certified_approved_certcleared_output.pdf');
546 } catch (err) {
547 console.log(err);
548 ret = 1;
549 }
550
551 //////////////////// TEST 4: Verify a document's digital signatures.
552 // EXPERIMENTAL. Digital signature verification is undergoing active development, but currently does not support a number of features. If we are missing a feature that is important to you, or if you have files that do not act as expected, please contact us using one of the following forms: https://apryse.com/form/trial-support or https://apryse.com/form/request
553 try {
554 if (!(await VerifyAllAndPrint(input_path + 'waiver_withApprovalField_certified_approved.pdf', input_path + 'pdftron.cer'))) {
555 ret = 1;
556 }
557 } catch (err) {
558 console.log(err);
559 ret = 1;
560 }
561
562 //////////////////// TEST 5: Verify a document's digital signatures in a simple fashion using the document API.
563 try {
564 if (!(await VerifySimple(input_path + 'waiver_withApprovalField_certified_approved.pdf', input_path + 'pdftron.cer'))) {
565 ret = 1;
566 }
567 } catch (err) {
568 console.log(err);
569 ret = 1;
570 }
571
572 //////////////////// TEST 6: Custom signing API.
573 // The Apryse custom signing API is a set of APIs related to cryptographic digital signatures
574 // which allows users to customize the process of signing documents. Among other things, this
575 // includes the capability to allow for easy integration of PDF-specific signing-related operations
576 // with access to Hardware Security Module (HSM) tokens/devices, access to cloud keystores, access
577 // to system keystores, etc.
578 try {
579 await CustomSigningAPI(input_path + 'waiver.pdf',
580 'PDFTronCertificationSig',
581 input_path + 'pdftron.pfx',
582 'password',
583 input_path + 'pdftron.cer',
584 input_path + 'signature.jpg',
585 PDFNet.DigestAlgorithm.Type.e_SHA256,
586 true,
587 output_path + 'waiver_custom_signed.pdf');
588 } catch (err) {
589 console.log(err);
590 ret = 1;
591 }
592
593 //////////////////// TEST 7: Timestamp a document, then add Long Term Validation (LTV) information for the DocTimeStamp.
594 // try {
595 // // Replace YOUR_URL_OF_TSA with the timestamp authority (TSA) URL to use during timestamping.
596 // // For example, as of July 2024, http://timestamp.globalsign.com/tsa/r6advanced1 was usable.
597 // // Note that this url may not work in the future. A reliable solution requires using your own TSA.
598 // const tsa_url = 'YOUR_URL_OF_TSA';
599 // if (tsa_url == 'YOUR_URL_OF_TSA')
600 // {
601 // throw new Error('The URL of your timestamp authority was not specified.');
602 // }
603 //
604 // // Replace YOUR_CERTIFICATE with the trusted root certificate corresponding to the chain used by the timestamp authority.
605 // // For example, as of July 2024, https://secure.globalsign.com/cacert/gstsacasha384g4.crt was usable.
606 // // Note that this certificate may not work in the future. A reliable solution requires using your own TSA certificate.
607 // const trusted_cert_path = 'YOUR_CERTIFICATE';
608 // if (trusted_cert_path == 'YOUR_CERTIFICATE')
609 // {
610 // throw new Error('The path to your timestamp authority trusted root certificate was not specified.');
611 // }
612 //
613 // if (!(await TimestampAndEnableLTV(input_path + 'waiver.pdf',
614 // tsa_url,
615 // trusted_cert_path,
616 // input_path + 'signature.jpg',
617 // output_path + 'waiver_DocTimeStamp_LTV.pdf'))) {
618 // ret = 1;
619 // }
620 // } catch (err) {
621 // console.log(err);
622 // ret = 1;
623 // }
624
625 //////////////////// End of tests. ////////////////////
626 if (!ret) {
627 console.log('Tests successful.\n==========');
628 }
629 else {
630 console.log('Tests FAILED!!!\n==========');
631 }
632 };
633
634 PDFNet.runWithCleanup(main, PDFTronLicense.Key).catch(function (error) {
635 console.log('Error: ' + JSON.stringify(error));
636 }).then(function () { return PDFNet.shutdown(); });
637 };
638 exports.runDigitalSignatureTest();
639})(exports);
640// eslint-disable-next-line spaced-comment
641//# sourceURL=DigitalSignatureTest.js

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales