2017-09-26 85 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的「微服務」調用。