本文へスキップ
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);

関連するエラー

署名エラーデータベースをすべて見る