在 PHP 中使用“openssl_pkcs7_decrypt”出现错误“BIO_new_file:no such file”

Posted

技术标签:

【中文标题】在 PHP 中使用“openssl_pkcs7_decrypt”出现错误“BIO_new_file:no such file”【英文标题】:Error "BIO_new_file:no such file" by using "openssl_pkcs7_decrypt" in PHP 【发布时间】:2015-03-15 08:09:11 【问题描述】:

感谢 OpenSSL,我使用以下命令加密了一个文件:

openssl smime -encrypt -in myfile.xml -out myfile.p7m -outform DER -binary publicKey.pem

现在,我将使用 php 解密文件“myfile.p7m”。目前,我正在使用此代码但没有成功:

$output = "myfile.xml";
$crt = file_get_contents("mycert.crt");
$private = openssl_pkey_get_private (file_get_contents("privateKey.pem"), "password");
openssl_pkcs7_decrypt ("myfile.p7m", $output, $crt, $private);
while($error = openssl_error_string())
    echo $error.'<br />'.PHP_EOL;

此时,我收到此错误:

error:2006D080:BIO routines:BIO_new_file:no such file

我不知道这是什么意思。

你能帮帮我吗?

PS: 我已经使用 OpenSSL 命令成功解密了这个文件:

openssl smime -decrypt -in myfile.p7m -out myfile.xml -inkey 
privateKey.pem -inform DER -passin pass:password

编辑:

听从 Vladimir Kunschikov 的建议,我使用了文件的完整路径。我已将“myfile.xml”替换为“file://c:/wamp/www/test/myfile.xml”和“myfile.p7m” ”通过“file://c:/wamp/www/test/myfile.p7m”。现在,我还有两个错误:

error:0200107B:system library:fopen:Unknown error
error:2006D002:BIO routines:BIO_new_file:system lib

编辑 2

感谢乔瓦尼的回复。我按照您的指示替换所有路径。现在,出现了一个新的错误!

error:0D0D20CC:asn1 encoding routines:SMIME_read_ASN1:no content type

【问题讨论】:

您应该使用文件名的完整路径并检查 www-data(或 apache?)用户的访问权限。 OpenSSL and error in reading openssl.conf file 的可能重复项。 【参考方案1】:

尝试将 'file://c:/wamp/www/test/myfile.xml' 替换为 'c:\\wamp\\www\\test\\myfile.xml' 和 'file://c :/wamp/www/test/myfile.p7m' 与 'c:\\wamp\\www\\test\\myfile.p7m'

【讨论】:

【参考方案2】:

最后,我找到了解决这个问题的方法。首先,文件路径错误。我按照乔瓦尼的建议解决了这个问题。对于我的第二个错误,我刚刚在 base 64 中编码了由于我的 OPENSSL 命令而获得的“.P7M”,并且我添加了一个标头:

MIME-Version: 1.0
Content-Disposition: attachment; filename="smime.p7m"
Content-Type: application/x-pkcs7-mime; smime-type=enveloped-data; name="smime.p7m"
Content-Transfer-Encoding: base64

MIIJWAYJKoZIhvcNAQcDoIIJSTCCCUUCAQAxggGnMIIBowIBADCBijB9MQswCQYD
VQQGEwJGUjEVMBMGA1UECAwMUmhvbmVzLUFscGVzMQ0wCwYDVQQHDARMeW9uMQ0w
CwYDVQQKDARZcG9rMQwwCgYDVQQLDANQVmUxDTALBgNVBAMMBFlQVmUxHDAaBgkq
hkiG9w0BCQEWDXlwb2tAeXBvay5jb20CCQCCV/J9OpZ9pjANBgkqhkiG9w0BAQEF
...

这样,我就可以正确解密P7M文件了。

所以,我注意到通过在我的 OPENSSL 命令中删除选项“-outform DER”,我得到了一个可以使用“openssl_pksc7_decrypt 解密的文件” em>":

openssl smime -encrypt -in myfile.xml -out myfile.p7m -binary publicKey.pem

【讨论】:

【参考方案3】:

我使用 Yandex Money 签署信以获取收银员余额的工作代码示例。 从代码中提取的片段,因为请不要严厉批评

