簡體   English   中英

.crx文件中的CRX_ZREO_SIGNTURE_LENGTH失敗

[英]CRX_ZREO_SIGNTURE_LENGTH failure in .crx file

我發現這篇文章用PHP創建Google Chrome Crx文件,用我的ZIP存檔創建.crx文件。 但是當我嘗試運行它時,我得到一個$ signtrue = 0的長度,我沒弄明白為什么...我的.pem文件在找到並且有效,以及我的.pub密鑰文件但是它仍然返回給我signture中的零長度......

$fp = fopen("/public_html/apps/chrome/nsii.pem", "r");
$priv_key = fread($fp, filesize($fp));
fclose($fp);

$pkeyid = openssl_get_privatekey($priv_key);
openssl_sign(file_get_contents("$name.zip"), $signature, $pkeyid, 'sha1');
openssl_free_key($pk);

# decode the public key

$key = base64_decode(file_get_contents('extension_public_key.pub'));

$fh = fopen("$name.crx", 'wb');
fwrite($fh, 'Cr24');             // extension file magic number
fwrite($fh, pack('V', 2));       // crx format version
fwrite($fh, pack('V', strlen($key)));            // public key length
fwrite($fh, pack('V', strlen($signature)));      // signature length
fwrite($fh, $key);               // public key
fwrite($fh, $signature);         // signature
fwrite($fh, file_get_contents("$name.zip")); // package contents, zipped
fclose($fh);

更新:

orignial代碼如下:

<?php
# make a SHA1 signature using our private key
$pk = openssl_pkey_get_private(file_get_contents('/public_html/apps/chrome/nsii.pem'));
openssl_sign(file_get_contents('/public_html/apps/chrome/extGoogle.zip'), $signature, $pk, 'sha1');
openssl_free_key($pk);

# decode the public key
$key = base64_decode(file_get_contents('/public_html/apps/chrome/extension_public_key.pub'));

# .crx package format:
#
#   magic number               char(4)
#   crx format ver             byte(4)
#   pub key lenth              byte(4)
#   signature length           byte(4)
#   public key                 string
#   signature                  string
#   package contents, zipped   string
#
# see http://code.google.com/chrome/extensions/crx.html
#
$fh = fopen('extension.crx', 'wb');
fwrite($fh, 'Cr24');                             // extension file magic number
fwrite($fh, pack('V', 2));                       // crx format version
fwrite($fh, pack('V', strlen($key)));            // public key length
fwrite($fh, pack('V', strlen($signature)));      // signature length
fwrite($fh, $key);                               // public key
fwrite($fh, $signature);                         // signature
fwrite($fh, file_get_contents('/public_html/apps/chrome/extGoogle.zip')); // package contents, zipped
fclose($fh);

似乎不起作用......問題是為什么?...如果我使用CLI編譯它,一切正常......

你的問題原樣並沒有留下任何完全出錯的跡象。

但是我可以看到沒有太多的錯誤檢查。 我建議 - 因為編寫良好的代碼很常見 - 你首先要為返回值添加一些測試。 此外,您可能需要啟用錯誤報告並跟蹤錯誤日志以查看某些問題。

讓我們稍微檢查一下代碼並添加注釋。 它只是一些指針並不完整。 從這三行開始:

$fp = fopen("/public_html/apps/chrome/nsii.pem", "r");
$priv_key = fread($fp, filesize($fp));
fclose($fp);

你已經知道了(至少你以后再使用它),有一個方便的函數file_get_contents 它可以替換這三行,我添加了更多行來使代碼更多說話:

$privateKeyPemFile = "/public_html/apps/chrome/nsii.pem";
$privateKey = file_get_contents($privateKeyPemFile);
if (false === $privateKey) {
    throw new UnexpectedValueException(
        sprintf("Unable to read private key file %s", $privateKeyPemFile)
    );
}

在使用file_get_contents旁邊,這實際上是驗證打開文件是否成功運行。 如果沒有,則拋出UnexpectedValueException ,並顯示錯誤消息,告知發生了什么。 異常的名稱並不重要,你可以為初學者拋出Exception並繼續。

在這里拋出異常實際上會告訴消息,以防這種情況失敗。

如您所見,您需要驗證函數的返回值並檢查錯誤條件。 請參閱手冊中使用的PHP函數,並查看記錄的返回值及其含義。 通常會出現錯誤情況,例如file_get_contents

然后你特別關注零長度$signature 讓我們看看,對於每個函數,我們是否可以檢查返回值並獲取一些錯誤信息:

$keyResource = openssl_pkey_get_private($privateKey);

openssl_get_privatekey實際上是一個別名openssl_pkey_get_private ,所以這已經改變了這里。 此外,我重命名了變量名稱,因此更多地說,我們有足夠的空間,不需要復雜的縮寫。

我們再次在這里有一個返回值,如果出現錯誤則返回false 在非錯誤條件下,它是一個關鍵資源,因此我相應地命名了返回值。 讓我們再次添加錯誤檢查:

if (false === $keyResource) {
    throw new UnexpectedValueException("Unable to parse and prepare private key");
}

所以到下一行,首先不變:

