I'm having some problems loading in a public key for encrypting using openssl_seal function in PHP...
I've created the public & private keys using the openSSL command line tool:
openssl genrsa -des3 -out private.pem 1024
openssl rsa -in private.pem -out public.pem -outform PEM -pubout
However, when I run it in my PHP code I get the following errors:
openssl_seal() [function.openssl-seal]: Don't know how to get public key from this private key
openssl_seal() [function.openssl-seal]: not a public key (1th member of pubkeys)
When I verify the public key using: openssl verify public.pem, I get:
unable to load certificate
1876:error:0906D06C:PEM routines:PEM_read_bio:no start line:.\crypto\pem\pem_lib
.c:648:Expecting: TRUSTED CERTIFICATE
Anyone know why this is happening?
PHP Code:
public function encrypt($valueToEncrypt, $publicKeyFile)
{
$pk = file_get_contents($publicKeyFile);
$publicKey = openssl_pkey_get_public($pk);
$encrypted = '';
$a_envelope = array();
$a_key = array($publicKey);
if (openssl_seal($valueToEncrypt, $encrypted, $a_envelope, $a_key) === FALSE)
{
while ($msg = openssl_error_string())
echo $msg . "<br />\n";
die('Failed to encrypt data!');
}
openssl_free_key($publicKey);
....
For anyone experiencing the same problem, the issue related to an install of xampp on windows. Running on the command line on a fresh install of just php worked fine.
In addition to StuffandBlah's answer: It is in fact related to the different OpenSSL versions in Apache and PHP in XAMPP on Windows. Here's a post of how to solve the problem (copying DLLs).
Related
Environment:
Ubuntu 14.04, PHP 5.5.9, MYSQL 5.6.30
From time to time I get an error
mysqli::real_connect(): SSL operation failed with code 1. OpenSSL
Error message:
error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number
Front/nginx is on one server and mysql is on a different server.
The error is not continuous, it happens randomly and I find those error messages in error log so I cannot really do full debug.
Sample:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$this->objMySqli = mysqli_init();
mysqli_options ($this->objMySqli, MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, true);
$this->objMySqli->ssl_set($this->SslKey, $this->SslCertificate, $this->SslCACertificate, null, null);
$link = $this->objMySqli->real_connect($this->Server, $this->Username, $this->Password, $this->Database, $this->Port);
if (!$link) {
throw new QMySqliDatabaseException("Unable to connect to Database", -1, null);
}
SSL Cipher:
It fails on this line:
$link = $this->objMySqli->real_connect($this->Server, $this->Username, $this->Password, $this->Database, $this->Port);
It is problem with mysql version 5.6.30,
I have updated to 5.6.32 and now this error is not happening anymore.
Upgrading didn't fix my problem, but I did find a new solution.
TLDR; Convert your PKCS#8 format keys to PKCS#1 format keys
openssl rsa -in example.com.server.key.pem -out example.com.server.key.pkcs1.pem
I ran into these bugs:
MySQL Bug 71271
MySQL Bug 64870
Essentially, if your private key is in PKCS#8 format instead of PKCS#1 format, MySQL will not "find" the private key.
A lot of Stack Overflow answers say rename the header and footer to include RSA in the header and footer like so:
From (PKCS#8 format)
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
To (PKCS#1 format)
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
However, this does not change the private key data between the header and footer. When using my PKCS#8 format key with the modified header and footer, no error occured at MySQL startup, but when I tried to connect with mysqli I got
error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number
By converting my private keys to PKCS#1 format, the keys worked and I could connect fine:
openssl rsa -in example.com.server.key.pem -out example.com.server.key.pkcs1.pem
Note that newer OpenSSL versions, at least 1.0.2j (what I was using) output PKCS#8 keys when using
openssl req -config "openssl.cnf" \
-keyout "private/example.com.server.key.pem" -new -sha256 \
-days 3652 -nodes -out "csr/example.com.server.csr.pem"
but using different options may output PKCS#1 keys (possibly -newkey rsa:2048, I haven't tested). Which would explain why only some people are experiencing this when using openssl generated private keys.
This problem occurred form me in MySQL 5.6.17 and 5.7.14, so it seems like the bugs are not fixed.
I try to make a connection through SoapClient. I need a certificate for this. I received a .pfx certificate. I used the following command to create a .pem file.
openssl pkcs12 -in cert.pfx -out cert.pem -nodes
There is a password in the certificate so I need to enter it before I get the cert.pem file. So far so good, I think.
Now I try to connect to the WSDL service.
$url = "https://test.website.com/webservices/transfer.asmx?WSDL";
$cert = '/path/to/cert.pem';
$passphrase = "12345678";
$soapClient = new SoapClient($url, array('local_cert'=>$cert,'passphrase'=>$passphrase));
I get the following error:
(Warning) SoapClient::SoapClient(): Unable to set private key file `/var/www/vhosts/............./cert.pem'
I think the problem is the certificate. Is the way that I converted the .pfx to a .pem the correct way?
The problem you're running into is that a .pem certificate is always supposed to be an encrypted file. According to the OpenSSL docs for the pkcs12 command when you used -nodes it didn't encrypt anything, rather put each node into plain text, which caused the .pem certificate to be invalid and your SoapClient couldn't parse the invalid file.
To fix this, hopefully you haven't deleted the original cert.pfx, just re-convert it using this line:
openssl pkcs12 -in cert.pfx -out cert.pem -clcerts
and your cert.pem file will be correct.
Today I had this problem with an invalid Cert/Private combination, meaning the cert wasn't belonging to the specified key.
You can verify this problem using:
openssl rsa -noout -modulus -in server.key | openssl md5
openssl x509 -noout -modulus -in server.crt | openssl md5
key and cert should return the same checksum. If not, somebody has mixed up some files.
The same procedure works for CSRs as well:
# and for a CSR
openssl req -noout -modulus -in server.csr | openssl md5
I already have converted a public key (.cer) and a private key (.key) to pem format but I had use the command lines to convert them as follows:
$openSSLpath = "c:\OpenSSL-Win64\bin\openssl.exe"; //Path to OpenSSL exe
$path = "c:\appserver\Apache2.2\htdocs\FIEL"; //Path to Project Folder
$rutaCer = $path.'\GAMA600504JP1.cer';
$rutaKey = $path.'\GAMA600504JP1.key';
$passwordKey = '12345678a';
$cmdKey = $openSSLpath." pkcs8 -inform DER -in ".$rutaKey." -passin pass:".$passwordKey." -out ".$rutaKey.".pem";
exec($cmdKey);
$cmdCer = $openSSLpath." x509 -inform DER -outform PEM -in ".$rutaCer." -pubkey -out ".$rutaCer.".pem";
exec($cmdCer);
This generates correctly the .pem files but I need to know if is it possible to do this by any other way using PHP. Note that I'm completely new to openSSL and this is the only way I've found to do it on PHP.
To do this I have to ensure that OpenSSL its properly located and installed on my server and in order to do the conversions to .pem I have to save the .cer and .key files temporarily in the server which its not recommended due to security reasons.
Is there any other way?
You can easily convert your der data to PEM by simple code.
$rutaCer = file_get_contents($path.'\GAMA600504JP1.cer');
$rutaKey = file_get_contents($path.'\GAMA600504JP1.key');
echo "-----BEGIN PRIVATE KEY-----\n" . chunk_split(base64_encode($rutaKey), 64, "\n") . "-----END PRIVATE KEY-----";
echo "-----BEGIN CERTIFICATE-----\n" . chunk_split(base64_encode($rutaCer), 64, "\n") . "-----END CERTIFICATE-----";
// Save anywhere
PHP has functions for exporting to PEM but there is problem with loading keys/certificates from binary DER format.
Another way can be use of phpsec library.
I need to encrypt with private key and I'm attempting to do so with the following code:
$content = file_get_contents("file.key");
$plaintext = "14d9df79-8c4c-4380-8444-d31e1fd3f78a";
openssl_private_encrypt($plaintext, $encrypted, $content);
$transfer = base64_encode($encrypted);
echo "text encrypted is:" . $transfer; //encrypted string
I'm getting the error:
openssl_private_encrypt(): key param is not a valid private key in
Do I have to do something to the key file? It is binary.
First, try converting a key into PEM format using openssl:
openssl rsa -inform der -in file.key -outform pem -out filekey.pem
Next, extract the private key from the PEM file using openssl_pkey_get_private
$key = openssl_pkey_get_private(file_get_contents("filekey.pem"));
$plaintext = "14d9df79-8c4c-4380-8444-d31e1fd3f78a";
openssl_private_encrypt($plaintext, $encrypted, $key);
$transfer = base64_encode($encrypted);
echo "text encrypted is:" . $transfer; //encrypted string
I don't know of any x509 file format using a .key extension. There's pem (which is the format you need to load into openssl), DER (files may have .der, .crt or .cer extension) or PKCS#12 (.pfx .p12). It's probably DER or PKCS#12:
openssl pkcs12 -in file.key -out file.pem -nodes
...converts a PKCS#12 to file.pem,
openssl x509 -inform der -in file.key -out file.pem
...converts a DER file. They'll report an error if it's the wrong file format. OTOH you could just use the 'file' command to find out the file type. (this is assuming that you've got a Posix / Linux system - you didn't say).
Or you could just ask the person who gave it to you what format it is.
Solved
I just use the
openssl pkcs8 .....
command
hope this is useful to someone else
I'm looking for days how to translate this command to OpenSLL php function:
$ openssl pkcs8 -inform DER -in aaa010101aaa_CSD_01.key -out AAA010101AAA.key.pem
Enter Password: a0123456789
This work perfect, but I can't (I don't know) use the correct function of PHP OpenSSL
http://www.php.net/manual/es/ref.openssl.php
I have made this for .cer working perfect:
command : openssl x509 -inform DER -outform PEM -in aaa010101aaa_CSD_01.cer -out AAA010101AAA.cer.pem
PHP equivalent:
function der2pem($der_data) {
$pem = chunk_split(base64_encode($der_data), 64, "\n");
$pem = "-----BEGIN CERTIFICATE-----\n".$pem."-----END CERTIFICATE-----\n";
return $pem;
}
$fp = fopen("llaves/aaa010101aaa_CSD_01.cer", "r");
$priv_key = fread($fp, 8192);
fclose($fp);
echo der2pem($priv_key);
It's perfect, giving it to me the PEM. But doesn't work for the .key, just for the .cer, I obtain on OpenSSL this for .key using the funcion on PHP:
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDpmiW1q9gyzCFtMcbaFDJexk2IpLoTdNXg4ToGRZ/f+hIjmj3N
6ODWX1ARNFGYocEHf113GpW5Oe/mj6UqhBpiH4JRTNR4Udb8myJTArIlODynVHuI
UuyhKo7gbMbDdXjilTAYY2XWQuQ7aDtWwntUmNg4vAC/F3OtRz3+y9wM5QIDAQAB
AoGAfNkHomqvZ6a1jrh1wIPez8xID+mKEW/2BvQYoNWBNqFeJG0A7xWxZKEYF7nQ
ijSZB7rIZylsL8yJLL5E1c44koc+2+S6OF6gcWujcLR5UFRIZscxo0e1ro30wSTy
MBcdBeWASbaEy7+7MF46W0hAhBE7b49JUmduz1fBjtNNeoECQQD3VbNAsbf/90Vw
ZVexUXWNquwPsAZjmdpL1Te1RdC5txj2EbUdDPaaYC1cCXXjblf9rsyyViUowsNt
cnh92wSRAkEA8clIHObESiZZEndtmYuRlgLsX2Gr/qo30uAUurH7p8Q07SWOZCJk
OPJUhh2qanYZsnsOYHW+9Br5U6gDknxdFQJBALoua9nWLdDjnQTHdKSI0jmLIVmJ
wrV1GgsdfGrbHAzAlGye1bwBhxycK2jtwi0qYdgXngTcreop+hxIIAV1OdECQQC7
v7rZhnBhy8lax5Y5puEUBY0au7Nc+zyB6TLvjgmGSpt2krUxGGuOtM3hnuOX68Ek
kN2nFYeD8fYtecfcVenJAkEAxM+QzoVdJpw1/ijh+IfZ5eNhvMK2bj4De+/2Sx5K
ZZ9SiI7bRaOjBfvaI7AkeH0LpihURW12Zt7hZv8kC058Jg==
-----END RSA PRIVATE KEY-----
The same function on php give me:
-----BEGIN-----
MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIgkLCyAP9+nQCAggA MBQGCCqGSIb3DQMHBAgTJc/0zgL+tASCAoBHumtbuHsY5IevnUwr1Ha5P+S3RpVS 6iYvoOvKs5L6bPE+fjCkLxset0e68NcyXDw3WO/qzfGkFVGBnC90gekWUiS7/2pf ltPeKjo8Fw7T4CgVWhtnVdPZmJWihY52FuIQ2HuyQYzH8K/SnjYP4GBkJKpdPCjy JNzjspfJPoOlfdOkj7URwvKH5RjsLGYkopjtdaqxS2pFfz6PPCSiFMn+Jo9Vkjwv 3d1b3X2SoYuYhV2g3XgHWHBQNqoas8Blhcw8OYNlntxcaNnx3Eb9YcCWSmNj7l+c pibvosXzEqVoat6PsJyUVzJQZBao15PnI438qomkprsCy6EvFSSXuIunMH7nVIGH gcS0TRxYpXPHY3cdQOdsJtxb4Ny1aCJqLQkHs2jbiLZ5mu+rmQUil3tLxfRd4Bje AYA3T1e5VVVha97BmNQVTbNfxj9wWvkmrearxJXTvvnML4f0ma830S/1AGmCGLb/ A2KlqHq9RxqJn1SdOuYQbcQTeGe/JRVOaJVGUKxJ2vbwjB/35cmGNLKYj4faZZgy jYpC3BqVeDcPGlPuMnoNkgrBfLDgDX+JV6tqqT2uMo76Wp6xYKmM41jkO1IAWpHR /R7d3aG2psL0wKkFSEXWxhX3SRLdurVcFLv6E6bEPHqHJR4QrvF2OUwpDhOZz9F/ Lz935gz5MQNRuVRtAVBAa2ZmjRbdCboL/qiL2MKibZLNRmKy3dqRdPOmnlKKBR8d cYQc4YwRm5dWuObO2tY68R4H43g7shw+POKSzvSPhAkzRRGExONVDJ6Zg/0iAUNe 0xYlsqKJyCJ1fg/b1AuFyyAnOhCO9ywUGiK7t92pZRgmwxEfVBDRNcbA
-----END -----
Any ideas?
There's a library that allows just that. It is called Chilkat2. I used it to do the same in Python without console.
Right now I'm trying to remove this dependency in my library because it's closed source and it can't be installed through package managers, it must be installed manually with the website instructions.
It works pretty well, however, so here's how you would do it, assuming you have the .key file, the password, and Chilkat2 PHP Extension installed:
include("chilkat_9_5_0.php"); //whatever version you download
privateKey = new CkPrivateKey();
privateKey.LoadPkcs8EncryptedFile('path/to/private.key',password)
pemString = privateKey.getPkcs8Pem()
Note: I created this code with the documentation, but I have never used Chilkat2 with PHP.