fockopen: Failed to enable crypto - php

Similar questions have been answered before, but I haven't been able to solve this particular case.
On a PHP 5.6+ machine when I try to use fsockopen on a particular domain I receive the following (not the real domain):
$ php -r "var_dump(fsockopen(\"ssl://www.domain.net\", 9085, \$errnum, \$errstr, 5));"
PHP Warning: fsockopen(): Failed to enable crypto in Command line code on line 1
PHP Warning: fsockopen(): unable to connect to ssl://www.domain.net:9085 (Unknown error) in Command line code on line 1
bool(false)
This works fine on PHP 5.5, which points to it being by the change in 5.6 dealing with the way fsockopen verifies ssl certificates.
Other connections can be made without issue:
$ php -r "var_dump(fsockopen(\"ssl://www.google.com\", 443, \$errnum, \$errstr, 5));"
resource(4) of type (stream)
Based on other suggestions I've checked the default cert file
$ php -r "print_r(openssl_get_cert_locations());"
Array
(
[default_cert_file] => /usr/lib/ssl/cert.pem
[default_cert_file_env] => SSL_CERT_FILE
[default_cert_dir] => /usr/lib/ssl/certs
[default_cert_dir_env] => SSL_CERT_DIR
[default_private_dir] => /usr/lib/ssl/private
[default_default_cert_area] => /usr/lib/ssl
[ini_cafile] =>
[ini_capath] =>
)
The file /usr/lib/ssl/cert.pem was originally missing, I download the ca bundle from curl and renamed it to match. Still no luck.
I'm not receiving any additional information indicating that verifying the certificate fails. Are there any other ways to debug the issue?

After much head bashing, I finally discovered the cause.
PHP 5.6 implemented a default set of support ciphers, which removed support for older more vulnerable ones. http://php.net/manual/en/migration56.openssl.php
The default ciphers used by PHP have been updated to a more secure list based on the » Mozilla cipher recommendations, with two additional exclusions: anonymous Diffie-Hellman ciphers, and RC4. The domain I was attempting to connected currently supports TLSv1/SSLv3, Cipher RC4-MD5
Do work around the issue I switched to stream_socket_client instead of fsockopen. Added RC4-MD5 to stream cipher support in the context:
$context = stream_context_create(['ssl' => [
'ciphers' => 'RC4-MD5'
]]);
$socket = stream_socket_client('ssl://'.$host.':'.$port, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);

Related

file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages: error:0A000126:SSL routines::unexpected eof while reading

