在 PHP 中使用 "openssl_pkcs7_decrypt" 时出错 "BIO_new_file:no such file"

Error "BIO_new_file:no such file" by using "openssl_pkcs7_decrypt" in PHP

感谢 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

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

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

尝试将 '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'

终于,我找到了解决这个问题的方法。首先,文件路径错误。我已经按照 Giovani 的建议解决了这个问题。对于我的第二个错误,由于我的 OPENSSL 命令,我刚刚在 base 64 中编码了我的“.P7M”,并且我添加了一个 header:

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":

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

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

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