openssl_sign(file_get_contents("$name.zip"), $signature, $pkeyid, 'sha1');

顯然,沒有對zip文件的file_get_contents進行錯誤檢查。 相反,我們需要更多代碼來保證安全:

$zipFile     = "$name.zip";
$zipContents = file_get_contents($zipFile);
if (false === $zipContents) { 
    throw new ... 
}

由於這僅用於加載數據,因此需要采用openssl_sign調用:

$signatureAlgorithm = OPENSSL_ALGO_SHA1;
$result = openssl_sign($zipContents, $signature, $keyResource, $signatureAlgorithm);
if (!$result) {
    throw new ...
}

也許第一個區別是你使用了字符串'SHA1'而手冊告訴我正在使用常量。 也許它具有相同的值,我不能告訴你,我在這里使用了記錄的常量(可能不是文檔總是正確的,但是如果你不知道發生了什么,我首先建議遵循docs然后看)。

同樣,正在檢查函數的返回值以查找錯誤情況。 假設您的代碼可能在該函數中失敗,我們只會知道它失敗了,而不是出了什么問題。

PHP手冊顯示有一個名為openssl_error_string的函數可以返回(peu-a-peu)錯誤字符串。 因為它一個接一個地返回,所以你需要循環來獲取所有(最近的第一個),這可以通過一個常見的for循環來完成:

for ($buffer = ''; $string = openssl_error_string(); $buffer .= $string, "\n");

所以我們可以將其添加到異常中。 將這個內置到某種功能中也可能是有用的,做你需要的。

if (!$result) {
    $buffer = sprintf(
        "Failed to sign zip contents (%d); Openssl error(s):\n", strlen($zipContents)
    );
    for (; $string = openssl_error_string(); $buffer .= $string, "\n");
    throw new UnexpectedValueException($buffer);
}

因此,您的代碼是檢查錯誤條件的地方的一個完美示例,並顯示不同的函數/庫有不同的方式來表示失敗以及如何獲取有關錯誤的信息。

如果以安全的方式編寫代碼,它具有所有前置和后置條件檢查,這意味着您不僅要檢查返回值,還要在使用它們之前檢查值。 一個例子是zipfile的文件名。 檢查文件是否存在且在打開之前是否可讀:

$zipFile = "$name.zip";
if (!is_readable($zipFile)) {
    throw new Exception(sprintf("Zipfile is not readable %s", $zipFile));
}
$zipContents = file_get_contents($zipFile);
...

這只是一個失敗的設計示例(在這種情況下,它可能會略高於頂部,因為file_get_contents也會通知我們,以防我們無法讀取文件,但有時這些前置條件檢查更有價值。

到目前為止的代碼一次審查,將參數變量移到頂部:

$privateKeyPemFile  = "/public_html/apps/chrome/nsii.pem";
$zipFile            = "$name.zip";
$signatureAlgorithm = OPENSSL_ALGO_SHA1;

$privateKey = file_get_contents($privateKeyPemFile);
if (false === $privateKey) {
    throw new UnexpectedValueException(
        sprintf("Unable to read private key file %s", $privateKeyPemFile)
    );
}

$keyResource = openssl_pkey_get_private($privateKey);
if (false === $keyResource) {
    $buffer = sprintf(
        "Unable to parse and prepare private key (%d) %s; Openssl error(s):\n"
        , strlen($privateKey), $privateKeyPemFile
    );
    for (; $string = openssl_error_string(); $buffer .= $string, "\n") ;
    throw new UnexpectedValueException($buffer);
}

if (!is_readable($zipFile)) {
    throw new Exception(sprintf("Zipfile is not readable %s", $zipFile));
}
$zipContents = file_get_contents($zipFile);
if (false === $zipContents) {
    throw new UnexpectedValueException(
        sprintf("Failed to open zipfile %s", $zipFile)
    );
}

$result = openssl_sign($zipContents, $signature, $keyResource, $signatureAlgorithm);
if (!$result) {
    $buffer = sprintf(
        "Failed to sign zip contents (%d); Openssl error(s):\n"
        , strlen($zipContents)
    );
    for (; $string = openssl_error_string(); $buffer .= $string, "\n") ;
    throw new UnexpectedValueException($buffer);
}

將變量置於頂部允許您預先查看以下代碼的輸入參數,並為您提供更好的概述。

檢查處理中的返回值可以讓您最早發現問題。

讀出openssll錯誤將為您提供有用的信息來解決問題。

您可以在PHP手冊中找到幾乎所有相關信息。 這個答案可能無法解決您的具體問題,但應該為您提供所需的工具,以便更好地解決問題本身以及您可能遇到的代碼問題。

它只會花費你一些代碼,但你的代碼會更好。 想象一下,您將腳本復制到新服務器上,可能會有不同之處,您不想盲目飛行。

快樂的調試。 如您所見,我只覆蓋了代碼的前半部分,您應該知道我沒有運行您的代碼。 所以這個例子是以最好的意圖完成的,但是不能保證它能夠立即為你的場景工作。 但我認為我想展示的是顯而易見的。 如果對代碼的其余部分應用類似的檢查,您應該能夠了解究竟出了什么問題,這是解決方案的一半。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM