DigitalSignature

Sample JavaScript code to use Apryse SDK's high-level digital signature API for digitally signing and/or certifying PDF files. Learn more about our Web SDK and PDF Digital Signature Library.

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

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales