【问题标题】:PHP with openSSL - supplied key param cannot be coerced into a private key带有 openSSL 的 PHP - 提供的密钥参数不能被强制转换为私钥
【发布时间】:2023-03-16 11:07:01
【问题描述】:

我正在尝试使用openssl_sign() 函数对文件进行签名。我有以下私钥: -----BEGIN EC PRIVATE KEY----- MHQCAQEEIDzQVg9bJ1kZFsZDoLeqadA4OTgKc40ukSmQ3MVzcV0soAcGBSuBBAAK oUQDQgAEvzUNKCE3UVimCLUePomOUH/kfy0ujHdN5Kmn7ez3TtokJDy5ksVnOgf6 WzpmzY46zvKAnQ44Cgx5Kdqx5dVDiw== -----END EC PRIVATE KEY-----

我正在使用以下函数:openssl_sign("test", $signature, $private_key, OPENSSL_ALGO_SHA256);

我有一台服务器可以使用给定的密钥进行签名,而另一台则不能。一个有 PHP 5.6 ,一个没有 PHP 7.1 。为什么一台服务器可以使用密钥而一台不能?

【问题讨论】:

  • 出于安全考虑,我希望这不是您在此处发布的实际私钥。如果是这样,我建议你立即更换。
  • 啊不,这只是一些随机字节..
  • 是否有任何突出问题的错误消息?

标签: php pyopenssl


【解决方案1】:

一旦我因为密钥文件末尾的空行而收到此错误。我觉得值得一看。

