一开始,请阅读关于AdobePDF中的数字签名的文章
其次,读完这个之后,你会知道签名被存储在b和c字节之间,根据/ ByteRange [a b c d]指示器
第三,我们可以从文档中提取b和c,然后提取签名本身(指导说它将是十六进制编码的PKCS7#对象)。$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中运行此命令后,您将拥有一个证书链。 最后一个是你需要的。 你可以看到文件的结构并解析所需的数据。
有一个代码可以根据需要进行调整。use ASN1TypeConstructedSequence;
use ASN1Element;
use X509CertificateCertificate;
$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;