Foxit PDF SDK for Web: Digital Signatures
A digital signature is a digitally generated representation of a person’s identity through either an image of a persons signature or a computer generated typed signature which verifies a person’s identify and authenticates the contents of a document. In technical terms digital signatures are generated public key encryption that confirms a person’s identity in order to substantiate a document for legal or other purposes. Digital signatures can happen at page or document level depending on regulation and company standards.
Digital Signatures add a layer of security to documents that can help lessen the amount of steps needed to sign up to your services. Valid contracts and authenticate documents with customizable electronic signatures that can adhere to any standards or regulations across the world, including eIDAS, UETA and ESIGN. Our technology can be integrated with any PDF documents, like smart forms and is compliant with PDF 2.0.
Digital Signature
In this section, you will learn about the general steps to sign and verify signature, related signature APIs, ways to interact with the digital signature, and the test signature service routes we provided.
Steps to sign and verify digital signature on PDF
To sign and verify a digital signature on PDF, you should go over the following procedures:
- Sign Document
a) Generate a file stream which contains signature’s byteRange. You may refer to PDF Reference 1.7+ for details.
b) Calculate the message digest of the content covered by signature’s byteRange. This can be implemented by calling PDFUI.registerSignHandler(signerInfo) or PDFDoc.sign(signInfo,digestSignHandler).
c) Get signedData by signing the digest using certification. This can be implemented by calling PDFUI.registerSignHandler(signerInfo) or PDFDoc.sign(signInfo,digestSignHandler).
d) Write the signedData into the file stream. The signedData’s position is specified in byteRange).
- Verify signature
e) Get the original(unmodified) file content, the byteRange of signature, the signed data and signer.
f) Calculate the message digest of the content covered by signature’s byteRange. This can be implemented by calling PDFUI.setVerifyHandler(verifyFunction) or PDFDoc.verifySignature(signatureField, verifyHandler).
g) Verify the digest and signed data, and output the verified state result which includes information about document changes, issuer and timestamp status, ect.. This can be implemented by callingPDFUI.setVerifyHandler(verifyFunction) or PDFDoc.verifySignature(signatureField, verifyHandler).
Related digital signature APIs
PDFUI.registerSignHandler(signerInfo)
This method is used to register signed data. Here is the example code:
pdfui.registerSignHandler({ filter: "Adobe.PPKLite", subfilter: "adbe.pkcs7.sha1", flag: 0x100, distinguishName: "[email protected]", location: "FZ", reason: "Test", signer: "web sdk", sign: (signInfo, buffer) => { //sign handler which complete the signing action, return a Promise with signed data; //function getDigest() and sign() should be completed by user. let digest = getDigest(buffer); let signData = sign(digest); return Promise.resolve(signData); } } ) ;
PDFUI.setVerifyHandler(verifyFunction)
This method is used to set verification handler which will be called when a signature is being verified. Verification handler returns a verifying result state called Signature_State. Here is the example code:
pdfui.setVerifyHandler((signatureField, plainBuffer, signedData) => { //function getDigest() and verify() should be completed by user. let digest = getDigest(plainBuffer); let verifiedStatus = verify( signatureField.getFilter(), signatureField.getSubfilter(), signatureField.getSigner(), digest, signedData ); return Promise.resolve(verifiedStatus);});
PDFDoc.sign(signInfo,digestSignHandler)
This method is used to sign the document. A message digest and sign function are required. Here is the example code:
/** * @returns {Blob} - File stream of signed document. */const signResult= await pdfdoc.sign(signInfo,(signInfo,buffer) => { //function getSignData() should be completed by developer. return Promise.resolve(getSignData(signInfo,buffer))});
PDFDoc.verifySignature(signatureField, verifyHandler)
This method is used to verify the signature. A callback function is required. Here is the example code:
/** * @returns {number} - Signature state. */var result = await singedPDF.verifySignature( pdfform.getField("Signature_0"), function verify(signatureField, plainBuffer, signedData, hasDataOutOfScope) { //function verifySignData() should be completed by developer. let signInfo = { byteRange: signatureField.getByteRange(), signer: signatureField.getSigner(), filter: signatureField.getFilter(), subfilter: signatureField.getSubfilter(), }; return Promise.resolve(verifySignData(signInfo, buffer)); } ) ;
PDFSignature Class
- PDFSignature.isSigned() – Check if the current signature is signed or not.
- PDFSignature.getByteRange() – Get byte range which specifies scope of file stream of current signature.
- PDFSignature.getFilter() – Get the current signature filter.
- PDFSignature.getSubfilter() – Get the current signature subfilter.
Interact with the digital signature feature
You can try our signature workflow by the way of using API or UI. This workflow is based on the Node.js backend which can be accessed at ./server/pkcs7 in our package.
Method 1 Programmatically place a signature on the current document
2) Run https://webviewer-demo.foxit.com/ with starting a service.
3) Run the following code on the console. A signature field will be automatically created and a digital signature will be placed on it.
4) A signed document will be downloaded and reopened in your viewer. You can click on the signature field to verify it.
//this code example assumes you are running the signature service on a local host and using the default port 7777.
var pdfviewer = await pdfui.getPDFViewer();
var pdfdoc = await pdfviewer.getCurrentPDFDoc();
var signInfo = {
filter: "Adobe.PPKLite",
subfilter: "adbe.pkcs7.sha1",
rect: { left: 10, bottom: 10, right: 300, top: 300 },
pageIndex: 0,
flag: 511,
signer: "signer",
reason: "reason",
email: "email",
distinguishName: "distinguishName",
location: "loc",
text: "text",
};
const signResult = await pdfdoc.sign(signInfo, (signInfo,buffer) => {
return requestData(
"post",
"http://127.0.0.1:7777/digest_and_sign",
"arraybuffer",
{ plain: new Blob([buffer]) }
);
});
//open the signed PDF
const singedPDF = await pdfviewer.openPDFByFile(signResult);
var pdfform = await singedPDF.loadPDFForm();
var verify = (signatureField, plainBuffer, signedData, hasDataOutOfScope) => {
return requestData("post", "http://127.0.0.1:7777/verify", "text", {
filter: signatureField.getFilter(),
subfilter: signatureField.getSubfilter(),
signer: signatureField.getSigner(),
plainContent: new Blob([plainBuffer]),
signedData: new Blob([signedData]),
});
};
var result = singedPDF.verifySignature(pdfform.getField("Signature_0"), verify);
Method 2 Place a signature from the UI
Let’s use our online viewer https://webviewer-demo.foxit.com/ to experience how it works.
- Preparation
Open https://webviewer-demo.foxit.com/on your browser.
- Add and sign a signature
a) Click the signature button in the Form tab to switch to the addSignatureStateHandler.
b) Click to draw a rectangle field on the page.
c) Click Hand tool or press Esc key to switch to the handStateHandler.
d) Set the sign information on the pop-up box and click Ok to sign it. The signed document will be downloaded and re-opened automatically.
- Verify signature
Click the signed signature field with the hand tool to verify it. A prompt box will be pop-up reporting the verifying result.
Note: To make this signature workflow work, we have referenced the following callback code in the index.html file of the complete_webViewer, and run a signature service on our backend.
//the variable `origin` refers to the service http address where your signature service is running.//signature handlers var requestData = (type, url, responseType, body) => { return new Promise((res, rej) => { var xmlHttp = new XMLHttpRequest(); xmlHttp.open(type, url); xmlHttp.responseType = responseType || "arraybuffer"; let formData = new FormData(); if (body) { for (let key in body) { if (body[key] instanceof Blob) { formData.append(key, body[key], key); } else { formData.append(key, body[key]); } } } xmlHttp.onload = (e) => { let status = xmlHttp.status; if ((status >= 200 && status < 300) || status === 304) { res(xmlHttp.response); } }; xmlHttp.send(body ? formData : null); }); }; //set signature information and function. This function can be called to register different algorithm and information for signing//the api `/digest_and_sign` is used to calculate the digest and return the signed data pdfui.registerSignHandler({ filter: "Adobe.PPKLite", subfilter: "adbe.pkcs7.sha1", flag: 0x100, distinguishName: "[email protected]", location: "FZ", reason: "Test", signer: "web sdk", showTime: true, sign: (setting, buffer) => { return requestData("post", "origin", "arraybuffer", { plain: new Blob([buffer]), }); } }); //set signature verification function //the api /verify is used to verify the state of signature pdfui.setVerifyHandler((signatureField, plainBuffer, signedData) => { return requestData("post", "origin", "text", { filter: signatureField.getFilter(), subfilter: signatureField.getSubfilter(), signer: signatureField.getSigner(), plainContent: new Blob([plainBuffer]), signedData: new Blob([signedData]), }); });
About signature HTTP service
If you don’t have backend signature service available, you can use the following HTTP service routes which we provide for the test purpose.
Server in US:
http://webviewer-demo.foxit.com/signature/digest_and_sign
http://webviewer-demo.foxit.com/signature/verify
https://webviewer-demo.foxit.com/signature/digest_and_sign
https://webviewer-demo.foxit.com/signature/verify
Server in China:
http://webviewer-demo.foxitsoftware.cn/signature/digest_and_sign
http://webviewer-demo.foxitsoftware.cn/signature/verify
Updated on June 30, 2021