Как получить информацию о цифровой подписи из PDF с помощью PHP?


У меня есть приложение, которому необходимо извлечь некоторые данные (имя подписавшего) из цифровой подписи, "прикрепленной" к файлам PDF.

Я нашел только примеры в Java и C# с использованием метода AcroFields класса iText GetSignatureNames

Редактировать: Я пробовал pdftk с помощью полей dump_data_fields и generate_fpdf, и в результате получилось (к сожалению):

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

И

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

Заранее спасибо!

Author: celsowm, 2017-09-26

2 answers

Ну, это сложно (я бы сказал, даже невозможно, но кто знает) достичь этого только с помощью PHP.

Сначала, пожалуйста, прочитайте статью о цифровой подписи в Adobe PDF

Во-вторых, после прочтения этого вы узнаете, что подпись хранится между байтами b и c в соответствии с индикатором /ByteRange[a b c d]

В-третьих, мы можем извлечь 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));
}

Далее, после третьего шага у нас есть объект PKCS#7 в файле signature.pkcs7. К сожалению, я не знаю методов извлечения информации из подписи с помощью PHP. Таким образом, вы должны иметь возможность запускать команды оболочки, чтобы использовать openssl

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

После выполнения этой команды в файле info.txt у вас будет цепочка сертификатов. Последний - это тот, который вам нужен. Вы можете увидеть структуру файла и проанализировать необходимые данные.

Пожалуйста, также обратитесь к этому вопросу, это вопрос и в этой теме

РЕДАКТИРОВАТЬ в 2017-10-09 Я сознательно посоветовал вам посмотреть именно этот вопрос Существует код, который вы можете настроить в соответствии с вашими потребностями.

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;

Я настроил его для вас, но, пожалуйста, сделайте остальное самостоятельно.

 13
Author: Denis Alimov, 2017-10-11 23:24:16

Я использовал iText и нашел его очень надежным, я настоятельно рекомендую его. вы всегда можете вызвать код java как "микросервис" из PHP.

 0
Author: Felipe Valdes, 2017-10-12 04:47:42