I'm running the next script from my local host and the production server, and Im getting different outputs. Anyone knows why am I getting that false from my localhost?
<?php
$host = 'ssl://mail.companyname.org';
$port = 993;
$error = 0;
$errorString = "";
var_dump(fsockopen($host, $port, $error, $errorString, 30));
var_dump($errorString);
var_dump($error);
Local host output:
bool(false)
Production server output:
resource(4) of type (stream)
UPDATE: after the comments/answer I have modified the code and now Im getting this output on my local host:
PHP Warning: fsockopen(): SSL operation failed with code 1. OpenSSL
Error messages: error:1416F086:SSL
routines:tls_process_server_certificate:certificate verify failed in
/tmp/test.php on line 7 PHP Warning: fsockopen(): Failed to enable
crypto in /tmp/test.php on line 7 PHP Warning: fsockopen(): unable to
connect to ssl://mail.twmdata.org:993 (Unknown error) in /tmp/test.php
on line 7 bool(false) string(0) "" int(0)
it seems this is problem with server certificate :
first you can check if your server certificate and its chains are valid by this:
https://www.sslshopper.com/ssl-checker.htm
if somethings were wrong in ssl-checker?
you can try to correct SSL certificate configs in companyname.org
if you succeed and error was persists ?
you have to add Certificate files manually.
if you have a self-signed certificate:
you have to add Certificate files manually.
if you dont have certificate nor you dont care about man-in-the-middle attack,
you can still use SSL without Certificate.
turn off php fsock Certificate check (not recommended)
its recommended to have a certificate at least a self-signed. if you have a self-signed try 1 solution.
I have found the Problem
You have exposed your Domain name in your PHP Warning Log, so i have checked your domain SSL.
after i check your company`s domain certificate using this tool:
https://www.sslshopper.com/ssl-checker.html#hostname=twmdata.org
it had 2 errors with your certificates:
This certificate has expired (0 days ago). Renew now.
None of the common names in the certificate match the name that was entered (twmdata.org). You may receive an error when accessing this site in a web browser.
so it seems you have to renew your certificate first
Update:
i have found this answer maybe helpful
https://stackoverflow.com/a/40962061/9287628
it suggested to use
stream_context_create(['ssl' => [
'ciphers' => 'RC4-MD5'
]])
as #ChrisHaas suggested connecting with stream_context_create and stream_socket_client brings you a lot of option if you want to dictate the cert directory or you want to turn off certificate check.
Per the documentation for fsockopen
The function stream_socket_client() is similar but provides a richer set of options, including non-blocking connection and the ability to provide a stream context.
Basically, fsockopen is very low-level but without many options, or, arguably, "sane defaults".
Instead, you can switch to stream_socket_client which will allow you to specify a context as the last parameter, and that object has many options, including a dedicated one with over a dozen options specific to SSL. The object created from this function is compatible with fwrite and other functions, so it should do everything you are hoping for.
$context = stream_context_create([/*Options here*/]);
$connection = stream_socket_client($host, $errno, $errorString, 30, null, $context);
Now, what options should you use?
The worst option that might work is probably verify_peer. I say "worst" because you are throwing away the verifiability part of SSL/TLS and only using it for encryption, and doing this will make you susceptible to MitM attacks. However, there's a place and time for this, so you could try it if the other options are too complicated.
$context = stream_context_create(['ssl' => ['verify_peer' => false]]);
$connection = stream_socket_client($host, $errno, $errorString, 30, null, $context);
Instead, I'd recommend using either cafile or capath which do the same thing except the former is for a file while the latter is for a directory.
$context = stream_context_create(['ssl' => ['verify_peer' => true, 'cafile' => '/path/to/file']]);
$connection = stream_socket_client($host, $errno, $errorString, 30, null, $context);
What certs should you use? We use this library to pull in recent CA files on a periodic basis, very convenient. There's a little bit of setup that's per-project but once you get it it goes pretty fast. See this for pulling in a CA file at a well-known location.
One other last option is local_cert which you can use with a PEM file that holds the certificate and private key from the server, if you have access to that.
EDIT
The cert on mail.twmdata.org:993 is different than the web server's cert that other people are talking about, which is generally a best practice. You can inspect that cert using:
openssl s_client -connect mail.twmdata.org:993 -servername mail.twmdata.org
If you do that, you'll see that the server has a self-signed cert which you can get around by setting the verify_peer option to false.
Remove the # symbol. You are hiding error messages that might tell you what the problem is. You should also set a variable in the errorno argument to fsockopen() and echo it for debugging.
My guess would be that you haven't installed PHP with SSL support on your local server. See here.
Companyname.org might also block requests from your local server that are allowed from the production server.
Related
I’ve been trying to access a HTML page on my own server over HTTPS. So script returns following errors:
PHP Version is 5.6.38
Warning: file_get_contents(): SSL operation failed with code 1.
OpenSSL Error messages: error:14090086:SSL
routines:ssl3_get_server_certificate:certificate verify failed in
/home/user/public_html/index.php on line 11
Warning: file_get_contents(): Failed to enable crypto in
/home/user/public_html/index.php on line 11
Warning: file_get_contents(https://myniceurl.com/file.html): failed to
open stream: operation failed in /home/user/public_html/index.php on
line 11
<?php
$contextOptions = [
'ssl' => [
'verify_peer' => true,
'cafile' => '/etc/pki/tls/cert.pem',
]
];
$context = stream_context_create($contextOptions);
$data = file_get_contents('https://myniceurl.com/file.html', false, $context);
I've tried many solutions from different forums, but none helped. When I try to fetch a page from other sites over HTTPS it works, even I tried to fetch (over HTTPS) the same HTML page on my local machine, it worked properly. I thought the server cannot communicate itself. For investigation purposes, I changed HTTP and it worked properly.
I have tried so far:
Downloaded certificate bundle, added it php.ini file
verify_peer = true and CAfile for stream_context_create
I also confirm that allow_url_fopen is working. Due to the specialized nature of this problem; I’m not finding a lot of information for help. Have any of you come across something like this? Thanks.
I found the reason why this is not working.
It was because of Cloudflare SSL/TLS encryption mode. My selected option was Full strict.
As seen from the image the request has to hit Cloudflare request first, then Cloudflare forwards it to the origin server. However, I added my IP address and hostname to /etc/hosts file, that is why the request was not going out from my network and it causes SSL verification problems.
Once upon a time, there was a normalish error in PHP land:
Warning: ftp_nlist(): data_accept: SSL/TLS handshake failed in [path] on line 29
But here's the catch, "line 29" is not the connection or login, note how it referenced the ftp_nlist() function:
$ftp = ftp_ssl_connect($cred['host'], $cred['port'], 180);
if (!ftp_login($ftp, $cred['user'], $cred['pass'])) {die("Login Failed");}
ftp_pasv($ftp, true);
$files = ftp_nlist($ftp, '');
OpenSSL is compiled and enabled in phpinfo() as suggested here:
ftp_login() : SSL/TLS handshake failed
Other posts I've seen all seem to reference error in the ftp_ssl_connect() or ftp_login() commands which work for me. What can I check when ftp_login() returns true?
Or... are there any logs to get more details on what is wrong?
I'm using php 5.3.29. The code does work properly on my desktop (php 7), but I'm hoping I don't have to upgrade the server to 7 for this to work
12-28-2017 update:
Upgrading to 5.6 resolved, so looks like Martin is on point.
Although this question is quite old, but in case someone else hits this problem:
If your ftp_ssl_connect and ftp_login works fine but functions like ftp_nlist, ftp_put, ftp_fput don't works the problem might be that your FTP server is using port 21 for Connection but different port ranges for data transfer, that explains why you can connect and login but you can't upload or download data, and you need to allow the Out-going connections to those port range in your firewall
The ftp_nlist opens a data connection. That connection needs TLS/SSL handshake too.
As the control connection handshake succeeded, the problem indeed cannot be with an absent TLS/SSL support in PHP. Neither the problem can be with anything like the server and PHP not being able to find a cipher to agree on.
When TLS/SSL handshake on data connection fails after handshake on control connection succeeded, it's quite usually because the client (PHP) did not reuse TLS/SSL session from control connection on the data connection (see Why is session reuse useful in FTPS?). Some servers do require that. PHP supports the reuse only since 5.6.26. See PHP Bug 70195. So make sure you use that version of PHP at least.
I'm using Gallery 3 for image upload.
When I use https://domain the upload works fine. But as I use https://domain Gallery3 is not able to make a connection.
Errors : **fsockopen(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in fileName**
**fsockopen(): Failed to enable crypto in finleName**
**fsockopen(): unable to connect to ssl://domain:443 (Unknown error) in /**
Below are the observations:
The URL to connect becomes ssl://domain having port 443
fsockopen fails to make a connects and throws error.
What is going wrong ? I have a valid https certificate on my server and also openssl is installed.
Anything else required ?
PHP 5.6+ updated the default ciphers based on the Mozilla cipher recommendations. There is more detail about what ciphers are used in the RFC for improving tls defaults. Overall this change removed support for Anonymous Diffie-Hellman and RC4, it's likely your server still uses RC4.
There are two options:
Update the ciphers your server is using based on the Mozilla ciper recommendations
Update the gallery3 code to use RC4, since it hasn't been updated since 2013 you can probably do this option without too much concern
For option 2 it looks like the call is done in gallery3/modules/gallery/helpers/MY_remote.php on line 73/74:
$handle = fsockopen(
$url_components['fsockhost'], $url_components['port'], $errno, $errstr, 5);
You can change this to use stream_socket_client which is compatible with fsockopen:
$context = stream_context_create(['ssl' => [
'ciphers' => 'RC4-MD5'
]]);
$timeout = ini_get('default_socket_timeout');
$handle = stream_socket_client('ssl://' . $url_components['fsockhost'] . ':' . $url_components['port'], $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $context);
I'm busy with a curl php library which needs to connect to an FTPS server.
I have this semi working... If I connect to ftp://domain.com then it does work. If I watch the comms on the server with tcpflow I see it logging in with AUTH TLS and and all the comms is encrypted. The file is uploaded so all's good..
What I'm unsure of is if its valid to try connecting instead to ftps://domain.com?
The reason I'm asking is because if I change the protocol from ftp to ftps in curl then the login fails and the server (watching tcpflow comms) says that the login has failed:
191.101.002.204.00021-088.099.012.154.51630: 530 Please login with USER and PASS.
Also, when I watch the comms when trying to connect to ftps:// I don't see the client issuing the AUTH TLS command as it does with plain ftp://
The problem I have is that it seems that my client's FTP server we have to ultimately connect to doesn't seem to allow connections without the ftps:// protocol.
If I connect using lftp I can do so using ftps:// but then I have to disable ssl:
set ftp://ssl-allow no
If I try the lftp connection using ftp:// it just hangs on the login command...
I'm not really that experienced with FTP or TLS / SSL so I don't know if its maybe because the client's server doesn't have the certificates set up correctly..
Here is a portion of my curl code which works with ftp:// but not ftps://
// Works
$url = "ftp://proxy.plettretreat.co.za/";
// Does not work
$url = "ftps://proxy.plettretreat.co.za/";
$port = 990;
$username = "ftpuser";
$password = "pass";
$filename = "/test.php";
$file = dirname(__FILE__)."/test.php";
$c = curl_init();
// check for successful connection
if ( ! $c)
throw new Exception( 'Could not initialize cURL.' );
$options = array(
CURLOPT_USERPWD => $username.':'.$password,
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_SSL_VERIFYHOST => 0,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_BINARYTRANSFER => 1,
CURLOPT_FTP_SSL => CURLFTPSSL_ALL, // require SSL For both control and data connections
CURLOPT_FTPSSLAUTH => CURLFTPAUTH_TLS, // let cURL choose the FTP authentication method (either SSL or TLS)
CURLOPT_UPLOAD => true,
CURLOPT_PORT => $port,
CURLOPT_TIMEOUT => 30,
);
Another thing I'm unsure of is that my client has given me an IP address to connect to.. Can an IP address be used in ftps? I would have thought that certificates are mostly certifying a domain name?
tl;dr
1) Can I use ftps://domain.com to connect using CURL PHP?
2) If I can use ftps:// in curl, then how do I get curl to log in (issue auth tls command)?
3) Can an FTP server use SSL / TLS with only an IP address?
Thanks...
John
Many many hours of struggling led me to an eventual answer.
Part of the answer was that the client server and the FTP server had "overly" strict firewall rules blocking the passive ports.
I was getting the following error:
Error no: 35; Error: SSL connect error.
Error 35 was because of the firewall rules. Once those were relaxed that error went away, but as a note, you will also see this error if the client machine is NAT'ed. If it is you need to set the curl option:
curl_setopt($c, CURLOPT_FTPPORT, '1.2.4.5' ); // change to your actual IP.
This tells the FTP server where to open up its data channel (instead of trying to open it to the client server's internal address).
Anyway, once the firewall and FTPPORT options were set I got:
Error no: 30; Error: bind(port=0) failed: Cannot assign requested address
This one baffled me for quite a while as everything looked correct.
I eventually stumbled upon a few thread here and elsewhere which talk about an issue with older versions of Curl using NSS for its encryption. I checked and I was using libcurl version 7.19.7 (about 8 years old) and sure enough it uses NSS...
I updated my Curl using this guide: https://www.digitalocean.com/community/questions/how-to-upgrade-curl-in-centos6.
That updated me to libcurl 7.52.1 which uses OpenSSL and lo and behold, my app started working...
So, if you're having issues connecting curl-ftp to a FTPS server, check the FTPPORT (passive IP) if you're NAT'ed, check your firewall, but most importantly, check your curl:
<?php
print print_r(curl_version());
?>
I hope this helps someone..
Here is a simple PHP script that opens an SSL socket ready to send HTTP requests:
$contextOptions = array();
$socketUrl = 'ssl://google.com:443';
$streamContext = stream_context_create($contextOptions);
$socket = stream_socket_client($socketUrl, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $streamContext);
if (!$socket || $errno !== 0) {
var_dump($socket, $errstr);
exit;
}
var_dump($socket);
exit('Socket created.');
This works - I've just tested it - but there is no validation against a trusted CA store.
We can modify that script to use PHP's SSL Context options:
$contextOptions = array(
'ssl' => array(
'cafile' => 'C:\xampp\cacerts.pem',
'CN_match' => '*.google.com', // CN_match will only be checked if 'verify_peer' is set to TRUE. See https://bugs.php.net/bug.php?id=47030.
'verify_peer' => TRUE,
)
);
$socketUrl = 'ssl://google.com:443';
$streamContext = stream_context_create($contextOptions);
$socket = stream_socket_client($socketUrl, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $streamContext);
if (!$socket || $errno !== 0) {
var_dump($socket, $errstr);
exit;
}
var_dump($socket);
exit('Socket created.');
As long as the 'cafile' exists and has the correct CA then this example also works...
...but how can we do this without hard-coding a CA filename/filepath? We're trying to create something that verifies SSL certificates OS-independently without requiring separate configuration for each server that runs this script.
I know Linux has a directory for CAs that we could put as the 'capath'. What about Windows? Where does it store its trusted CAs? I searched and these unfortunately seemed to be in the registry, so is there no way we can access them from PHP? What about other OSs?
A losing battle ...
There is no way to conduct a secure encrypted transfer in PHP without manually setting the "cafile" and "CN_match" context options prior to PHP 5.6. And unfortunately, even when you do set these values correctly your transfers are still very likely to fail because pre-5.6 versions do not consult the increasingly popular SAN (subjectAltName) extension present in peer certificates when verifying host names. As a result, "secure" encryption via PHP's built-in stream wrappers is largely a misnomer. Your safest bet (literally) with older versions of PHP is the curl extension.
Regarding windows certs ...
Windows uses its own cert store and encodes its certificates in different format from OpenSSL. By comparison, openssl applications use the open .PEM format. Pre-5.6 versions of PHP are unable to interface with the windows cert store in any way. For this reason it's impossible to have reliable and safe encryption in a cross-OS way using the built-in stream wrapper functionality.
PHP 5.6 is a major step forward
New openssl.cafile and openssl.capath php.ini directives allow you to globally assign cert locations without having set them in every stream context
All encrypted streams verify peer certs and host names by default and the host name is automatically parsed from the URI if no "CN_match" context option is supplied.
Stream crypto operations now check peer cert SAN entries when verifying host names
If no CA file/path is specified in the stream context or php.ini directives PHP automatically falls back to the operating system's cert stores (in Windows, too!)
By way of example, this is all you'd need to do to connect securely to github.com in PHP-5.6:
<?php
$socket = stream_socket_client("tls://github.com:443");
Yes. That really is it. No fussing about with context settings and verification parameters. PHP now functions like your browser in this regard.
More reading on the subject
These PHP 5.6 changes are only the tip of the iceberg with regard to SSL/TLS improvements. We've worked hard to make 5.6 the most secure PHP release to date with regard to encrypted communications.
If you'd like to learn more about these new features there is a wealth of information available via the official channels
[RFC] Improved TLS Defaults
[RFC] TLS Peer Verification
5.6 NEWS file
5.6 UPGRADING file
A note on SAN matching in 5.4/5.5
We are working to backport at least the SAN matching to the 5.4 and 5.5 branches as it's extremely difficult to use the encryption wrappers in any meaningful way (as a client) without this functionality. Though this backporting work is largely dependent on my available free time as a volunteer, upvoting this answer might certainly help it happen sooner :)