Перейти к содержимому
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

Что это означает

Функции OpenSSL в PHP принимают ключ в виде текста 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, либо URI `file://`, а для зашифрованных ключей — ещё и парольную фразу.

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

Связанные ошибки

Открыть всю базу ошибок подписей