2014-10-29 2 views
1

В настоящее время я пытаюсь найти this tutorial в разделе «Подписание XML-документа». До сих пор мне удалось запустить алгоритм c14n и вычислить соответствующий DigestValue.Вычисление SignatureValue от SignedInfo

Однако я не могу получить правильное значение для поля SignatureValue. В настоящее время я вычисляю значение дайджеста для тега SignedInfo, так как он соответствует расчету автора, но проблема, которую я не могу решить, заключается в том, что подписание хэша приводит к другой строке, ожидаемой.

Моего текущий сценарий выглядит следующим образом:

<?php 
$c14n = '<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> 
     <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod> 
     <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod> 
     <Reference URI=""> 
     <Transforms> 
      <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform> 
     </Transforms> 
     <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod> 
     <DigestValue>UWuYTYug10J1k5hKfonxthgrAR8=</DigestValue> 
     </Reference> 
    </SignedInfo>'; 

echo sha1($c14n).PHP_EOL.PHP_EOL; // a25a06d339d68b625cd7383a932357889956a54e OK !! 

$data = sha1($c14n); // sha1($c14n,true) wont work either 

$pkeyid = openssl_pkey_get_private("file://key.txt",'password'); // PK 

// compute signature 
openssl_sign($data, $signature, $pkeyid); 

// free the key from memory 
openssl_free_key($pkeyid); 

// Result should be: TSQUoVrQ0kg1eiltNwIhKPr ... 
echo base64_encode($signature); // Wont match! 
?> 

Я не уверен, должна ли быть подписана сырая версия или шестигранные один. В любом случае полученные значения не совпадают, поэтому должно быть что-то еще. Я использовал openssl и придумал другой результат, поэтому я очень смущен.

$ cat signedinfo.txt 
<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> 
     <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod> 
     <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod> 
     <Reference URI=""> 
     <Transforms> 
      <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform> 
     </Transforms> 
     <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod> 
     <DigestValue>UWuYTYug10J1k5hKfonxthgrAR8=</DigestValue> 
     </Reference> 
    </SignedInfo> 
$ openssl dgst -sha1 -sign key.txt -out sign-ID.bin signedinfo.txt 
$ php -r 'echo base64_encode(file_get_contents("sign-ID.bin"));' 
bFGI6KjCXtu1mAPFzvfyPkhZU5/CsYIR2IIQ0/n+6zZYqVAuIqjtgrc+xQXOQhf5RTcVR2zr/teWSSjmQvaHzFn4NhXGxvEMng1Kqg04XpQS41OLgAjaNMRW5iU4cRwFW1VMPAiHkjZggDkDgG8pSn6zdQh0yUEgo+86zJI6kbQ= 

Я был в состоянии проверить, что OpenSSL генерирует Diferent переварить, чем ожидалось (a25a06d339d68b625cd7383a932357889956a54e), если запущен из терминала. Я проверил дважды, проверил три раза и убедился, что содержимое файла точно так же, как и переменная $c14n.

Что именно я делаю неправильно?

Примечания: Я сделал проверить XML, что автор представил на this website и это, кажется, в порядке. private key used - это то же самое, что и на How-To.

ответ

0

Я использую следующие:

1) Получить .pem файл OpenSSL PKCS12 -in certificate.pfx -nocerts -out privatekey.pem -nodes Затем в PHP 2)

$certificateNode = $doc3 
     ->getElementsByTagName('X509Certificate') 
     ->item(0); 

$content = $certificateNode->C14N(FALSE, TRUE); // <-- no exclusive, with comments 

$actualDigest = base64_encode(hash('SHA1', $content, true)); 
$fp = fopen('privatekey.pem', "r"); 
$priv_key = fread($fp, 8192); 
fclose($fp); 
$passphrase = 'the pasphrase'; 
$res = openssl_get_privatekey($priv_key,$passphrase); 
openssl_private_encrypt($actualDigest, $crypttext, $res); 
$signatureValueBase64 = base64_encode($crypttext); 

Надеюсь, это поможет вам. [email protected]

+0

Хуан, спасибо за ответ. Кажется, он все еще работает. Возвращаемое значение - D8U622bvnhiEXBTfcD90 ... что неверно. Я правильно вычисляю значение дайджеста для тега SignedInfo, но не могу заставить его работать. –

+0

Преобразование строки в Base64 должно быть последним. $ actualDigest не должен быть закодирован Base64! – canolucas

1

Я знаю, что это очень старое сообщение, но я просто наткнулся на него, потому что у меня такая же проблема.

Я прошел один и тот же учебник и, насколько я понимаю, вы не должны вычислять sha1 для канонизированной строки, но вставлять ее непосредственно в команду openssl_sign. Придерживаясь вашего первого примера (php), он должен сказать:

$c14n = '<SignedInfo... </SignedInfo>'; 
// Do not use sha1 here 
//$data = sha1($c14n); // sha1($c14n,true) wont work either 

$pkeyid = openssl_pkey_get_private("file://key.txt",'password'); // PK 

// compute signature 
// openssl_sign($data, $signature, $pkeyid); // your initial command 
openssl_sign($c14n, $signature, $pkeyid, 'OPENSSL_ALGO_SHA1'); // modified version 

// free the key from memory 
openssl_free_key($pkeyid); 

// Result should be: TSQUoVrQ0kg1eiltNwIhKPr ... 
echo base64_encode($signature); // Should match now ;-)