//--------------------------------------------------------------------------------------- // Copyright (c) 2001-2023 by Apryse Software Inc. All Rights Reserved. // Consult legal.txt regarding legal and license information. //--------------------------------------------------------------------------------------- const fs = require('fs'); const crypto = require('crypto'); const { PDFNet } = require('../../../lib/pdfnet.js'); const PDFTronLicense = require('../../LicenseKey/NODEJS/LicenseKey'); ((exports) => { 'use strict'; exports.runDigitalSignatureTest = () => { const input_path = '../../TestFiles/'; const output_path = '../../TestFiles/Output/'; const SignPDF = async (in_docpath, in_approval_field_name, in_public_key_file_path, in_private_key_file_path, in_appearance_img_path, in_outpath) => { console.log('================================================================================'); console.log('Signing PDF document using PDFNet ' + await PDFNet.getVersionString()); const in_PAdES_signing_mode = false; const doc = await PDFNet.PDFDoc.create(); const page1 = await doc.pageCreate(); await doc.pagePushBack(page1); // Create a digital signature field and associated widget. const digsig_field = await doc.createDigitalSignatureField(in_approval_field_name); const widgetAnnot = await PDFNet.SignatureWidget.createWithDigitalSignatureField(doc, new PDFNet.Rect(143, 287, 219, 306), digsig_field); const img = await PDFNet.Image.createFromFile(doc, in_appearance_img_path); await widgetAnnot.createSignatureAppearance(img); await page1.annotPushBack(widgetAnnot); // Create a digital signature dictionary inside the digital signature field, in preparation for signing. await digsig_field.createSigDictForCustomSigning("Adobe.PPKLite", in_PAdES_signing_mode? PDFNet.DigitalSignatureField.SubFilterType.e_ETSI_CAdES_detached : PDFNet.DigitalSignatureField.SubFilterType.e_adbe_pkcs7_detached, 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. // ... or, if you want to apply a certification signature, use createSigDictForCustomCertification instead. await doc.save(in_outpath, PDFNet.SDFDoc.SaveOptions.e_incremental); // Digest the relevant bytes of the document in accordance with ByteRanges surrounding the signature. const pdf_digest = await digsig_field.calculateDigest(PDFNet.DigestAlgorithm.Type.e_SHA256); const signer_cert = await PDFNet.X509Certificate.createFromFile(in_public_key_file_path); // Generate the signedAttrs component of CMS, passing any optional custom signedAttrs (e.g. PAdES ESS). The signedAttrs are certain attributes that become protected by their inclusion in the signature. const signedAttrs = await PDFNet.DigitalSignatureField.generateCMSSignedAttributes(pdf_digest); ///////////////////////////////////////////////////////////////////////////////////////////// // At this point, use your signing provider (e.g. HSM device, cloud keystore) to sign the digest of signedAttrs. // Your input should be the variable signedAttrs_digest. In the following code, we assume the output is in a variable named signature_value. console.log('skipping calculateDigest on signedAttrs, which is instead handled by crypto.sign() API'); //const signedAttrs_digest = await PDFNet.DigestAlgorithm.calculateDigest(PDFNet.DigestAlgorithm.Type.e_SHA256, signedAttrs); const privateKey = fs.readFileSync(in_private_key_file_path); const signature_value = crypto.sign("SHA256", signedAttrs , privateKey); ///////////////////////////////////////////////////////////////////////////////////////////// // Then, load all your chain certificates into a container of X509Certificate. var chain_certs = []; chain_certs.push(signer_cert); // Then, create ObjectIdentifiers for the algorithms you have used. const digest_algorithm_oid = await PDFNet.ObjectIdentifier.createFromDigestAlgorithm(PDFNet.DigestAlgorithm.Type.e_SHA256); const signature_algorithm_oid = await PDFNet.ObjectIdentifier.createFromIntArray([1,2,840,113549,1,1]); console.log('generateCMSSignature'); // Then, put the CMS signature components together. const cms_signature = await PDFNet.DigitalSignatureField.generateCMSSignature( signer_cert, chain_certs, digest_algorithm_oid, signature_algorithm_oid, signature_value, signedAttrs); console.log('saveCustomSignature'); // Write the signature to the document. await doc.saveCustomSignature(cms_signature, digsig_field, in_outpath); console.log('================================================================================'); } const main = async () => { var ret = 0; //////////////////// TEST: Custom signing sample. try { await SignPDF(input_path + 'waiver_withApprovalField_certified.pdf', 'PDFTronApprovalSig', input_path + 'pdftron.cer', input_path + 'pdftron.key', input_path + 'signature.jpg', output_path + 'waiver_withApprovalField_certified_approved_output.pdf'); } catch (err) { console.log(err); ret = 1; } //////////////////// End of tests. //////////////////// if (!ret) { console.log('Tests successful.\n=========='); } else { console.log('Tests FAILED!!!\n=========='); } }; PDFNet.runWithCleanup(main, PDFTronLicense.Key).catch(function (error) { console.log('Error: ' + JSON.stringify(error)); }).then(function () { return PDFNet.shutdown(); }); }; exports.runDigitalSignatureTest(); })(exports); // eslint-disable-next-line spaced-comment //# sourceURL=DigitalSignatureTest.js