简体   繁体   中英

How to retrieve digital signature information from PDF with PHP?

I have app that needs to retrieve some data (signer name) from digital signature "attached" on PDF files.

I have found only examples in Java and C# using the iText class AcroFields method GetSignatureNames

edit: I've tried pdftk with dump_data_fields and generate_fpdf and the result was that (unfortunately):

/Fields [
<<
/V /dftk.com.lowagie.text.pdf.PdfDictionary@3048918
/T (Signature1)
>>]

and

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

Thanks in Advance !

Well, it's complicated (I would say even impossible, but who knows) to achieve this only with PHP.

At first, please read article about digital signature in Adobe PDF

Second, after reading this you will know that signature is stored between b and c bytes according to /ByteRange[abcd] indicator

Third, we can extract b and c from document and then extract signature itself (guide says it will be hexdecoded PKCS7# object).

<?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));
}

Forth, after third step we have PKCS#7 object in file signature.pkcs7. Unfortunately, I don't know methods to extract information from signature using PHP. So you must be able to run shell commands to use openssl

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

After running this command in file info.txt you will have a chain of certificates. Last one is the one you need. You can see the structure of the file and parse needed data.

Please also refer to this question , this question and this topic

EDIT at 2017-10-09 I knowingly advised you to see exactly this question There is a code that you can adjust to your needs.

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;

I've adjusted it for you, but please make the rest by yourself.

I've used iText and found it to be very reliable, I highly recommend it. you can always call the java code as a "microservice" from PHP.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM