# 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

    1. Generate a file stream which contains signature's byteRange. You may refer to PDF Reference 1.7+ for details.
    2. 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).
    3. Get signedData by signing the digest using certification. This can be implemented by calling PDFUI.registerSignHandler(signerInfo) or PDFDoc.sign(signInfo,digestSignHandler).
    4. Write the signedData into the file stream. The signedData's position is specified in byteRange).
  • Verify signature

    1. Get the original(unmodified) file content, the byteRange of signature, the signed data and signer.
    2. 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).
    3. 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).

# PDFUI.registerSignHandler(signerInfo)

This method is used to register signer data. Here is the example code:

pdfui.registerSignHandler({
  filter: "Adobe.PPKLite",
  subfilter: "adbe.pkcs7.sha1",
  flag: 0x100,
  distinguishName: "support@foxitsoftware.com",
  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

  1. Run https://webviewer-demo.foxitsoftware.com/ with starting a service.
  2. Run the following code on the console. A signature field will be automatically created and a digital signature will be placed on it.
  3. 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.foxitsoftware.com/ to experience how it works.

  • Preparation

    • Open https://webviewer-demo.foxitsoftware.com/on your browser.
  • Add and sign a signature

    1. Click the signature button in the Form tab to switch to the addSignatureStateHandler.
    2. Click to draw a rectangle field on the page.
    3. Click Hand tool or press Esc key to switch to the handStateHandler.
    4. 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=test@foxitsoftware.com",
  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.foxitsoftware.com/signature/digest_and_sign

http://webviewer-demo.foxitsoftware.com/signature/verify

https://webviewer-demo.foxitsoftware.com/signature/digest_and_sign

https://webviewer-demo.foxitsoftware.com/signature/verify

Server in China:

http://webviewer-demo.foxitsoftware.cn/signature/digest_and_sign

http://webviewer-demo.foxitsoftware.cn/signature/verify