2017-09-26 64 views
19

Mam aplikację, która potrzebuje pobrać niektóre dane (nazwisko osoby podpisującej) z podpisu cyfrowego "załączony" na pliki PDF.Jak odzyskać informacje o podpisie cyfrowym z pliku PDF z PHP?

znalazłem tylko przykłady w Java i C# przy użyciu klasy iText AcroFields metoda GetSignatureNames

edit: Próbowałem pdftk z dump_data_fields i generate_fpdf i wynik był, że (niestety):

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

i

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

Tha NKS w Advance!

+2

Czy obejrzałeś funkcje fdf? –

+0

Jeśli rozwiązanie @Dennis opublikował, nie działa dla Ciebie, daj mi znać, a ja chciałbym dać to pytanie shot –

+0

Czy rozważałeś patrząc na dodanie kodu c jako rozszerzenie do php? – Nitin

Odpowiedz

13

Cóż, to skomplikowane (powiedziałbym, że nawet niemożliwe, ale kto wie), aby osiągnąć to tylko z PHP.

Najpierw należy przeczytać article about digital signature in Adobe PDF

drugie, po przeczytaniu tego będziesz wiedzieć, że podpis jest przechowywana pomiędzy bic bajtów według/ByteRange [abcd] Wskaźnik

Trzeciej, możemy wyodrębnić B i c z dokumentu, a następnie wyodrębnij sam podpis (przewodnik mówi, że będzie to obiekt # PKCS7 # hexagramu).

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

Dalej, po trzecim kroku mamy obiekt PKCS # 7 w pliku signature.pkcs7. Niestety, nie znam metod wyodrębniania informacji z podpisu przy pomocy PHP. Więc trzeba być w stanie uruchomić powłokę poleceń w użyciu OpenSSL

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

Po uruchomieniu tej komendy w pliku info.txt będziesz miał łańcuch certyfikatów. Ostatni to ten, którego potrzebujesz. Możesz zobaczyć strukturę pliku i przeanalizować potrzebne dane.

Proszę zapoznać się również z this question, this question i this topic

EDIT na 09.10.2017 ja świadomie zaleca cię zobaczyć exactly this question Jest to kod, który można dostosować do swoich potrzeb.

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; 

Dostosowałem to dla Ciebie, ale proszę, odpocznij sam.

+0

Niestety nie udaje się preg_match_all do tego pdf z moim podpisem: https://www.docdroid.net/oVB1AW2/ – celsowm

+1

@celsown Dlaczego nie zadał sobie trudu, aby spojrzeć na zawartość pliku test.pdf? Twój wskaźnik ByteRange jest nieco inny, po prostu trzeba trochę zmienić '$ regexp = '#ByteRange \ s * \ [(\ d +) (\ d +) (\ d +) #';' –

+0

nowe wyrażenie działa, dziękuję. Teraz próbuję użyć PHPASN1 do dekodowania DER, ponieważ najwyraźniej PHP openssl nie działa z DER – celsowm

0

Użyłem iText i stwierdziłem, że jest bardzo niezawodny, bardzo polecam. zawsze można wywołać kod Java jako "mikroserwis" z PHP.