I am trying to make a simple file_get_contents(https://some.api) in my code, but, while the URL works in the browser, it doesn't in php. I always get the following error:
file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages:
error:0A000126:SSL routines::unexpected eof while reading
I already tried some suggestions from similar questions in Stack Overflown like using stream_context_create():
$arrContextOptions=array(
"ssl"=>array(
"verify_peer"=>false,
"verify_peer_name"=>false,
),
);
$geoData = file_get_contents($requestUrl, false, stream_context_create($arrContextOptions));
But it still doesn't work. PHP SLL also seems to be ok:
~ » php -i | grep -i openssl user#localhost
SSL Version => OpenSSL/3.0.3
libSSH Version => libssh/0.9.6/openssl/zlib
libmongoc SSL library => OpenSSL
openssl
OpenSSL support => enabled
OpenSSL Library Version => OpenSSL 3.0.3 3 May 2022
OpenSSL Header Version => OpenSSL 3.0.2 15 Mar 2022
Openssl default config => /etc/pki/tls/openssl.cnf
openssl.cafile => no value => no value
openssl.capath => no value => no value
Native OpenSSL support => enabled
This is likely due to this issue: https://bugs.php.net/bug.php?id=79589
An IIS or equivalent non-compliant daemon is not following the SSL specification and OpenSSL is raising an error because of this. PHP does not provide any method to work around it and since you cannot pass the necessary SSL_OP_IGNORE_UNEXPECTED_EOF flag to OpenSSL the connection fails with an error.
For reference:
https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html
SSL_OP_IGNORE_UNEXPECTED_EOF
Some TLS implementations do not send the mandatory close_notify alert on shutdown. If the application tries to wait for the
close_notify alert but the peer closes the connection without sending
it, an error is generated. When this option is enabled the peer does
not need to send the close_notify alert and a closed connection will
be treated as if the close_notify alert was received.

I am using laravel version 6. I received below error when try to reset password. How can I Solve this error [duplicate]

After upgrading to PHP 5.6 I get an error when trying to connect to a server via fsockopen()..
The certificate on the server (host) is self-signed
PHP Warning: fsockopen(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
code
if($fp = fsockopen($host, $port, $errno, $errstr, 20)){
$this->request = 'POST '.substr($this->url, strlen($this->host)).' HTTP/1.1'.$crlf
.'Host: '.$this->host.$crlf
.'Content-Length: '.$content_length.$crlf
.'Connection: Close'.$crlf.$crlf
.$body;
fwrite($fp, $this->request);
while($line = fgets($fp)){
if($line !== false){
$this->response .= $line;
}
}
fclose($fp);
}
Have tried
# cd /etc/ssl/certs/
# wget http://curl.haxx.se/ca/cacert.pem
php.ini
openssl.cafile = "/etc/ssl/certs/cacert.pem"
But the script still fails to work
update
This works
echo file_get_contents("/etc/ssl/certs/cacert.pem");
update 2
$contextOptions = array(
'ssl' => array(
'verify_peer' => true, // You could skip all of the trouble by changing this to false, but it's WAY uncool for security reasons.
'cafile' => '/etc/ssl/certs/cacert.pem',
//'CN_match' => 'example.com', // Change this to your certificates Common Name (or just comment this line out if not needed)
'ciphers' => 'HIGH:!SSLv2:!SSLv3',
'disable_compression' => true,
)
);
$context = stream_context_create($contextOptions);
$fp = stream_socket_client("{$host}:{$port}", $errno, $errstr, 20, STREAM_CLIENT_CONNECT, $context);
error
PHP Warning: stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
The file that you downloaded (http://curl.haxx.se/ca/cacert.pem) is a bundle of the root certificates from the major trusted certificate authorities. You said that the remote host has a self-signed SSL certificate, so it didn't use a trusted certificate. The openssl.cafile setting needs to point to the CA certificate that was used to sign the SSL certificate on the remote host. PHP 5.6 has been improved over previous versions of PHP to now verify peer certificates and host names by default (http://php.net/manual/en/migration56.openssl.php)
You'll need to locate the CA certificate that was generated on the server that signed the SSL certificate and copy it to this server. If you're using self-signed certificates, you'll need to add the CA cert that was used to sign the remote host's SSL certificate to the trusted store on the server you're connecting from OR use stream contexts to use that certificate for each individual request. Adding it to the trusted certificates is the simplest solution. Just add the contents of the remote host's CA cert to the end of the cacert.pem file you downloaded.
Previous:
fsockopen doesn't support stream contexts, so use stream_socket_client instead. It returns a resource that can be used with all the commands that fsockopen resources can.
This should be a drop in replacement for the snippet you have in your question:
<?php
$contextOptions = array(
'ssl' => array(
'verify_peer' => true, // You could skip all of the trouble by changing this to false, but it's WAY uncool for security reasons.
'cafile' => '/etc/ssl/certs/cacert.pem',
'CN_match' => 'example.com', // Change this to your certificates Common Name (or just comment this line out if not needed)
'ciphers' => 'HIGH:!SSLv2:!SSLv3',
'disable_compression' => true,
)
);
$context = stream_context_create($contextOptions);
$fp = stream_socket_client("tcp://{$host}:{$port}", $errno, $errstr, 20, STREAM_CLIENT_CONNECT, $context);
if (!$fp) {
echo "$errstr ({$errno})<br />\n";
}else{
$this->request = 'POST '.substr($this->url, strlen($this->host)).' HTTP/1.1'.$crlf
.'Host: '.$this->host.$crlf
.'Content-Length: '.$content_length.$crlf
.'Connection: Close'.$crlf.$crlf
.$body;
fwrite($fp, $this->request);
while (!feof($fp)) {
$this->response .= fgets($fp);
}
fclose($fp);
}
I faced a similar issue during work with Ubuntu 16.04 by using Docker. In my case that was a problem with Composer, but error message (and thus the problem) was the same.
Because of minimalist Docker-oriented base image I had missing ca-certificates package and simple apt-get install ca-certificates helped me.
Add
$mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
));
before
mail->send()
and replace
require "mailer/class.phpmailer.php";
with
require "mailer/PHPMailerAutoload.php";
The problem is in new PHP Version in macOS Sierra
Please add
stream_context_set_option($ctx, 'ssl', 'verify_peer', false);
In my case, I was on CentOS 7 and my php installation was pointing to a certificate that was being generated through update-ca-trust. The symlink was /etc/pki/tls/cert.pem pointing to /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem. This was just a test server and I wanted my self signed cert to work properly. So in my case...
# My root ca-trust folder was here. I coped the .crt file to this location
# and renamed it to a .pem
/etc/pki/ca-trust/source/anchors/self-signed-cert.pem
# Then run this command and it will regenerate the certs for you and
# include your self signed cert file.
update-ca-trust
Then some of my api calls started working as my cert was now trusted. Also if your ca-trust gets updated through yum or something, this will rebuild your root certificates and still include your self signed cert. Run man update-ca-trust for more info on what to do and how to do it. :)
Firstable, make sure that you Antivirus software doesn't block SSL2.
Because I could not solve a problem for a long time and only disabling the antivirus helped me
I used the following script to check the issue
<?php
$url = "mail.example.com";// your host which has issue
$orignal_parse = parse_url($url, PHP_URL_HOST);
$get = stream_context_create(array("ssl" => array("capture_peer_cert" => TRUE)));
$read = stream_socket_client("ssl://".$url.":993", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $get);
if (!$read) {
// ssl connection failed for some reason
// could be a certificate error or failure to connect on port 443
echo "Failed to connect to site. Error {$errno}: {$errstr}\n";
} else {
$cert = stream_context_get_params($read);
$certinfo = openssl_x509_parse($cert['options']['ssl']['peer_certificate']);
var_dump($certinfo);
}
?>
I was getting below error
PHP Warning: stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed
Updated ca certificates and then ran reinstall that helped
yum reinstall ca-certificates
You mention the certificate is self-signed (by you)? Then you have two choices:
add the certificate to your trust store (fetching cacert.pem from cURL website won't do anything, since it's self-signed)
don't bother verifying the certificate: you trust yourself, don't you?
Here's a list of SSL context options in PHP:
https://secure.php.net/manual/en/context.ssl.php
Set allow_self_signed if you import your certificate into your trust store, or set verify_peer to false to skip verification.
The reason why we trust a specific certificate is because we trust its issuer. Since your certificate is self-signed, no client will trust the certificate as the signer (you) is not trusted. If you created your own CA when signing the certificate, you can add the CA to your trust store. If your certificate doesn't contain any CA, then you can't expect anyone to connect to your server.
If you are using macOS sierra there is a update in PHP version. you need to have Entrust.net Certificate Authority (2048) file added to the PHP code. more info check accepted answer here Push Notification in PHP using PEM file
Have you tried using the stream_context_set_option() method ?
$context = stream_context_create();
$result = stream_context_set_option($context, 'ssl', 'local_cert', '/etc/ssl/certs/cacert.pem');
$fp = fsockopen($host, $port, $errno, $errstr, 20, $context);
In addition, try file_get_contents() for the pem file, to make sure you have permissions to access it, and make sure the host name matches the certificate.

