数字签名

数字签名

在本节中,您将了解签名和验证签名的常规步骤、相关的签名 API、数字签名交互的方式、以及我们提供的测试签名服务路由。

在 PDF 上签名和验证数字签名的步骤

在 PDF 上签名和验证数字签名,应执行以下过程:

  • 签名文档
  1. 生成包含签名覆盖范围信息(签名域字典的byteRange)的文档文件流。有关详细信息,请参阅 PDF Reference 1.7或更高版本。
  2. 对签名覆盖范围的文件流计算相应的摘要。这可以通过调用registerSignHandler(signerInfo)或者PDFDoc.sign(signInfo,digestSignHandler)接口来实现。
  3. 使用证书对摘要进行签名来获取signedData。这可以通过调用registerSignHandler(signerInfo)或者PDFDoc.sign(signInfo,digestSignHandler)接口来实现。
  4. 将signedData写入文件流。signedData的位置在byteRange中指定。
  • 验证签名
  1. 获取文档原始(未修改)文件流、签名覆盖范围信息(签名域字典的byteRange)、签名数据和签名者。
  2. 对签名覆盖范围的文件流计算相应的摘要。这可以通过调用setVerifyHandler(verifyFunction)或者PDFDoc.verifySignature(signatureField, verifyHandler) 接口来实现。
  3. 验证摘要和签名数据,并输出验证结果,其中包括文档是否被修改、签名者信息是否有效和时间戳是否过期等信息。这可以通过调用setVerifyHandler(verifyFunction) 或者PDFDoc.verifySignature(signatureField, verifyHandler) 接口来实现。

数字签名相关 API

PDFUI.registerSignHandler(signerInfo)

此方法用于注册签名者数据。下面是示例代码:

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)

此方法用于设置Verification handler,在验证签名时将调用该handler。Verification handler返回称为Signature_State的验证结果状态。下面是示例代码:

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)

此方法用于对文档进行签名。需要消息摘要和签名函数。下面是示例代码:

/**
 * @returns {Blob} - File stream of signed document.
 */
const signResult= await pdfdoc.sign(signInfo,(buffer) => {
 //function getSignData() should be completed by developer.
 return Promise.resolve(getSignData(signInfo,buffer))
});

PDFDoc.verifySignature(signatureField, verifyHandler)

此方法用于验证签名。需要回调函数。下面是示例代码:

/**
 * @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

  • isSigned() – 检查当前签名是否已签名。
  • getByteRange() – 获取当前签名的文件流中指定范围的字节范围。
  • getFilter() – 获取当前签名filter。
  • getSubfilter() – Get the current signature subfilter.

数字签名功能交互

您可以通过使用 API 或 UI 的方式体验我们的签名工作流。该工作流基于Node.js后端,可以访问发布包中的 ./server/pkcs7。

方法1以编程方式在当前文档上放置签名

  • Run https://webviewer-demo.foxitsoftware.com/with starting a service.
  • 开启服务器,运行https://webviewer-demo.foxitsoftware.com/
  • 在控制台中运行如下的代码。其将自动创建一个签名域,并在该签名域上放置一个数字签名。
  • 签名后的文档将会被下载,并在viewer中重新打开。您可以点击签名域来进行验证。
//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, (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);

方法2 以UI的方式来放置签名

通过我们在线的viewer https://webviewer-demo.foxitsoftware.com/ 来体验其是如何工作的。

  • 准备工作
  • 在您的浏览器中打开https://webviewer-demo.foxitsoftware.com/
  • 添加一个签名并对其进行签名
    1. 单击Form选项卡中的signature按钮,切换到addSignatureStateHandler。
    2. 单击左键,在页面上绘制一个矩形域。
    3. 点击手型工具或者按下ESC键,切换到handStateHandler。
    4. 在弹出框中设置签名信息,然后单击OK进行签名。签名后的文档将自动下载并重新打开。
  • 验证签名
  • 点击手型工具,然后点击已签名的签名域来进行验证。此时会弹出一个提示框,显示验证的结果。

备注:为了使此签名流程正常工作,我们在complete_webViewer的index.html文件中引用了如下的回调代码,并在后端运行签名服务。

//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=zhiquan_ye@foxitsoftware.cn",
 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]),
 });

签名 HTTP 服务

如果您没有可用的后端签名服务,您可以使用以下我们提供作为测试的 HTTP 服务路由。

美国服务器:

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

中国服务器:

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

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

更新于 2021年1月25日

这篇文章有用吗?

相关文章