OpenSSL在Windows上无法工作,错误代码分别为0x02001003、0x2006D080和0x0E064002。

52

问题:在我的Windows环境中,OpenSSL无法正常工作。OpenSSL一直报告0x02001003、0x2006D080和0x0E064002错误。

环境:

Windows NT x 6.1 build 7601 (Windows 7 Business Edition Service Pack 1) i586
Apache/2.4.4 (Win32)
PHP/5.4.13 x86
PHP Directory: E:\wamp\php\
Virtual Host Directory: E:\Projects\1\public_html

我尝试过的:

  • 安装说明 http://www.php.net/manual/en/openssl.installation.php
  • PHP.ini extension=php_openssl.dll
  • Openssl.cnf E:\wamp\php\extras\openssl.cnf
  • %PATH% E:\wamp\php
  • 重新启动电脑
  • phpinfo:
    ----OpenSSL支持已启用
    ----OpenSSL库版本 OpenSSL 1.0.1e 11 Feb 2013
    ----OpenSSL头文件版本 OpenSSL 0.9.8y 5 Feb 2013
  • configargs中指定和不指定config
  • 在apache配置中指定和不指定<Directory E:\wamp\php\extras>
  • openssl.cnf复制到虚拟主机public_html,指向它并仍然得到相同的错误
  • 错误日志中没有记录任何内容
  • 研究:我花了最近两天时间研究这个问题,很惊讶竟然没有更多的信息,所以我在这里发布。似乎是OpenSSL配置或apache/php未正确读取配置的问题。

代码:

$privateKey = openssl_pkey_new();
while($message = openssl_error_string()){
    echo $message.'<br />'.PHP_EOL;
}

结果:

error:02001003:system library:fopen:No such process
error:2006D080:BIO routines:BIO_new_file:no such file
error:0E064002:configuration file routines:CONF_load:system lib
error:02001003:system library:fopen:No such process
error:2006D080:BIO routines:BIO_new_file:no such file
error:0E064002:configuration file routines:CONF_load:system lib

手动安装 OpenSSL:

E:\wamp\apache\bin>openssl.exe pkey
WARNING: can't open config file: c:/openssl-1.0.1e/ssl/openssl.cnf

E:\wamp\apache\bin>set OPENSSL_CONF="E:\wamp\php\extras\openssl.cnf"

E:\wamp\apache\bin>openssl.exe pkey
3484:error:0200107B:system library:fopen:Unknown error:.\crypto\bio\bss_file.c:169:fopen('"E:\wamp\php\extras\openssl.cnf"','rb')
3484:error:2006D002:BIO routines:BIO_new_file:system lib:.\crypto\bio\bss_file.c:174:
3484:error:0E078002:configuration file routines:DEF_LOAD:system lib:.\crypto\conf\conf_def.c:199:

编辑:

  1. 感谢@Gordon,我现在可以使用openssl_error_string查看open_ssl错误。
  2. 彻底卸载EasyPHP。手动安装稳定版本的PHP / Apache。相同的结果!绝对是我在Windows上实现openssl时做错了什么。
  3. OpenSSL手动部分...其他错误信息。

最后的想法:
我设置了一个Linux箱,我得到了相同的错误。经过一些试验,我发现即使它在openssl_pkey_new处抛出错误,它最终也会创建我的测试p12文件。长话短说,这些错误是误导的,它更多地涉及您如何使用openssl函数,而不是服务器端配置。

最终代码:

// Create the keypair
$res=openssl_pkey_new();

// Get private key
openssl_pkey_export($res, $privkey);

// Get public key
$pubkey=openssl_pkey_get_details($res);
$pubkey=$pubkey["key"];

// Actual file
$Private_Key = null;
$Unsigned_Cert = openssl_csr_new($Info,$Private_Key,$Configs);
$Signed_Cert = openssl_csr_sign($Unsigned_Cert,null,$Private_Key,365,$Configs);
openssl_pkcs12_export_to_file($Signed_Cert,"test.p12",$Private_Key,"123456");

