# # 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 calling`PDFUI.setVerifyHandler(verifyFunction)` or `PDFDoc.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

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,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 = singedPDF.getPDFForm();
    var verify = async (signatureField, plainBuffer, signedData, hasDataOutOfScope) => {
      return requestData("post", "http://127.0.0.1:7777/verify", "text", {
        filter: await signatureField.getFilter(),
        subfilter: await signatureField.getSubfilter(),
        signer: await 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=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)