Curl failed: NSS: client certificate not found (nickname not specified) - On Centos 7

I know this has been asked on SO before but I think my situation is a little bit different:
When I'm trying to use curl inside PHP I receive the following error when trying to interact with apples push notification service (https://api.push.apple.com/3/device/)
Curl failed: NSS: client certificate not found (nickname not specified)
This is due to the fact that on centos, php is build with curl that uses NSS instead OpenSSL.
What I tried so far:
Recompiling curl (worked! Binary is able to perform the call, but php is not)
Recompiling php (didnt work, as it requires curl-devel to be installed, which might link to NSS again)
So my next approach is to fix this NSS problem, but it turns out NSS is a very bad piece of software as just a simple rename of an imported lets-ecnrypt certificate doesnt work.. ..
Could someone please explain me how I could fix this? I already tried importing a lets encrypt certificate into the NSS database stored in /etc/pki/nssdb, that worked - but unfortunately the certificate is not recognized in PHP, even if I provide its nickname in CURLOPT_SSLCERT => 'nickname'.
Maybe this is because it has special characters inside its nickname which i cannot change as NSS fails to rename (lol).
When I directly try to provide certificates in php using
CURLOPT_SSLCERT => $certFile,
CURLOPT_SSLKEY => $keyFile,
CURLOPT_CAINFO => $caCertFile
I get:
Curl failed: Peer's Certificate issuer is not recognized.
I also turned of peer verification by
CURLOPT_SSL_VERIFYPEER => FALSE
ending in
Curl failed: security library failure
Is there anybody out there who could teach me how to fix it or how to build php on centos with builting curl using openssl?
BR,
Finally I got this working, here is what I did:
Recompiled curl with openssl and put the libcurl.so.4 in a new folder /home/mylibs/
Copied all libs from /usr/lib to /home/mylibs/ while not replacing my libcurl.so.4
Located the system's php-cgi binary, renamed it to php-cgi-real
Created a blank file php-cgi
#! /bin/bash
export LD_PRELOAD=/home/mylibs/libcurl.so.4
exec php-cgi-real "$#"
Restarted the service
Done!

