# 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
- Generate a file stream which contains signature's byteRange. You may refer to PDF Reference 1.7+ for details.
- Calculate the message digest of the content covered by signature's byteRange. This can be implemented by calling
PDFUI.registerSignHandler(signerInfo)
orPDFDoc.sign(signInfo,digestSignHandler)
. - Get signedData by signing the digest using certification. This can be implemented by calling
PDFUI.registerSignHandler(signerInfo)
orPDFDoc.sign(signInfo,digestSignHandler)
. - Write the signedData into the file stream. The signedData's position is specified in byteRange).
Verify signature
- Get the original(unmodified) file content, the byteRange of signature, the signed data and signer.
- Calculate the message digest of the content covered by signature's byteRange. This can be implemented by calling
PDFUI.setVerifyHandler(verifyFunction)
orPDFDoc.verifySignature(signatureField, verifyHandler)
. - 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 calling
PDFUI.setVerifyHandler(verifyFunction)
orPDFDoc.verifySignature(signatureField, verifyHandler)
.
# Related digital signature APIs
# PDFUI.registerSignHandler(signerInfo)
Currently, Foxit PDF SDK for Web supports two formats of signature filter: adbe.pkcs7.detached
and adbe.pkcs7.sha1
.
The digest algorithms supported by adbe.pkcs7.detached
are: 'sha1'
, 'sha256'
, and 'sha384'
.
The digest algorithm supported by adbe.pkcs7.sha1
is: 'sha1'
.
This method is used to register signer data. Here are the examples code:
Use adbe.pkcs7.detached
and sha256
:
pdfui.registerSignHandler({
filter: "Adobe.PPKLite",
subfilter: "adbe.pkcs7.detached",
flag: 0x100,
distinguishName: "e=foxit@foxitsoftware.cn",
location: "FZ",
reason: "Test",
signer: "web sdk",
showTime: true,
sign: (setting, plainContent) => {
return requestData("post", "http://localhost:7777/digest_and_sign", "arraybuffer", {
subfilter: setting.subfilter,
md: "sha256", // "sha1", "sha256", "sha384"
plain: plainContent,
});
},
});
Use adbe.pkcs7.sha1
and sha1
:
pdfui.registerSignHandler({
filter: "Adobe.PPKLite",
subfilter: "adbe.pkcs7.sha1",
flag: 0x100,
distinguishName: "support@foxitsoftware.com",
location: "FZ",
reason: "Test",
signer: "web sdk",
sign: (signInfo, plainContent) => {
//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(plainContent);//plainContent is a Blob data
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,plainContent) => {
//function getSignData() should be completed by developer.
return Promise.resolve(getSignData(signInfo,plainContent))//plainContent is a Blob data
});
# 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/signature-server-for-win
in our package.
# Method 1 Programmatically place a signature on the current document
- Run
https://webviewer-demo.foxitsoftware.com/
with starting a service. - Run the following code on the console. A signature field will be automatically created and a digital signature will be placed on it.
- 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,plainContent) => {
return requestData(
"post",
"http://127.0.0.1:7777/digest_and_sign",
"arraybuffer",
{ plain: plainContent }
);
});
//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.foxitsoftware.com/
to experience how it works.
Preparation
- Open
https://webviewer-demo.foxitsoftware.com/
on your browser.
- Open
Add and sign a signature
- Click the signature button in the Form tab to switch to the addSignatureStateHandler.
- Click to draw a rectangle field on the page.
- Click Hand tool or press
Esc
key to switch to the handStateHandler. - 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: "e=foxit@foxitsoftware.com",
location: "FZ",
reason: "Test",
signer: "web sdk",
showTime: true,
sign: (setting, plainContent) => {
return requestData("post", "origin", "arraybuffer", {
plain: plainContent,
});
}
});
//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.
http://webviewer-demo.foxitsoftware.com/signature/digest_and_sign (opens new window)
http://webviewer-demo.foxitsoftware.com/signature/verify (opens new window)