In PHP7.0, when using fsockopen to connect to open a https connection (hosted in same
host), using a host name like tls://foo.localhost, I am getting an error that
looks like
fsockopen(): Peer certificate CN="bar" did not match expected CN="foo.localhost"
Connection is not opened.
Same code worked in PHP 5.5 (that is less strict checking vertificates). I do
not really care about verifying certificates (this code runs in a unit test and
integration suite, connecting only to localhost). Tests need to be run against
http and https, though.
I know how to disable those checks when using file_get_contents.
How can I disable the peer certificate verification when using fsockopen?
fsockopen don't provide method to ignore peer certificate errors.
You have to use stream_socket_client with context. Available ssl/tls context options are available here.
Example of opening socket without peer verification
$context = stream_context_create([
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false
]
]);
$hostname = "tls://foo.localhost:8123";
$socket = stream_socket_client($hostname, $errno, $errstr, ini_get("default_socket_timeout"), STREAM_CLIENT_CONNECT, $context);
Related
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.
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..
I'm trying to send an email with php and swiftmailer, using STARTTLS, but I'm getting a certificate error. I have root access to the SMTP server, and the certificate used is self-signed.
I'm using Debian on both machines (web server and smtp server)
PHP message: PHP Warning: stream_socket_enable_crypto(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in [..]/lib/classes/Swift/Transport/StreamBuffer.php on line 97
PHP message: PHP Fatal error: Uncaught exception 'Swift_TransportException' with message 'Unable to connect with TLS encryption' in [..]/lib/classes/Swift/Transport/EsmtpTransport.php:294
Do I need to add my own certificate somewhere to get it accepted? Or is this some OpenSSL configuration error?
Editor's note: disabling SSL verification has security implications. Without verification of the authenticity of SSL/HTTPS connections, a malicious attacker can impersonate a trusted endpoint (such as GitHub or some other remote Git host), and you'll be vulnerable to a Man-in-the-Middle Attack.
Be sure you fully understand the security issues before using this as a solution.
Swiftmailer has now been updated to include an option for this. It can now be solved using the setStreamOptions method from your Swift_SmtpTransport instance rather than editing the swift class.
$transport = Swift_SmtpTransport::newInstance('smtp.server.com', 123, 'tls')
->setUsername('username')
->setPassword('password')
->setStreamOptions(array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false)));
I got the same problem using Swiftmailer in Laravel.
Looks like there is no option for this in Swiftmailer. Clean solution would be to add your own root CA to your server and sign your mail server certificate with this CA. The certificate would be valid after this. See for example this tutorial.
Editor's note: disabling SSL verification has security implications. Without verification of the authenticity of SSL/HTTPS connections, a malicious attacker can impersonate a trusted endpoint (such as GitHub or some other remote Git host), and you'll be vulnerable to a Man-in-the-Middle Attack.
Be sure you fully understand the security issues before using this as a solution.
Anyway, a quick dirty hack you should not use would be to edit swiftmailer\swiftmailer\lib\classes\Swift\Transport\StreamBuffer.php. In _establishSocketConnection() line 253 replace:
$options = array();
with something like this:
$options = array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false));
This will change the ssl options of stream_context_create() (a few lines below $options):
$this->_stream = #stream_socket_client($host.':'.$this->_params['port'], $errno,
$errstr, $timeout, STREAM_CLIENT_CONNECT, stream_context_create($options));
Editor's note: disabling SSL verification has security implications. Without verification of the authenticity of SSL/HTTPS connections, a malicious attacker can impersonate a trusted endpoint (such as GitHub or some other remote Git host), and you'll be vulnerable to a Man-in-the-Middle Attack.
Be sure you fully understand the security issues before using this as a solution.
You do not need to edit /vendor files. You can specify (undocumented) options in your config/mail.php file:
'stream' => [
'ssl' => [
'allow_self_signed' => true,
'verify_peer' => false,
'verify_peer_name' => false,
],
],
You can check it yourself in vendor/laravel/framework/src/Illuminate/Mail/TransportManager.php on line ~50:
...
if (isset($config['stream'])) {
$transport->setStreamOptions($config['stream']);
}
...
Needless to say, circumventing peer verification has huge security implications (read vulnerabilities). I imagine this solution for some dev or local environment, never in production or even in an Internet/Publicly available app.
Editor's note: disabling SSL verification has security implications. Without verification of the authenticity of SSL/HTTPS connections, a malicious attacker can impersonate a trusted endpoint (such as GitHub or some other remote Git host), and you'll be vulnerable to a Man-in-the-Middle Attack.
Be sure you fully understand the security issues before using this as a solution.
For me, I had to add $transport->setStreamOptions(array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false, 'verify_peer_name' => false))); to the Mailer.php file, see:
/**
* Returns the SMTP transport
*
* #return \Swift_SmtpTransport
*/
protected function getSmtpInstance(): \Swift_SmtpTransport {
$transport = new \Swift_SmtpTransport();
$transport->setTimeout($this->config->getSystemValue('mail_smtptimeout', 10));
$transport->setHost($this->config->getSystemValue('mail_smtphost', '127.0.0.1'));
$transport->setPort($this->config->getSystemValue('mail_smtpport', 25));
if ($this->config->getSystemValue('mail_smtpauth', false)) {
$transport->setUsername($this->config->getSystemValue('mail_smtpname', ''));
$transport->setPassword($this->config->getSystemValue('mail_smtppassword', ''));
$transport->setAuthMode($this->config->getSystemValue('mail_smtpauthtype', 'LOGIN'));
}
$smtpSecurity = $this->config->getSystemValue('mail_smtpsecure', '');
if (!empty($smtpSecurity)) {
$transport->setEncryption($smtpSecurity);
}
$streamingOptions = $this->config->getSystemValue('mail_smtpstreamoptions', []);
if (is_array($streamingOptions) && !empty($streamingOptions)) {
$transport->setStreamOptions($streamingOptions);
}
/* EDIT - allow self-signed mail cert */
$transport->setStreamOptions(array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false, 'verify_peer_name' => false)));
/* EDIT end */
return $transport;
}
I got this from another link, can't find it now.
One think that I did extra to the other answers was to specify the 'verify_peer_name' => false
I wrote a small SIP client for a special purpose.
Basically it connects to port 5060 using function fsockopen()
$fp = fsockopen("10.0.0.1", 5060, $errno, $errstr, 30);
and then basically reads and writes SIP commands using fread() and fwrite().
Now my SIP service operator wants us clients to use SIPS which is
basically SIP over TLS. I've spent hours looking for information
on how to connect to a port with TLS using PHP but without any
success. Apparently the fsockopen() supports TLS to an extent but
when I replaced the above with:
$fp = fsockopen("tls://10.0.0.1", 5061, $errno, $errstr, 10);
I get nothing. I can connect to the server from my shell with with OpenSSL client:
$ openssl s_client -connect 10.0.0.1:5061
And I can communicate with the SIP server through that connection without problems. OpenSSL support is compiled in the PHP.
My problem is that I can't set up the TLS connection with the server in PHP. I noticed in some forums that in older versions of PHP it was possible to build and use the SSL context with fsockopen() but apparently not anymore, since I get an error about too many parameters.
I also tried using stream_context_create() with stream_context_set_option() but I get no replies from the server:
$context = stream_context_create();
$result=stream_context_set_option($context, 'ssl', 'verify_peer', 'TRUE');
$result=stream_context_set_option($context, 'ssl', 'cafile', 'cert.cer');
$result=stream_context_set_option($context, 'ssl', 'verify_depth', '5');
$fp = stream_socket_client('tls://'.$host.':'.$port, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);
but I still can't get any replies or errors from the server. What is the recommended and working way of using TLS in PHP?
This is enough to open a TLS connection:
$context = stream_context_create();
$fp = stream_socket_client('tls://'.$host.':'.$port, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context)
if the certificates are in their place. If they are not, follow the instructions linked by Filippos.
I think some of your options are wrong for validating self signed certificates; the following should be enough to make it work:
$context = stream_context_create([
'ssl' => [
'verify_peer' => true,
'allow_self_signed' => true,
'local_cert' => 'cert.cer',
],
]);
I just recently encountered this error, debugging here and there for connection problem or proxy problem, finally found the culprit ... and the solution was to install php-pecl-crypto extension.
My machine is centos 7 using remi-repo for PHP
You will also need to install the appropriate certificates to get TLS working. Check this SO question for an example of how to use your key files with regular TLS connections.
Also, check the specs of SIPS itself in RFC 5630.