SoapServer::SoapServer(): SSL operation failed with code 1

i have exposed a couple of web services through Yii. After upgrading to PHP 5.6.33 from PHP 5.5.x, i face the following error
SoapServer::SoapServer(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
the error occurs on line 166 on framework/web/services/CWebService.php (1.1.19) so far i haven't found any work around, the options property is protected and don't know how to bypass this issue, but still http://php.net/manual/en/soapserver.soapserver.php doesn't seem to support same options as SoapClient
$options["stream_context"] = stream_context_create([
"ssl" => [
// set some SSL/TLS specific options
"verify_peer" => false,
"verify_peer_name" => false,
"allow_self_signed" => true
]]);
We ended up that it was a server configuration issue. The production servers didn't faced this issue since the certificate was signed from a known authority however in the private servers, we needed to edit the php.ini file
openssl.cafile = "/etc/path/to/pem/file.pem"
I got the error too on Linux (Ubuntu) with PHP7.2 when I tried to create SoapServer in my development environment.
If you do not want to set the PHP openssl.cafile globally, just copy your Root CA into the correct folder and update certificates:
sudo cp my_root_ca.pem /usr/share/ca-certificates/my_root_ca.crt
sudo dpkg-reconfigure ca-certificates
sudo update-ca-certificates
While reconfigure ca-certificates you need to select your own certificate and activate it.
(If you do not need your Root CA anymore in your develop environment just reconfigure certificates again, unselect your CA from the list and finally update certificates.)

Unable to Connect to ssl

I have configured the openssl with wamp (Apache server). But while I using gdata api I'm getting following error.
( ! ) Fatal error: Uncaught exception 'Zend_Http_Client_Adapter_Exception' with message ' in C:\Zend_1_11_11\library\Zend\Http\Client\Adapter\Socket.php on line 234
( ! ) Zend_Http_Client_Adapter_Exception: Unable to Connect to ssl://accounts.google.com:443. Error #10060: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. in C:\Zend_1_11_11\library\Zend\Http\Client\Adapter\Socket.php on line 234
Somebody help me on this...
Solution only for Windows users:
Check the SSL module is enabled in php.ini:
extension=php_openssl.dll
Answer from Mikhail does not work for me as I run it in Alpine Linux and .dll is only windows extension. Do not use it outside of Windows, it only adds warnings.
Solved my problem:
I had a self-signed certificate that was unable to establish connection.
To check that it is problem you can make a request:
wget way:
// not working:
wget https://accounts.google.com:443
// working:
wget https://accounts.google.com:443 --no-check-certificate
or curl way:
// not working:
curl https://accounts.google.com:443
// working:
curl https://accounts.google.com:443 -k
To temporary solve it in my dev docker container, I have added use of curl adapter and no check for certificate to the code:
$config = array(
'adapter' => 'Zend_Http_Client_Adapter_Curl',
'curloptions' => [CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false]
);
$client = new Zend_Http_Client('https://example.com', $config);
You are behind proxy, so you can not connect directly.Try to use Zend/Http/Client/Adapter/Proxy.php instead of Zend\Http\Client\Adapter\Socket.php
If you on Ubuntu try add in your php.ini
openssl.capath=/etc/ssl/certs
For more info read this issue

Categories