【讨论】:

    【解决方案2】:

    可能是权限问题?确保您的 php 脚本可以读取您的 private_key.pem。还要记住,私钥参数必须是资源。

    // fetch private key from file and ready it
    $private_key = openssl_pkey_get_private("file:///path/to/your/private_key.pem");
    // compute signature
    openssl_sign("test", $signature, $private_key, OPENSSL_ALGO_SHA256);
    

    然后为您的密钥添加读取权限:chmod a+r /path/to/your/private_key.pem

    【讨论】:

      【解决方案3】:

      只需使用 HS256 编码。这是最好的答案。

      【讨论】:

        【解决方案4】:

        记住:

        $key="-----BEGIN RSA PRIVATE KEY-----
                ONp+TMNeWOkyAnfdRjXJnZisrkvk8kYaSCdFpE//Who4PZLvup8TBXV+aHUN5aNb
                qV8KP+r+yjsnAguLM1ZGuP1JJ+MRETk7pUX5QwIDAQABAoIBAAXCozlhkTCLo34V
                k7Ql3Y1tLiYnRIQqA1VYiJLmn4nZhUZkMQzyAWhp56ne38V7it2LVggENmZyyfzf
                BXLZCZLD2vXdvaIRM2BEZd4xouAVtrVozi8HP1UC+OfQpbAH+ez+Ek+XArSNUXiQ
                MIIEowIBAAKCAQEAk8uKqR2c7kDZIsEb2DAyhYz2HxIjKVXALHxZTWHKqyWgUXKw
                htiJlpi6T/jJw9FALnvQMFT9q8BXhVkKTMJvXkNDJtOZ35dZ7+GqfSEHzKojXv4v
                -----END RSA PRIVATE KEY-----";
        

        无效且不一样

        $key="-----BEGIN RSA PRIVATE KEY-----
        ONp+TMNeWOkyAnfdRjXJnZisrkvk8kYaSCdFpE//Who4PZLvup8TBXV+aHUN5aNb
        qV8KP+r+yjsnAguLM1ZGuP1JJ+MRETk7pUX5QwIDAQABAoIBAAXCozlhkTCLo34V
        k7Ql3Y1tLiYnRIQqA1VYiJLmn4nZhUZkMQzyAWhp56ne38V7it2LVggENmZyyfzf
        BXLZCZLD2vXdvaIRM2BEZd4xouAVtrVozi8HP1UC+OfQpbAH+ez+Ek+XArSNUXiQ
        MIIEowIBAAKCAQEAk8uKqR2c7kDZIsEb2DAyhYz2HxIjKVXALHxZTWHKqyWgUXKw
        htiJlpi6T/jJw9FALnvQMFT9q8BXhVkKTMJvXkNDJtOZ35dZ7+GqfSEHzKojXv4v
        -----END RSA PRIVATE KEY-----";
        

        它是有效的。

        如果您使用第一个或任何类似的,您可能会遇到该异常。在我的情况下,密钥是在一行中传递的,因此会引发异常,并且与 php 版本或 SO 无关。

        【讨论】:

        • 请为您的答案添加一些进一步的解释。这些信息如何解决给定的问题?
        • @Nico,ericksho 可能会指出在您的键中不要留下制表符/空格。我更喜欢 Heredoc 甚至更好的外部文件
        【解决方案5】:

        首先您应该检查是否启用了 OpenSSL。你可以通过输出来做到这一点

        phpinfo();

        并检查:“OpenSSL 支持已启用”。在这种情况下是这样。

        为了进一步排除故障有两个功能大有帮助:

        error_get_last()
        Usage: print_r(error_get_last());
        

        openssl_error_string()
        Usage: echo openssl_error_string();
        

        在这种情况下,“error_get_last()”返回:

        openssl_sign(): 提供的密钥参数不能被强制转换为私有的 键

        并返回“openssl_error_string()”:

        错误:100AE081:椭圆曲线 例程:EC_GROUP_new_by_curve_name:未知组

        此消息表示使用的 OpenSSL 版本没有代码来处理使用的 EC 曲线。 “EC_GROUP_new_by_curve_name”搜索“static const ec_list_element curve_list[]”并没有找到。结果它返回“未知”。

        现在您有 3 个选项:

        • 升级您的 OpenSSL 以支持此曲线。
        • 选择两个服务器都支持的另一条曲线。
        • 使用非 EC 加密。

        从 PHP 7.1.0 开始,您可以使用:

        openssl_get_curve_names()
        

        获取支持的曲线列表。我不知道 PHP 5.6 有类似的功能,因此您可能需要尝试一些,然后才能在两台主机上获得一个可用的功能。

        作为旁注: 一些 Linux 发行版,如 RedHat 和 CentOS,使用的 OpenSSL 版本比其他发行版更严格。该错误表明在这种情况下,OpenSSL 是在旧的 (5.8) CentOS 版本上手动更新的。有一些在线手册(如https://syslint.com/blog/tutorial/how-to-upgrade-openssl-on-centos-7-or-rhel-7/)仅升级 OpenSSL 可执行文件。如果使用这种或类似的技术,PHP 仍将使用“旧”OpenSSL,因此从命令行运行 OpenSSL 会得到与从 PHP 调用不同的结果。

        【讨论】:

        • 同样的错误是我得到的:openssl_sign(): supplied key param cannot be coerced into a private key
        • 尝试了您的第二条评论。收到:error:100AE081:elliptic curve routines:EC_GROUP_new_by_curve_name:unknown group
        • 工作服务器:PHP 5.6,OpenSSL:1.0.1f 2014 年 1 月 6 日;不支持的服务器:PHP 7.1,OpenSSL:1.0.2n 2017 年 12 月 7 日(最新)。
        • 服务器操作系统:工作的服务器:Ubuntu 3,不工作的服务器:Centos 5.8
        • CentOS 5.8 与 PHP 7.1 和 OpenSSL 1.0.2n 绝对是自定义/非默认设置。在这种情况下,很难说到底是什么问题,但我的怀疑仍然是 OpenSSL 安装而不是开发错误。
        【解决方案6】:

        也许您需要使用openssl_get_privatekey 来创建私钥资源,而不是简单地使用字符串

        $str_priv_key='-----BEGIN EC PRIVATE KEY-----
        MHQCAQEEIDzQVg9bJ1kZFsZDoLeqadA4OTgKc40ukSmQ3MVzcV0soAcGBSuBBAAK
        oUQDQgAEvzUNKCE3UVimCLUePomOUH/kfy0ujHdN5Kmn7ez3TtokJDy5ksVnOgf6
        WzpmzY46zvKAnQ44Cgx5Kdqx5dVDiw==
        -----END EC PRIVATE KEY-----';
        
        $pkey=openssl_get_privatekey( $str_priv_key );
        openssl_sign( "test", $signature, $pkey );
        openssl_free_key( $pkey );
        

        根据PHP manual,私钥参数必须是资源

        > priv_key_id
        > resource - a key, returned by openssl_get_privatekey()
        

        【讨论】:

        • 感谢您的评论,好像我遇到了同样的错误。 openssl_get_privatekey 没有区别:PHP Warning: openssl_sign(): supplied key param cannot be coerced into a private key in
        • 大概问题中的私钥字符串不是完整的字符串吧?也许值得注意的是我有 PHP 5.3.2
        • 应该是,因为它确实可以在不同的服务器上工作,并且当我使用 OpenSSL 使用命令行进行签名时它确实可以工作:openssl dgst -sha256 -hex -sign key.pem hash.txt
        • 当我尝试使用那个键时我得到openssl_sign(): key type not supported in this PHP build
        猜你喜欢
        • 1970-01-01
        • 2019-05-29
        • 2021-03-01
        • 2014-02-04
        • 2014-12-11
        • 1970-01-01
        • 2016-04-02
        • 1970-01-01
        • 2012-08-25
        相关资源
        最近更新 更多