关闭。

一年后...

一年后,我又发现自己在做同样的事情。无论我在计算机或脚本执行期间设置了什么PATH变量,它都会出现文件找不到的错误。我通过在openssl_pkey_new中的config_args数组中传递config参数来解决了这个问题。下面是一个测试成功使用OpenSSL的函数:

    /**
     * Tests the ability to 1) create pub/priv key pair 2) extract pub/priv keys 3) encrypt plaintext using keys 4) decrypt using keys
     * 
     * @return boolean|string False if fails, string if success
     */
    function testOpenSSL($opensslConfigPath = NULL)
    {
        if ($opensslConfigPath == NULL)
        {
            $opensslConfigPath = "E:/Services/Apache/httpd-2.4.9-win32-VC11/conf/openssl.cnf";
        }
        $config = array(
            "config" => $opensslConfigPath,
            "digest_alg" => "sha512",
            "private_key_bits" => 4096,
            "private_key_type" => OPENSSL_KEYTYPE_RSA,
        );

        $res = openssl_pkey_new($config); // <-- CONFIG ARRAY
        if (empty($res)) {return false;}

        // Extract the private key from $res to $privKey
        openssl_pkey_export($res, $privKey, NULL, $config); // <-- CONFIG ARRAY

        // Extract the public key from $res to $pubKey
        $pubKey = openssl_pkey_get_details($res);
        if ($pubKey === FALSE){return false;}

        $pubKey = $pubKey["key"];

        $data = 'plaintext data goes here';

        // Encrypt the data to $encrypted using the public key
        $res = openssl_public_encrypt($data, $encrypted, $pubKey);
        if ($res === FALSE){return false;}

        // Decrypt the data using the private key and store the results in $decrypted
        $res = openssl_private_decrypt($encrypted, $decrypted, $privKey);
        if ($res === FALSE){return false;}

        return $decrypted;
    }

    // Example usage:
    $res = testOpenSSL();
    if ($res === FALSE)
    {
        echo "<span style='background-color: red;'>Fail</span>";
    } else {
        echo "<span style='background-color: green;'>Pass: ".$res."</span>";
    }

7
@Populus“更换操作系统”并不是一个现实世界的解决方案。 - Brock Hensley
但是你可以轻松地创建一个虚拟环境。任何想在 Windows 上使用 Apache 进行生产的人都应该重新考虑他们的计划 :x 所以我只能假设这是为了测试环境。 - Populus
3
这是一个开发环境。虽然生产环境将在Linux上运行,但不幸的是,这是我目前所困在的开发环境。尽管我同意你的观点,但我也想找到答案,因为我知道在Windows上可以实现该功能。 - Brock Hensley
回到问题本身...当我手动运行openssl.exe时,我看到它在./crypto上出现错误,但是我在apache\bin中没有看到./crypto文件夹,而这里是openssl.exe所在的位置.... 未知错误:.\crypto\bio\bss_file.c:169:fopen - Brock Hensley
Windows 上默认的 OpenSSL 配置通常没有意义。它们会指向 Linux 和 Unix 的 /usr/local/ssl,或者像 Z:\OpenSSL 这样的驱动器。甚至可能是一些 Cygwin 的路径,比如 /c/windows/system。这些构建中有各种疯狂的配置硬编码进去了。使用 ProcMon 来确定错误的路径。 - jww
显示剩余6条评论
10个回答

10

以下代码按预期工作。但是,如果在openssl方法之后运行openssl_error_string(),则会显示error:0E06D06C:configuration file routines:NCONF_get_string:no value,这是我无法找到文档的一些注意事项。

另请注意,根据http://www.php.net/manual/en/function.openssl-error-string.php的说明,您可能会看到误导性的错误,因为错误消息被排队:

  

使用此函数检查错误时要小心,因为它似乎从一个错误缓冲区中读取错误,其中可能包括正在使用openssl函数的另一个脚本或进程的错误。(我很惊讶地发现它在调用任何openssl_*函数之前就返回错误消息)