(OpenSSL подпись письма на получения баланса по кассе Яндекс Деньги)

 private function _make_message($data)

    $tmp_file_msg_raw  = realpath(tempnam('C:\Temp', 'ymr_'));
    $tmp_file_msg_sign = realpath(tempnam('C:\Temp', 'yms_'));
    $EOL     = "\r\n";                // ограничитель строк, некоторые почтовые сервера требуют \n - подобрать опытным путём
    $EOL2    = "\n\n";
    $boundary = md5(uniqid(time()));  // любая строка, которой не будет ниже в потоке данных.

    $fd = fopen($tmp_file_msg_raw, 'w');

    if(!$fd) 
        $error = "Could not open temporary file $tmp_file_msg_raw.";
        return array("status" => false, "error_msg" => $error, "error_no" => 0);
    

    fwrite($fd, $data);
    fclose($fd);

    if(!@openssl_pkcs7_sign(
        $tmp_file_msg_raw,
        $tmp_file_msg_sign,
        'file://' . $this->_deposit_crt_sign,
        ['file://' . $this->_deposit_key, $this->_config['secret_keyword']],
        [],
        PKCS7_BINARY))
    
        unlink($tmp_file_msg_raw);
        unlink($tmp_file_msg_sign);
        $error = "Could not sign data: ".openssl_error_string();

        return FALSE;
    

    $signed_data       = file_get_contents($tmp_file_msg_sign);
    $signed_data_array = explode($EOL2, $signed_data);
    $signed_data       = $signed_data_array[1];
    $signed_data = "-----BEGIN PKCS7-----\n" . $signed_data . "\n-----END PKCS7-----";

    $multipart  = '--' . $boundary . $EOL;
    $multipart .= 'Content-Disposition: form-data; name=smime; filename=smime.p7m' . $EOL;
    $multipart .= 'Content-Type: application/pkcs7-mime' . $EOL;
    $multipart .= $EOL; // раздел между заголовками и телом html-части
    $multipart .= $signed_data;
    $multipart .= $EOL . '--' . $boundary . '--' . $EOL;

    unlink($tmp_file_msg_raw);
    unlink($tmp_file_msg_sign);

    return [
        'headers' => [
            'MIME-Version: 1.0',
            "Content-Type: multipart/form-data; boundary=\"$boundary\"",
        ],
        'body' => $multipart
    ];




private function _read_message($data)

    $EOL = "\r\n";
    $pkcs7_headers  = 'MIME-Version: 1.0' . $EOL;
    $pkcs7_headers .= 'Content-Disposition: attachment' . $EOL;
    $pkcs7_headers .= 'Content-Type: application/x-pkcs7-mime' . $EOL;
    $pkcs7_headers .= 'Content-Transfer-Encoding: base64' . $EOL;
    $pkcs7_headers .= $EOL;

    $pkcs7_message = $pkcs7_headers . $data;

    $file_pkcs7_msg          = realpath(tempnam('C:\Temp', 'ymm'));
    $file_pkcs7_outfilename  = realpath(tempnam('C:\Temp', 'ymo_'));
    $file_pkcs7_content      = realpath(tempnam('C:\Temp', 'ymc_'));

    $fd_message_response = fopen($file_pkcs7_msg, 'a');

    if(!$fd_message_response) 
        $error = "Could not open temporary file $file_pkcs7_msg.";
        return array("status" => false, "error_msg" => $error, "error_no" => 0);
    

    fwrite($fd_message_response, $pkcs7_message);
    fclose($fd_message_response);

    if (!@openssl_pkcs7_verify(
        $file_pkcs7_msg,
        PKCS7_BINARY,
        $file_pkcs7_outfilename,
        [$this->_deposit_crt_verify],
        $this->_deposit_crt_verify,
        $file_pkcs7_content))
    
        // TODO

    ;

    $data = file_get_contents($file_pkcs7_content);

    unlink($file_pkcs7_msg);
    unlink($file_pkcs7_outfilename);
    unlink($file_pkcs7_content);

    //while ($msg = openssl_error_string()) echo $msg . "<br />\n";

    return $data;



    $data = '<?xml version="1.0" encoding="UTF-8"?><balanceRequest agentId="123456" clientOrderId="1" requestDT="2015-02-17T16:21:22+04:00"/>';
    $data = $this->_make_message($data);

    $url = $this->_config['uri_api_deposition'].'webservice/deposition/api/balance';
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $data['headers']);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data['body']);
    curl_setopt($ch, CURLOPT_VERBOSE, false);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Ymoney CollectMoney');
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_SSLCERT, $this->_ssl_crt);
    curl_setopt($ch, CURLOPT_SSLKEY, $this->_ssl_key);
    curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $this->_config['secret_keyword']);
    curl_setopt($ch, CURLOPT_FORBID_REUSE, TRUE);
    curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE);
    $response = curl_exec($ch);
    //var_dump($response);
    curl_close($ch);

    $msg = $this->_read_message($response);
    var_dump($msg);

【讨论】:

以上是关于在 PHP 中使用“openssl_pkcs7_decrypt”出现错误“BIO_new_file:no such file”的主要内容,如果未能解决你的问题,请参考以下文章

在 php 中使用“全局”

php [php:在Heredoc中使用DEFINE]注意旧代码。 #PHP

为啥在 PHP 中使用 ORM?

php 在PHP中使用平面数组构建树

如何将js的变量在php中使用

在 PHP 中使用 Pygments(PHP 中的 Python)