2014-10-29 25 views
1

我目前正在嘗試關注「簽署XML文檔」上的this tutorial。到目前爲止,我已經能夠運行c14n算法並計算出合適的DigestValue從SignedInfo計算SignatureValue

但是,我似乎無法獲得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變量完全相同。

我究竟做錯了什麼?

注: 我做了檢查,作者提供了this website的XML,它似乎是好的。 private key used與How-To上的相同。

回答

0

我使用了以下內容:

1)獲取的.pem文件OpenSSL的PKCS12 -in certificate.pfx -nocerts退房手續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標記的摘要值,但無法使簽名步驟正常工作。 – 2014-10-30 10:56:01

+0

將字符串轉換爲Base64應該是最後一步。 $ actualDigest不應該是Base64編碼! – canolucas 2014-12-16 14:48:47

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