首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何用PHP从PDF中检索数字签名信息?

如何用PHP从PDF中检索数字签名信息?
EN

Stack Overflow用户
提问于 2017-09-26 23:23:35
回答 3查看 6.3K关注 0票数 21

我有一个应用程序,需要检索一些数据(签名者姓名)从数字签名“附加”的PDF文件。

我只在Java和C#中找到了使用iText类AcroFields方法GetSignatureNames的示例

编辑:我尝试过dump_data_fields和generate_fpdf的pdftk,结果是(不幸的):

代码语言:javascript
复制
/Fields [
<<
/V /dftk.com.lowagie.text.pdf.PdfDictionary@3048918
/T (Signature1)
>>]

代码语言:javascript
复制
FieldType: Signature
FieldName: Signature1
FieldFlags: 0
FieldJustification: Left

提前感谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-10-06 18:14:32

嗯,只用PHP实现这一点很复杂(我会说甚至是不可能的,但谁知道呢)。

首先,请阅读article about digital signature in Adobe PDF

其次,在阅读本文后,您将知道签名是根据/ByteRangea b c d指示符存储在b和c字节之间的

第三,我们可以从文档中提取b和c,然后提取签名本身(指南说它将是十六进制解码的PKCS7#对象)。

代码语言:javascript
复制
<?php

 $content = file_get_contents('test.pdf');

 $regexp = '#ByteRange\[\s*(\d+) (\d+) (\d+)#'; // subexpressions are used to extract b and c

 $result = [];
 preg_match_all($regexp, $content, $result);

 // $result[2][0] and $result[3][0] are b and c
 if (isset($result[2]) && isset($result[3]) && isset($result[2][0]) && isset($result[3][0]))
 {
     $start = $result[2][0];
     $end = $result[3][0];
     if ($stream = fopen('test.pdf', 'rb')) {
         $signature = stream_get_contents($stream, $end - $start - 2, $start + 1); // because we need to exclude < and > from start and end

         fclose($stream);
     }

     file_put_contents('signature.pkcs7', hex2bin($signature));
}

第四,在第三步之后,我们在文件signature.pkcs7中有了PKCS#7对象。不幸的是,我不知道用PHP从签名中提取信息的方法。因此您必须能够运行shell命令才能使用openssl

代码语言:javascript
复制
openssl pkcs7 -in signature.pkcs7 -inform DER -print_certs > info.txt

在文件info.txt中运行此命令后,您将拥有一系列证书。最后一个是你需要的。您可以看到文件的结构并解析所需的数据。

请同时参考this questionthis questionthis topic

编辑2017-10-09我特意建议你去看看exactly this question有一个代码可以根据你的需要进行调整。

代码语言:javascript
复制
use ASN1\Type\Constructed\Sequence;
use ASN1\Element;
use X509\Certificate\Certificate;       

$seq = Sequence::fromDER($binaryData);
$signed_data = $seq->getTagged(0)->asExplicit()->asSequence();
// ExtendedCertificatesAndCertificates: https://tools.ietf.org/html/rfc2315#section-6.6
$ecac = $signed_data->getTagged(0)->asImplicit(Element::TYPE_SET)->asSet();
// ExtendedCertificateOrCertificate: https://tools.ietf.org/html/rfc2315#section-6.5
$ecoc = $ecac->at($ecac->count() - 1);
$cert = Certificate::fromASN1($ecoc->asSequence());
$commonNameValue = $cert->tbsCertificate()->subject()->toString();
echo $commonNameValue;

我已经为您调整好了,剩下的请您自己做。

票数 18
EN

Stack Overflow用户

发布于 2017-10-12 12:47:43

我使用过iText,发现它非常可靠,我强烈推荐它。您可以随时从PHP中调用java代码作为“微服务”。

票数 0
EN

Stack Overflow用户

发布于 2022-03-04 09:52:32

这是我在PHP7中的工作代码:

代码语言:javascript
复制
<?php


require_once('vendor/autoload.php');

use Sop\ASN1\Type\Constructed\Sequence;
use Sop\ASN1\Element;
use Sop\X509\Certificate\Certificate;  



$currentFile = "./upload/test2.pdf";


$content = file_get_contents($currentFile);


$regexp = '/ByteRange\ \[\s*(\d+) (\d+) (\d+)/'; // subexpressions are used to extract b and c

$result = [];
preg_match_all($regexp, $content, $result);

// $result[2][0] and $result[3][0] are b and c
if (isset($result[2]) && isset($result[3]) && isset($result[2][0]) && isset($result[3][0])) {
    $start = $result[2][0];
    $end = $result[3][0];
    if ($stream = fopen($currentFile, 'rb')) {
        $signature = stream_get_contents($stream, $end - $start - 2, $start + 1); // because we need to exclude < and > from start and end

        fclose($stream);
    }

    
    $binaryData = hex2bin($signature);
    
    $seq = Sequence::fromDER($binaryData);
    $signed_data = $seq->getTagged(0)->asExplicit()->asSequence();
    // ExtendedCertificatesAndCertificates: https://tools.ietf.org/html/rfc2315#section-6.6
    $ecac = $signed_data->getTagged(0)->asImplicit(Element::TYPE_SET)->asSet();
    // ExtendedCertificateOrCertificate: https://tools.ietf.org/html/rfc2315#section-6.5
    $ecoc = $ecac->at($ecac->count() - 1);
    $cert = Certificate::fromASN1($ecoc->asSequence());
    $commonNameValue = $cert->tbsCertificate()->subject()->toString();
    echo $commonNameValue;

    
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46430367

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档