跳到主要内容
ecdsa.com
PHP OpenSSL extensionPHP

错误信息

openssl_verify(): Supplied key param cannot be coerced into a public key

也可能输出为

  • openssl_sign(): Supplied key param cannot be coerced into a private key
  • Warning: openssl_verify(): Supplied key param cannot be coerced into a public key

函数名各不相同(`openssl_verify`、`openssl_sign`、`openssl_seal`、`openssl_public_encrypt`…),密钥类型也是如此(“public key” / “private key”)。开启 `display_errors` 时,PHP 会加上前缀“Warning: ”。

PHP OpenSSL extension — warning from openssl_verify / openssl_sign / openssl_seal

含义

PHP 的 OpenSSL 函数接受 PEM 文本、`file://` 路径或密钥对象形式的密钥,而你传入的值无法转换成所需类型的密钥(验证需要公钥,签名需要私钥)。这是警告,而不是异常:函数返回 `false`(或 `-1`),只检查 `=== 1` 的代码会悄无声息地把它当作“签名无效”。底层的 OpenSSL 原因可以通过 `openssl_error_string()` 获取。

原因

修复方法

  1. 1.

    显式加载密钥并输出 OpenSSL 给出的原因

    `openssl_pkey_get_public` / `_private` 失败时返回 `false`;反复调用 `openssl_error_string()` 取出全部错误并记录原因,然后停止处理,而不是在验证失败的情况下继续执行。

    php
    $pem = str_replace('\\n', "\n", getenv('JWT_PUBLIC_KEY'));   // undo escaped newlines
    $publicKey = openssl_pkey_get_public($pem);
    if ($publicKey === false) {
        while ($msg = openssl_error_string()) {
            error_log($msg);                                     // the real OpenSSL reason
        }
        throw new RuntimeException('JWT_PUBLIC_KEY is not a usable public key');
    }
    $ok = openssl_verify($data, $signature, $publicKey, OPENSSL_ALGO_SHA256) === 1;
  2. 2.

    文件路径使用 file://,并传入密码短语

    明确指定密钥来源:要么是 PEM 内容,要么是 `file://` URI;对于加密的密钥,还要提供密码短语。

    php
    // Paths need the file:// scheme; encrypted keys need their passphrase.
    $privateKey = openssl_pkey_get_private('file:///etc/app/private.pem', getenv('KEY_PASSPHRASE') ?: null);

相关错误

浏览完整的签名错误库