Some test text!

menu

Digitally sign PDF files in JavaScript

More languages

chevron_right
More languages
JavaScript
Java (Android)
C++
C#
C# (.NET Core)
Java
Kotlin
Obj-C
JS (Node.js)
PHP
Python
Ruby
Swift
C# (UWP)
VB
C# (Xamarin)

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

Get StartedSamplesDownload

To run this sample, get started with a free trial of PDFTron SDK.

//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2020 by PDFTron Systems Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------


const { PDFNet } = require('../../../lib/pdfnet.js');

((exports) => {
  'use strict';

  exports.runDigitalSignatureTest = () => {
    const input_path = '../../TestFiles/';
    const output_path = '../../TestFiles/Output/';

    // 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://www.pdftron.com/form/trial-support/ or https://www.pdftron.com/form/request/
    const VerifyAllAndPrint = async (in_docpath, in_public_key_file_path) => {
      console.log('==========');

      const doc = await PDFNet.PDFDoc.createFromFilePath(in_docpath);
      doc.initSecurityHandler();

      const opts = await PDFNet.VerificationOptions.create(PDFNet.VerificationOptions.SecurityLevel.e_compatibility_and_archiving);

      // Trust the public certificate we use for signing.
      const file = await PDFNet.Filter.createMappedFileFromUString(in_public_key_file_path);

      const file_reader = await PDFNet.FilterReader.create(file);

      const trusted_cert_buf = await file_reader.readAllIntoBuffer();
      await opts.addTrustedCertificate(trusted_cert_buf);

      // Iterate over the signatures and verify all of them.
      const digsig_fitr = await doc.getDigitalSignatureFieldIteratorBegin();
      var verification_status = true;
      for (; await digsig_fitr.hasNext(); await digsig_fitr.next()) {
        const curr = await digsig_fitr.current();
        const result = await curr.verify(opts);
        if (await result.getVerificationStatus()) {
          console.log('Signature verified, ');
        } else {
          console.log('Signature verification failed, ');
          verification_status = false;
        }
        console.log('objnum: ' + await (await curr.getSDFObj()).getObjNum());

        switch (await result.getSignersDigestAlgorithm()) {
          case PDFNet.DigestAlgorithm.Type.e_SHA1:
            console.log('Digest algorithm: SHA-1');
            break;
          case PDFNet.DigestAlgorithm.Type.e_SHA256:
            console.log('Digest algorithm: SHA-256');
            break;
          case PDFNet.DigestAlgorithm.Type.e_SHA384:
            console.log('Digest algorithm: SHA-384');
            break;
          case PDFNet.DigestAlgorithm.Type.e_SHA512:
            console.log('Digest algorithm: SHA-512');
            break;
          case PDFNet.DigestAlgorithm.Type.e_RIPEMD160:
            console.log('Digest algorithm: RIPEMD-160');
            break;
          case PDFNet.DigestAlgorithm.Type.e_unknown_digest_algorithm:
            console.log('Digest algorithm: unknown');
            break;
        }

        console.log('Detailed verification result: ');
        switch (await result.getDocumentStatus()) {
          case PDFNet.VerificationResult.DocumentStatus.e_no_error:
            console.log('\tNo general error to report.');
            break;
          case PDFNet.VerificationResult.DocumentStatus.e_corrupt_file:
            console.log('\tSignatureHandler reported file corruption.');
            break;
          case PDFNet.VerificationResult.DocumentStatus.e_unsigned:
            console.log('\tThe signature has not yet been cryptographically signed.');
            break;
          case PDFNet.VerificationResult.DocumentStatus.e_bad_byteranges:
            console.log('\tSignatureHandler reports corruption in the ByteRanges in the digital signature.');
            break;
          case PDFNet.VerificationResult.DocumentStatus.e_corrupt_cryptographic_contents:
            console.log('\tSignatureHandler reports corruption in the Contents of the digital signature.');
            break;
        }
        switch (await result.getDigestStatus()) {
          case PDFNet.VerificationResult.DigestStatus.e_digest_invalid:
            console.log('\tThe digest is incorrect.');
            break;
          case PDFNet.VerificationResult.DigestStatus.e_digest_verified:
            console.log('\tThe digest is correct.');
            break;
          case PDFNet.VerificationResult.DigestStatus.e_digest_verification_disabled:
            console.log('\tDigest verification has been disabled.');
            break;
          case PDFNet.VerificationResult.DigestStatus.e_weak_digest_algorithm_but_digest_verifiable:
            console.log('\tThe digest is correct, but the digest algorithm is weak and not secure.');
            break;
          case PDFNet.VerificationResult.DigestStatus.e_no_digest_status:
            console.log('\tNo digest status to report.');
            break;
          case PDFNet.VerificationResult.DigestStatus.e_unsupported_encoding:
            console.log('\tNo installed SignatureHandler was able to recognize the signature\'s encoding.');
            break;
        }
        switch (await result.getTrustStatus()) {
          case PDFNet.VerificationResult.TrustStatus.e_trust_verified:
            console.log('\tEstablished trust in signer successfully.');
            break;
          case PDFNet.VerificationResult.TrustStatus.e_untrusted:
            console.log('\tTrust could not be established.');
            break;
          case PDFNet.VerificationResult.TrustStatus.e_trust_verification_disabled:
            console.log('\tTrust verification has been disabled.');
            break;
          case PDFNet.VerificationResult.TrustStatus.e_no_trust_status:
            console.log('\tNo trust status to report.');
            break;
        }
        switch (await result.getPermissionsStatus()) {
          case PDFNet.VerificationResult.ModificationPermissionsStatus.e_invalidated_by_disallowed_changes:
            console.log('\tThe document has changes that are disallowed by the signature\'s permissions settings.');
            break;
          case PDFNet.VerificationResult.ModificationPermissionsStatus.e_has_allowed_changes:
            console.log('\tThe document has changes that are allowed by the signature\'s permissions settings.');
            break;
          case PDFNet.VerificationResult.ModificationPermissionsStatus.e_unmodified:
            console.log('\tThe document has not been modified since it was signed.');
            break;
          case PDFNet.VerificationResult.ModificationPermissionsStatus.e_permissions_verification_disabled:
            console.log('\tPermissions verification has been disabled.');
            break;
          case PDFNet.VerificationResult.ModificationPermissionsStatus.e_no_permissions_status:
            console.log('\tNo permissions status to report.');
            break;
        }

        const changes = await result.getDisallowedChanges();
        for (var i = 0; i < changes.length; ++i) {
          change = changes[i];
          console.log('\tDisallowed change: ' + await change.getTypeAsString() + ', objnum: ' + await change.getObjNum());
        }

        // Get and print all the detailed trust-related results, if they are available.
        if (await result.hasTrustVerificationResult()) {
          const trust_verification_result = await result.getTrustVerificationResult();
          console.log(await trust_verification_result.wasSuccessful() ? 'Trust verified.' : 'Trust not verifiable.');
          console.log('Trust verification result string: ' + await trust_verification_result.getResultString());

          const tmp_time_t = await trust_verification_result.getTimeOfTrustVerification();
          switch (await trust_verification_result.getTimeOfTrustVerificationEnum()) {
            case PDFNet.VerificationOptions.TimeMode.e_current:
              console.log('Trust verification attempted with respect to current time.');
              break;
            case PDFNet.VerificationOptions.TimeMode.e_signing:
              console.log('Trust verification attempted with respect to signing time: ');
              break;
            case PDFNet.VerificationOptions.TimeMode.e_timestamp:
              console.log('Trust verification attempted with respect to secure embedded timestamp: ');
              break;
          }
          console.log(new Date(tmp_time_t));
        }
        else {
          console.log('No detailed trust verification result available.');
        }

        console.log('==========');
      }

      return verification_status;
    }

    const SignPDF = async() => {
      const infile = '../../TestFiles/doc_to_sign.pdf';
      const certfile = '../../TestFiles/pdftron.pfx';
      const imagefile = '../../TestFiles/signature.jpg';

      const result = true;
      try {
        console.log('Signing PDF document: ');
        const doc = await PDFNet.PDFDoc.createFromFilePath(infile);
        doc.initSecurityHandler();
        console.log('PDFNet and PDF document initialized and locked');

        const sigHandlerId = await doc.addStdSignatureHandlerFromFile(certfile, 'password');

        // Obtain the signature form field from the PDFDoc via Annotation.
        const sigField = await doc.getField('Signature1');
        const widgetAnnot = await PDFNet.WidgetAnnot.createFromObj((await sigField.getSDFObj()));

        // Tell PDFNetC to use the SignatureHandler created to sign the new signature form field.
        const sigDict = await sigField.useSignatureHandler(sigHandlerId);

        // Add more information to the signature dictionary.
        // sigDict.PutName("SubFilter", "adbe.pkcs7.detached");
        await sigDict.putString('Name', 'PDFTron');
        await sigDict.putString('Location', 'Vancouver, BC');
        await sigDict.putString('Reason', 'Document verification.');

        // Add the signature appearance.
        const apWriter = await PDFNet.ElementWriter.create();
        const apBuilder = await PDFNet.ElementBuilder.create();

        apWriter.begin(doc);

        const sigImg = await PDFNet.Image.createFromFile(doc, imagefile);
        const w = await sigImg.getImageWidth();
        const h = await sigImg.getImageHeight();
        let apElement = await apBuilder.createImageScaled(sigImg, 0, 0, w, h);
        apWriter.writePlacedElement(apElement);
        let apObj = await apWriter.end();
        apObj.putRect('BBox', 0, 0, w, h);
        apObj.putName('Subtype', 'Form');
        apObj.putName('Type', 'XObject');
        apWriter.begin(doc);
        apElement = await apBuilder.createFormFromStream(apObj);
        apWriter.writePlacedElement(apElement);
        apObj = await apWriter.end();
        apObj.putRect('BBox', 0, 0, w, h);
        apObj.putName('Subtype', 'Form');
        apObj.putName('Type', 'XObject');

        await widgetAnnot.setAppearance(apObj);
        await widgetAnnot.refreshAppearance();

        await doc.save('../../TestFiles/Output/signed_doc.pdf', 0);

        console.log('Finished signing PDF document');
      } catch (err) {
        console.log(err);
      }
      return result;
    };

    const CertifyPDF = async() => {
      const infile = '../../TestFiles/newsletter.pdf';
      const certfile = '../../TestFiles/pdftron.pfx';
      const result = true;
      try {
        console.log('Certifying PDF document: "' + infile + '"');
        // Open existing PDF document.
        const doc = await PDFNet.PDFDoc.createFromFilePath(infile);
        doc.initSecurityHandler();
        // Add an StdSignatureHandler instance to PDFDoc, making sure to keep track of it using the ID returned.
        const sigHandlerId = await doc.addStdSignatureHandlerFromFile(certfile, 'password');
        // When using OpenSSLSignatureHandler class, uncomment the following lines and comment the line above.
        // Create a new instance of the SignatureHandler.
        // OpenSSLSignatureHandler sigHandler(certfile.ConvertToUtf8().c_str(), "password");
        // Add the SignatureHandler instance to PDFDoc, making sure to keep track of it using the ID returned.
        // SDF::SignatureHandlerId sigHandlerId = doc.AddSignatureHandler(sigHandler);

        // Create new signature form field in the PDFDoc.
        const sigField = await doc.fieldCreate('Signature1', PDFNet.Field.Type.e_signature);

        const page1 = await doc.getPage(1);
        const widgetAnnot = await PDFNet.WidgetAnnot.create((await doc.getSDFDoc()), (await PDFNet.Rect.init(0, 0, 0, 0)), sigField);
        page1.annotPushBack(widgetAnnot);
        widgetAnnot.setPage(page1);
        const widgetObj = await widgetAnnot.getSDFObj();
        widgetObj.putNumber('F', 132);
        widgetObj.putName('Type', 'Annot');

        // Tell PDFNetC to use the SignatureHandler created to sign the new signature form field.
        const sigDict = await sigField.useSignatureHandler(sigHandlerId);

        // Add more information to the signature dictionary.
        sigDict.putName('SubFilter', 'adbe.pkcs7.detached');
        sigDict.putString('Name', 'PDFTron');
        sigDict.putString('Location', 'Vancouver, BC');
        sigDict.putString('Reason', 'Document verification');

        // Appearance can be added to the widget annotation. Please see the "SignPDF()" function for details.

        // Add this sigDict as DocMDP in Perms dictionary from root
        const root = await doc.getRoot();
        const perms = await root.putDict('Perms');
        // add the sigDict as DocMDP (indirect) in Perms
        perms.put('DocMDP', sigDict);

        // add the additional DocMDP transform params
        const refObj = await sigDict.putArray('Reference');
        const transform = await refObj.pushBackDict();
        transform.putName('TransformMethod', 'DocMDP');
        transform.putName('Type', 'SigRef');
        const transformParams = await transform.putDict('TransformParams');
        transformParams.putNumber('P', 1); // Set permissions as necessary.
        transformParams.putName('Type', 'TransformParams');
        transformParams.putName('V', '1.2');

        await doc.save('../../TestFiles/Output/newsletter_certified.pdf', 0);

        console.log('Finished certifying PDF document.');
      } catch (err) {
        console.log(err);
      }
      return result;
    };

    const main = async () => {
      console.log('Beginning Test');
      let result = true;

      if (!(await SignPDF())) {
        result = false;
      }

      if (!(await CertifyPDF())) {
        result = false;
      }

      if (!(await VerifyAllAndPrint(input_path + "tiger_withApprovalField_certified_approved.pdf", input_path + "pdftron.cer"))) {
        result = false;
      }

      if (!result) {
        console.log('Tests Failed');
      } else {
        console.log('Done. All Tests Passed');
      }
    };
    // add your own license key as the second parameter, e.g. PDFNet.runWithCleanup(main, 'YOUR_LICENSE_KEY')
    PDFNet.runWithCleanup(main, 0).then(function () { PDFNet.shutdown(); });
  };
  exports.runDigitalSignatureTest();
})(exports);
// eslint-disable-next-line spaced-comment
//# sourceURL=DigitalSignatureTest.js
close

Free Trial

Get unlimited trial usage of PDFTron SDK to bring accurate, reliable, and fast document processing capabilities to any application or workflow.

Select a platform to get started with your free trial.

Unlimited usage. No email address required.

Join our live demo to learn about use cases & capabilities for WebViewer

Learn more
close