Mensaje de error
openssl_verify(): Supplied key param cannot be coerced into a public key
También se muestra 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
El nombre de la función varía (`openssl_verify`, `openssl_sign`, `openssl_seal`, `openssl_public_encrypt`…), y también el tipo de clave («public key» / «private key»). Con `display_errors` activado, PHP antepone «Warning: ».
PHP OpenSSL extension — warning from openssl_verify / openssl_sign / openssl_seal
Qué significa
Las funciones OpenSSL de PHP aceptan una clave como texto PEM, como ruta `file://` o como objeto de clave, y el valor que pasas no se pudo convertir en una clave del tipo requerido (pública para verificar, privada para firmar). Es una advertencia, no una excepción: la función devuelve `false` (o `-1`), y el código que solo comprueba `=== 1` lo trata en silencio como «firma no válida». El motivo subyacente de OpenSSL está disponible mediante `openssl_error_string()`.
Por qué ocurre
PEM con \n literales de una variable de entorno
frecuenteLas claves guardadas en archivos `.env`, variables de CI o JSON suelen contener los dos caracteres `\` y `n` en lugar de saltos de línea. OpenSSL no puede analizar un PEM así.
Una ruta de archivo sin file://
frecuenteUna ruta sin más, como `/etc/app/private.pem`, se trata como texto PEM y falla. PHP necesita `file:///etc/app/private.pem` o el contenido del archivo.
Un certificado, una clave privada o una clave SSH donde se espera una clave pública
ocasional`openssl_verify` acepta un certificado o una clave pública; una clave pública de OpenSSH (`ssh-ed25519 AAAA…`) o una cadena JSON con una JWK no son un PEM.
Una clave privada cifrada sin frase de contraseña
ocasionalPasar a `openssl_sign` un PEM `ENCRYPTED PRIVATE KEY` como cadena no puede funcionar; cárgalo antes con `openssl_pkey_get_private($pem, $passphrase)`.
Cómo solucionarlo
- 1.
Cargar la clave explícitamente y mostrar el motivo de OpenSSL
`openssl_pkey_get_public` / `_private` devuelven `false` si fallan; llama a `openssl_error_string()` hasta vaciar la cola para registrar el motivo, y detente en lugar de continuar con una verificación fallida.
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:// para las rutas de archivo y pasar las frases de contraseña
Indica explícitamente el origen de la clave: o bien el contenido PEM, o bien un URI `file://`, además de la frase de contraseña para las claves cifradas.
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);