2017-09-26 57 views
19

我有需要从数字签名“附加”PDF文件检索一些数据(签名者名称)的应用程序。如何使用PHP从PDF中检索数字签名信息?

我发现使用的iText类AcroFields方法GetSignatureNames

编辑Java和C#唯一的例子:我试过PDFTK与dump_data_fields和generate_fpdf,结果是(不幸):

/Fields [ 
<< 
/V /[email protected] 
/T (Signature1) 
>>] 

FieldType: Signature 
FieldName: Signature1 
FieldFlags: 0 
FieldJustification: Left 

临屋提前!

+2

你看过fdf函数吗? –

+0

如果解决方案@Dennis发布,不适合你然后让我知道,我想给这个问题一个镜头 –

+0

你有没有考虑添加c代码作为php的扩展? – Nitin

回答

13

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

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

其次,看完这个你就知道签名存储b和c字节根据/ BYTERANGE [ABCD]指示灯

第三,我们可以提取和B之间c从文档中提取签名本身(指导说它将是十六进制编码的PKCS7#对象)。

<?php 

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

$regexp = '#ByteRange\[(\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的

openssl pkcs7 -in signature.pkcs7 -inform DER -print_certs > info.txt 

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

请同时参阅this questionthis questionthis topic

编辑在2017年10月9日 明知劝你看到exactly this question 有,您可以调整您需要的代码。

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; 

我已经为你调整过了,但请自行完成。

+0

不幸的是,preg_match_all未能通过我的签名得到这个pdf文档:https://www.docdroid.net/oVB1AW2/ – celsowm

+1

@celsown为什么你没有费心去看看test.pdf文件的内容?你的ByteRange指标有点不同,你只需要稍微改变''regexp ='#ByteRange \ s * \ [(\ d +)(\ d +)(\ d +)#';' –

+0

新的正则表达式的工作,谢谢。现在我正在尝试使用PHPASN1来解码DER,因为显然PHP openssl不能与DER – celsowm

0

我用过iText,发现它非常可靠,我强烈推荐它。 您始终可以将PHP代码作为PHP的“微服务”调用。