Mensagem de erro
openssl_verify(): Supplied key param cannot be coerced into a public key
Também aparece como
- 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
O nome da função varia (`openssl_verify`, `openssl_sign`, `openssl_seal`, `openssl_public_encrypt`…), assim como o tipo de chave (“public key” / “private key”). Com `display_errors` ativado, o PHP acrescenta o prefixo “Warning: ”.
PHP OpenSSL extension — warning from openssl_verify / openssl_sign / openssl_seal
O que significa
As funções OpenSSL do PHP aceitam uma chave como texto PEM, um caminho `file://` ou um objeto de chave, e o valor que você passou não pôde ser convertido em uma chave do tipo exigido (pública para verificar, privada para assinar). É um aviso, não uma exceção: a função retorna `false` (ou `-1`), e um código que só verifica `=== 1` trata isso silenciosamente como “assinatura inválida”. O motivo real informado pelo OpenSSL está disponível via `openssl_error_string()`.
Por que acontece
PEM com \n literal vindo de uma variável de ambiente
comumChaves guardadas em arquivos `.env`, variáveis de CI ou JSON muitas vezes contêm os dois caracteres `\` e `n` em vez de quebras de linha. O OpenSSL não consegue analisar um PEM assim.
Um caminho de arquivo sem file://
comumUm caminho puro como `/etc/app/private.pem` é tratado como texto PEM e falha. O PHP precisa de `file:///etc/app/private.pem` ou do conteúdo do arquivo.
Um certificado, uma chave privada ou uma chave SSH onde se espera uma chave pública
ocasional`openssl_verify` aceita um certificado ou uma chave pública; uma chave pública OpenSSH (`ssh-ed25519 AAAA…`) ou uma string JSON de JWK não é um PEM.
Uma chave privada criptografada sem a frase secreta
ocasionalPassar um PEM `ENCRYPTED PRIVATE KEY` como string para `openssl_sign` não tem como funcionar; carregue-o antes com `openssl_pkey_get_private($pem, $passphrase)`.
Como corrigir
- 1.
Carregar a chave explicitamente e expor o motivo do OpenSSL
`openssl_pkey_get_public` / `_private` retornam `false` em caso de falha; chame `openssl_error_string()` até esvaziar a fila para registrar o motivo no log, e interrompa em vez de continuar com uma verificação que falhou.
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.
Usar file:// em caminhos de arquivo e passar as frases secretas
Deixe explícita a origem da chave: ou o conteúdo PEM, ou uma URI `file://`, além da frase secreta para chaves criptografadas.
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);