<?php
/* Create the private and public key */
$res = openssl_pkey_new();
openssl_error_string(); // May throw error even though its working fine!

/* Extract the private key from $res to $privKey */
openssl_pkey_export($res, $privKey);
openssl_error_string(); // May throw error even though its working fine!

/* Extract the public key from $res to $pubKey */
$pubKey = openssl_pkey_get_details($res);
$pubKey = $pubKey["key"];

$data = 'i.amniels.com is a great website!';

/* Encrypt the data using the public key
 * The encrypted data is stored in $encrypted */
openssl_public_encrypt($data, $encrypted, $pubKey);

/* Decrypt the data using the private key and store the
 * result in $decrypted. */
openssl_private_decrypt($encrypted, $decrypted, $privKey);

echo $decrypted;
?>

5

以下是需要注意的几个事项:

%PATH% 中还应包含 windows 和 system32,所以您的 %PATH% 应如下所示:c:\windows;c:\windows\system32;E:\wamp\php,而在 e:\wamp\php 中应该有 OpenSSL DLL 文件。

同时,尝试使用与头文件版本匹配的 OpenSSL 版本 0.9.8y 5 Feb 2013,可以在此处下载 32 位版本此处下载 64 位版本

下面是适用于我的代码:

// Create the keypair
$res=openssl_pkey_new();

// Get private key
openssl_pkey_export($res, $privkey);

// Get public key
$pubkey=openssl_pkey_get_details($res);
$pubkey=$pubkey["key"];
$Info = array(
    "countryName" => "UK",
    "stateOrProvinceName" => "Somerset",
    "localityName" => "Glastonbury",
    "organizationName" => "The Brain Room Limited",
    "organizationalUnitName" => "PHP Documentation Team",
    "commonName" => "Wez Furlong",
    "emailAddress" => "wez@example.com"
);

// Actual file
$Private_Key = null;
$Unsigned_Cert = openssl_csr_new($Info,$Private_Key);
$Signed_Cert = openssl_csr_sign($Unsigned_Cert,null,$Private_Key,365);
openssl_pkcs12_export_to_file($Signed_Cert,"test.p12",$Private_Key,"123456");

4

我曾经遇到过类似的问题,对我来说,在我的脚本开头手动设置环境变量 'OPENSSL_CONF' 对我有所帮助。

不知何故,环境变量没有被正确设置,或者没有传递给我的php(设置:AMPPS,Win7 64位)。

下面使用的示例位置是标准AMPPS安装所必须使用的路径,因此,如果您正在使用AMPPS,请复制并粘贴:

putenv("OPENSSL_CONF=C:\Program Files (x86)\Ampps\php\extras\openssl.cnf");

2
这对我没有用,但在config_args数组中指定openssl.cnf路径确实有效。 - Brock Hensley

3
如果您正在使用Apache 2.4 + mod_fcgid,则可以通过在httpd.conf文件中添加来指定OpenSSL配置文件:
# OPENSSL CONF
FcgidInitialEnv OPENSSL_CONF "D:/apps/php70/extras/ssl/openssl.cnf"

我没有使用预配置的软件包,如WAMP。我从Apache Lounge获取了Apache,从windows.php.net获取了PHP,并进行了自己的配置。


2

简单的解决方法:

  1. 从此处下载PHP Windows二进制文件的归档文件(不要紧哪个):http://windows.php.net/download
  2. 您会在其中找到/extras/ssl/openssl.cnf文件
  3. 将openssl.cnf提取到某个位置(例如“C:/WEB/PHP/extras/ssl/openssl.cnf”)
  4. 添加全局系统变量OPENSSL_CONF,并附上您使用的路径(例如“C:\WEB\PHP\extras\openssl.cnf”(不带双引号))。

enter image description here

您必须向OPENSSL_CONF系统变量中添加路径。将其添加到Path系统变量不足以解决问题! 在Windows 7下,您可以在以下位置找到设置对话框:“控制面板>系统和安全>系统>高级系统设置(左侧菜单)>高级(选项卡)>环境变量...”。 在那里添加变量OPENSSL_CONF

