PHP with openSSL - supplied key param cannot be coerced into a private key
Remember:
$key="-----BEGIN RSA PRIVATE KEY-----
ONp+TMNeWOkyAnfdRjXJnZisrkvk8kYaSCdFpE//Who4PZLvup8TBXV+aHUN5aNb
qV8KP+r+yjsnAguLM1ZGuP1JJ+MRETk7pUX5QwIDAQABAoIBAAXCozlhkTCLo34V
k7Ql3Y1tLiYnRIQqA1VYiJLmn4nZhUZkMQzyAWhp56ne38V7it2LVggENmZyyfzf
BXLZCZLD2vXdvaIRM2BEZd4xouAVtrVozi8HP1UC+OfQpbAH+ez+Ek+XArSNUXiQ
MIIEowIBAAKCAQEAk8uKqR2c7kDZIsEb2DAyhYz2HxIjKVXALHxZTWHKqyWgUXKw
htiJlpi6T/jJw9FALnvQMFT9q8BXhVkKTMJvXkNDJtOZ35dZ7+GqfSEHzKojXv4v
-----END RSA PRIVATE KEY-----";
is invalid and is not the same as
$key="-----BEGIN RSA PRIVATE KEY-----
ONp+TMNeWOkyAnfdRjXJnZisrkvk8kYaSCdFpE//Who4PZLvup8TBXV+aHUN5aNb
qV8KP+r+yjsnAguLM1ZGuP1JJ+MRETk7pUX5QwIDAQABAoIBAAXCozlhkTCLo34V
k7Ql3Y1tLiYnRIQqA1VYiJLmn4nZhUZkMQzyAWhp56ne38V7it2LVggENmZyyfzf
BXLZCZLD2vXdvaIRM2BEZd4xouAVtrVozi8HP1UC+OfQpbAH+ez+Ek+XArSNUXiQ
MIIEowIBAAKCAQEAk8uKqR2c7kDZIsEb2DAyhYz2HxIjKVXALHxZTWHKqyWgUXKw
htiJlpi6T/jJw9FALnvQMFT9q8BXhVkKTMJvXkNDJtOZ35dZ7+GqfSEHzKojXv4v
-----END RSA PRIVATE KEY-----";
which it is valid.
If you use the fist one or any similar you could get that exception. In my case the key was passed in a single line and therefore throwing the exception, and had nothing to do with php versión or SO.
First of all you should check if OpenSSL is enabled. You can do this by outputting
phpinfo();
and check for: "OpenSSL support enabled". In this case it was.
In order to troubleshoot further have two functions that help a great deal:
error_get_last()
Usage: print_r(error_get_last());
and
openssl_error_string()
Usage: echo openssl_error_string();
In this case the "error_get_last()" returned:
openssl_sign(): supplied key param cannot be coerced into a private key
and the "openssl_error_string()" returned:
error:100AE081:elliptic curve routines:EC_GROUP_new_by_curve_name:unknown group
This message means that the used OpenSSL version has no code to deal with the used EC Curve. The "EC_GROUP_new_by_curve_name" searches the "static const ec_list_element curve_list[]" and finds none. As a result it returns "unknown".
Now you have 3 options:
- Upgrade your OpenSSL to support this curve.
- Choose another curve that is supported on both servers.
- Use non-EC encryption.
As of PHP 7.1.0 you can use:
openssl_get_curve_names()
to get a list of supported curves. I'm unaware of a similar function for PHP 5.6 so you may have to try a few before getting one that is available on both hosts.
As as side note: Some Linux distributions, like RedHat and CentOS, use more restrictive versions of OpenSSL than others. The error indicates that this In this case OpenSSL was manually updated on an old (5.8) CentOS version. There are some manuals online (like https://syslint.com/blog/tutorial/how-to-upgrade-openssl-on-centos-7-or-rhel-7/) which only upgrade the OpenSSL executable. If this, or a similar, technique was used PHP would still use the 'old' OpenSSL and therefor running OpenSSL from the command line would give a different result than calls from PHP.
Perhaps you need to use openssl_get_privatekey
to create the private key resource rather than simply using a string
$str_priv_key='-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIDzQVg9bJ1kZFsZDoLeqadA4OTgKc40ukSmQ3MVzcV0soAcGBSuBBAAK
oUQDQgAEvzUNKCE3UVimCLUePomOUH/kfy0ujHdN5Kmn7ez3TtokJDy5ksVnOgf6
WzpmzY46zvKAnQ44Cgx5Kdqx5dVDiw==
-----END EC PRIVATE KEY-----';
$pkey=openssl_get_privatekey( $str_priv_key );
openssl_sign( "test", $signature, $pkey );
openssl_free_key( $pkey );
According to the PHP manual the private key parameter must be a resource
> priv_key_id
> resource - a key, returned by openssl_get_privatekey()