在使用之前不需要准备openssl.cnf文件-它可以直接使用。 但是,如果您想微调设置,则可以这样做。


1

您是否通过这种方法安装了OpenSSL? 在Windows上安装OpenSSL

  1. 前往http://gnuwin32.sourceforge.net/packages/openssl.htm,下载“二进制文件”的“设置”版本openssl-0.9.7c-bin.exe。

  2. 双击openssl-0.9.7c-bin.exe将OpenSSL安装到\local\gnuwin32目录。

  3. 返回相同的页面,下载“文档”的“设置”版本,并将其安装到同一目录中。

  4. 打开命令行窗口,尝试以下命令: 代码:

    \local\gnuwin32\bin\openssl -help
    openssl:Error: '-help' is an invalid command.

    Standard commands
    asn1parse      ca             ciphers        crl            crl2pkcs7
    dgst           dh             dhparam        dsa            dsaparam
    enc            engine         errstr         gendh          gendsa
    genrsa         nseq           ocsp           passwd         pkcs12
    pkcs7          pkcs8          rand           req            rsa
    rsautl         s_client       s_server       s_time         sess_id
    smime          speed          spkac          verify         version
    x509
    ......

如果您看到OpenSSL打印的命令列表,就说明您的安装已经正确完成。

请注意,链接的网站有旧版本的二进制文件!请前往此处获取最新且最安全的版本:http://slproweb.com/products/Win32OpenSSL.html - Icode4food

0
在我的情况下,将文件复制到c:\windows\system32有所帮助。

libeay32.dll, ssleay32.dll

可以在OpenSSL_INSTALL_PATH\bin目录中找到它们。

0
我曾经遇到过与XAMPP相关的类似问题。我发现在[xampp_dir]\apache\conf\extra\httpd-xampp.conf中的OPENSSL_CONF设置不正确,应该改为[xampp_dir]/apache/conf/openssl.cnf。修改后问题得以解决。

0
<?php 

         // also see  stackoverflow.com/questions/59195251/php-get-private-key-from-a-single-line-private-key 
         // micmap.org/php-by-example/de/function/openssl_get_publickey
         // best  stackoverflow.com/questions/15558321/openssl-not-working-on-windows-errors-0x02001003-0x2006d080-0x0e064002
         // sandrocirulli.net/how-to-encrypt-and-decrypt-emails-and-files/



         echo '<pre>';


        function testOpenSSL($openssl_args)
        {

                $res = openssl_pkey_new($openssl_args); // <-- CONFIG ARRAY
                openssl_error_string(); // May throw error even though its working fine!
                if (empty($res)) {return false;}
                $openssl_args['keysnew']=$res;
                        //var_dump($res);echo '<br><br>';


                // Extract the private key from $res to $privKey
                openssl_pkey_export($res, $privKey, NULL, $openssl_args); // <-- CONFIG ARRAY
                openssl_error_string(); // May throw error even though its working fine!

                // Extract the public key from $res to $pubKey
                $pubKey = openssl_pkey_get_details($res);
                openssl_error_string(); // May throw error even though its working fine!
                if ($pubKey === FALSE){return false;}
                $pubKey = $pubKey["key"];   

                // Encrypt the data to $encrypted using the public key
                $data = $openssl_args['data'];          
                $res = openssl_public_encrypt($data, $encrypted, $pubKey);
                if ($res === FALSE){return false;}
                        #var_dump($res);exit; //bool
                // Decrypt the data using the private key and store the results in $decrypted
                $res = openssl_private_decrypt($encrypted, $decrypted, $privKey);
                if ($res === FALSE){return false;}

                //return $decrypted;
                $openssl_args['pub_key']=$pubKey;
                $openssl_args['priv_key']=$privKey;
                $openssl_args['encr']=$encrypted;
                $openssl_args['decr']=$decrypted; 

                return $openssl_args;

        }




        // try sam openssl.cnf   , most error on windows xampp
        $try= 5;     
        $openssl_cnf_path = array(
            0=>'C:\xampp\apache\conf\openssl.cnf',   //11259 bytes
            1=>'C:\xampp\apache\bin\openssl.cnf',   //11259 bytes

            2=>'C:\xampp\php\windowsXamppPhp\extras\ssl\openssl.cnf',  //10909
            3=>'C:\xampp\php\extras\ssl\openssl.cnf',   //10909 byes
            4=>'C:\xampp\php\extras\openssl\openssl.cnf',   //9374 bytes

            5=>'C:\Program Files\Git\usr\ssl\openssl.cnf',  //10909 bytes
            6=>'C:\Program Files\Git\mingw64\ssl\openssl.cnf',  //10909 bytes
            );

        $data = ' todo in spin activate theme elementor-child plugin qw_casino ... permalinks postname media Lib. add new upload paysave pic make empty page   with template-casino in -child make page4todo in spin activate theme elementor-child plugin qw_casin245'; /**  ... permalinks postname media Lib. add new upload paysave pic make empty page   with template-casino in -child make page6todo in spin activate theme elementor-child plugin qw_casino  .. permalinks postname media Lib.add new upload paysave pic  make empty501'; 
        /** mist max str len 501  in RFC3447 can operate on messages of length up to k - 11 octets (k is the octet length of the RSA modulus) so if you are using 2048-bit RSA key then maximum length of the plain data to be encrypted is 245 bytes.  /***/

        echo 'str len : ', strlen($data);

        $openssl_args = array(
            "config" => $openssl_cnf_path[$try],
            "digest_alg" => "sha512",
            //"private_key_bits" => 4096,
            "private_key_bits" => 2048,
            "private_key_type" => OPENSSL_KEYTYPE_RSA,
            "try_path_ar" => $openssl_cnf_path,
            "data" => $data,
            );



        // Example
        $res = testOpenSSL($openssl_args);
        if ($res === FALSE)
        {
            echo "<h4 style='background-color: red;'>Fail</h4>";
        } else {
            echo '<h3 style=\'background-color: green; color:white;\'>with $try= '.$try.' decrypted ok: '.$res['decr'].'</h3>';
        }

                //////////////////////////////////////////
                //
                echo '<br>vardump res <br>';  var_dump($res);   
                echo '<br>======================<br>';      

        $privKey=$res['priv_key'];
        $pubKey =$res['pub_key'];
        file_put_contents('pri_key.txt',$privKey);
        file_put_contents('priv_key.txt',$privKey);
        file_put_contents('pub_key.txt',$pubKey);


        echo '<br><br><pre>';


        /* Encrypt the data using the public key
         * The encrypted data is stored in $encrypted */
        openssl_public_encrypt($data, $encrypted, $pubKey);
                echo '<br>public encrypt: '; var_dump( base64_encode($encrypted));


        /* Decrypt the data using the private key and store the
         * result in $decrypted. */
        openssl_private_decrypt($encrypted, $decrypted, $privKey);
                echo ' private decrypt: ', $decrypted;      



        // inverse testOpenSSL
        openssl_private_encrypt($data, $encrypted, $privKey);
                echo '<br><br> invers<br>pri encrypt: '; var_dump( base64_encode($encrypted));

        openssl_public_decrypt($encrypted, $decrypted, $pubKey);
                echo ' pub decrypt: ', $decrypted , '<br>'; 

在我的情况下,在Windows XAMPP中,最重要的是找到正确的openssl.cnf文件并将其放入参数数组中。 - Ed Vo

-1

我可以建议使用Virtual Box,创建一个虚拟机并安装LAMP堆栈。这将为您提供一个“更真实”的环境。同时,在Linux上更容易解决OpenSSL的问题。

话虽如此,我认为您的问题是找不到插件文件本身。确保它位于正确的路径中,并存在于您的计算机上,以及Apache运行的进程具有读取它的权限。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接