SNI issues connecting to Google LDAP server - php

I'm trying to connect to Google's LDAP server with a cert, the basic code is
ldap_set_option(null, LDAP_OPT_DEBUG_LEVEL, 7);
$ldap = ldap_connect('ldaps://ldap.google.com', 636);
putenv('LDAPTLS_REQCERT=demand');
putenv("LDAPTLS_CACERT=/etc/ssl/certs/ca-certificates.crt");
putenv("LDAPTLS_CERT=" . path('Google_2024_01_22_49615.crt'));
putenv("LDAPTLS_KEY=" . path('Google_2024_01_22_49615.key'));
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
ldap_start_tls($ldap);
ldap_sasl_bind($ldap, null, '', 'EXTERNAL');
$resuts = ldap_search($ldap, 'dc=foo,dc=com', 'uid=*');
print_r(ldap_get_entries($ldap, $searchResults));
It fails on ldap_start_tls with Unable to start TLS: Can't contact LDAP serer, looking into this further I can see the real error is TLS: peer cert untrusted or revoked (0x42) which is caused by hostname (ldap.google.com) does not match common name in certificate (invalid2.invalid). Google returns this cert to indicate that SNI isn't supported (https://support.google.com/a/answer/9190869)
But my PHP version is 7.1.33 compiled in Dec 2020 on Ubuntu 20.04, with OpenLDAP 20449 (SASL Support enabled) and OpenSSL 1.1.1i. So why would I not have SNI supported? Elsewhere I see people using LDAPTLS_REQCERT=never to bypass this problem, but as Google requires a TLS cert & SASL I need to use LDAPTLS_REQCERT=demand or PHP won't let me use the SASL EXTERNAL auth mechanism (https://gist.github.com/heiglandreas/8a299a6f47a13ba463c3f2da41c679f7) and I won't be able to authenticate
It's worth noting on the same machine the following command works perfectly, authenticates with SASL EXTERNAL and lists users LDAPTLS_CERT=Google_2024_01_22_49615.crt LDAPTLS_KEY=Google_2024_01_22_49615.key ldapsearch -X -W -D uid=MyUUID,ou=Users,dc=foo,dc=com -H ldaps://ldap.google.com:636 -b dc=foo,dc=com
I have also tried using the PHP options LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_CACERTDIR, LDAP_OPT_X_TLS_CACERTFILE, LDAP_OPT_X_TLS_KEYFILE and LDAP_OPT_X_TLS_CERTFILE but they don't make a difference

My problem here was using ldap_start_tls and ldap_sasl_bind (or ldap_bind) at the same time when you only need one to open the connection, as-well as using ldap_set_option with the resource like ldap_set_option($ldap, LDAP_OPT_X_TLS_KEYFILE, $keyFilePath); when it should be used on null like ldap_set_option(null, LDAP_OPT_X_TLS_KEYFILE, $keyFilePath); since it's overriding a /etc/ldap/ldap.conf variable.
Following https://www.php.net/manual/en/function.ldap-get-option.php#124601 was useful to figuring this out

Related

Connect an active directory or LDAP with PHP

I am trying to connect the active directory or LDAP of window with an application (GLPI) made in PHP.
Connection parameters:
Connecting with the server:
$ds = ldap_connect($host, $port) // return true
#ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
#ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
#ldap_set_option($ds, LDAP_OPT_DEREF, $deref_options);
Relate connection to server and user and password
ldap_bind ($ds, $ login, $ password)
returns me:
"Can not contact LDAP server"
I want to know what can happen with that error message, since in the first method it returns true to me, which means that if it connects to the server.
RootDN This is fine and has all the permissions the user I am using.
The default server is fine and I did ping andtelnet.
Note: I already downloaded LDAPExplorer and established connection without problem.
Does the missing : $ds = ldap_connect ... like how it is in your code?
It should be something like :
$ds = ldap_connect($host, $port);
#ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
#ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
#ldap_set_option($ds, LDAP_OPT_DEREF, $deref_options);
ldap_bind ($ds, $login, $password)
ldap_connect does not connect to the server as is clearly stated in the docs. It merely creates a resource and checks whether the given values are plausible. The actual connection is established with the first command that requires a connection to the server. In this case the ldap_bind.
BTW: The "first method" does not return true but a resource-handle. Only when you pass something absolutely not parseable it will return false. But never true
I'd recommend using an LDAP-URI instead of the $host, $port variation as the PHP-library has to do that otherwise internaly. And it's the only way to f.e. establish an LDAPS-connection.
Ok, the solution to my problem is to upgrade from GLPI version 9.3.0 to 9.3.3.
Suggestions:
For users, what could happen to this, verify the messages that GLPI has informs about pending installation packages. So I opted for the update and the connection worked without problem.
For users who can not update version, verify that apache packages are pending to install or update, also in the installation process in the setup, be very careful installing the entire list that seems pending.
To fix some errors by installing version 9.3.3:
chown -R apache: apache glpi / files
chmod -R 755 glpi / files
chown -R apache: apache config
chmod -R 755 glpi / config
also:
setsebool -P httpd_can_network_connect_db 1
Thank you.

PHP to MySQL using SSL

I have a remote MySQL Server that requires me to use SSL for connections. I can connect to it using my terminal. But when I try to connect to it using PHP, I get the following error:
SSL3_GET_RECORD:wrong version number
It seems like the OPENSSL Handshake fails and the reason could be that my PHP is trying to connect to it using SSL3. The MySQL Server supports only TLSv1.2. Is there a way to force PHP to connect using TLSv1.2 ?
Here is my code used to connect:
<?php
ini_set ('error_reporting', E_ALL);
ini_set ('display_errors', '1');
error_reporting (E_ALL|E_STRICT);
$db = mysqli_init();
mysqli_options ($db, MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, true);
$db->ssl_set(NULL, NULL, '/path/to/ca-cert.pem' , NULL, NULL);
$link = mysqli_real_connect ($db, 'hostname', 'user', 'password', 'dbname', 3306, NULL, MYSQLI_CLIENT_SSL);
if (!$link)
{
die ('Connect error (' . mysqli_connect_errno() . '): ' . mysqli_connect_error() . "\n");
} else {
$res = $db->query('SHOW TABLES;');
print_r ($res);
$db->close();
}
?>
Things I have tried and possible problems:
Seems like openssl version mismatch. I can connect using my terminal and not PHP, so I checked my openssl version in the terminal with the one I get using phpinfo(), they were the same
PHP is possibly using SSL3 to connect, and the server only supports TLSv1.2, I wasn't able to find a way to force PHP connections to MySQL using TLSv1.2
I tried to observe the handshake using tcpdump/Wireshark, but I don't think the process even starts since there is a version mismatch.
I confirmed using "openssl s_client -debug" that the server doesn't support SSL3 which makes me think this is an issue on my computer, but not sure.
The reason I say my client might be using SSL3 is because of SSL3_GET_RECORD, I don't know for sure if I'm right in that too.
So, in short, Help!
Environment:
PHP 7.0.18
MySQL Server Enterprise version 5.7.18
OpenSSL 1.0.2g
OS: Windows 7, Ubuntu 16.04. Tried on both
The problem was the driver that PHP used to connect to MySQL. By default, it is mysqlnd. And I don't think it was being able to connect using a SHA256 or better cipher to my MySQL Server, which is an enterprise version.
The other option for the driver is a libmysql library which Oracle does provide as part of the MySQL Enterprise Server (.deb files). I started with a clean OS(Ubuntu), and compiled PHP with the libmysql provided by Oracle, and then I was able to establish the connection successfully!
More info here

PayPal 14077410 error

I am receiving this error exception:
PayPal\Exception\PayPalConnectionException' with message 'error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
from my test website.
I am using Paypal sdk to run a simple payment (like the example that they have. In my test server locally works just fine).
I have tried various solutions that I found but no luck.
I contacted my web host provider and said that they support tls 1.2 and its a coding problem from my end.
Web server curl versions is : 7.15.5
and openssl : 0.9.8b
From what i searched online many people said that this versions do not support tls 1.2. Did the add backwards capability ?
I also run this test but i am not sure if i am reading it correctly:
Edit :
The server finally confirmed that they are no supporting this and they also said that this server cannot be upgraded so they offered to move me to one that support this. Thank you all for your help.
Support for TLS1.2 was not added in openssl until 1.0.1, 14 Mar 2012.
https://www.openssl.org/news/changelog.html#x19
You need to update SSL on your server, and educate your host, or find a new one.
We faced this back in August (we were at 0.9.8-e-fips-rhel5); updating SSL did the trick.
To add onto what #Kkinsey said, it sounds like your host is using CentOS/RHEL 5 (which is approaching end of life). CentOS 6, while it contains the higher level of openssl, is apparently not capable of automatically negotiating TLS 1.2. CentOS 7 for some reason can.
curl -v https://api-3t.sandbox.paypal.com/nvp
About to connect() to api-3t.sandbox.paypal.com port 443 (#0)
Trying 173.0.82.83... connected
Connected to api-3t.sandbox.paypal.com (173.0.82.83) port 443 (#0)
Initializing NSS with certpath: sql:/etc/pki/nssdb
CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
NSS error -12286
Closing connection #0
SSL connect error
curl: (35) SSL connect error
You have to force PHP's CURL to use TLS 1.2. Once you have upgraded your OpenSSL package (doing this on 0.9.8 WILL BREAK) you'll need to add this to your CURL request
curl_setopt($ch, CURLOPT_SSLVERSION, 6);

LDAP_BIND Can't contact LDAP server

I have a question for you.
My goal is to bind a ldap server with php.
When I try with a terminal ( bash ) I use:
ldapsearch -H ldaps://[server]:[port] -D [dn] -W
It works well.
When I try with a php script
$server = array("ldaps://[server]", "[port]");
$userdn = "[dn]";
$userpw = "[pw]";
$ds = ldap_connect($server[0], $server[1]) or die("ldap server offline");
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
ldap_bind($ds, $userdn, $userpw);
Warning: ldap_bind(): Unable to bind to server: Can't contact LDAP server
I don't understand my mistake. I've search all night long on google.
Q/A
_ I use mamp ( apache )
_ Ldap server pings good, and works with bash.
_ I use a firewall, but it doesnt work without too.
_ all [var] are ok, because in bash it works.
adding TLS_REQCERT allow to ldap.conf and it works! thanks to #rooster

How do I solve ldap_start_tls() "Unable to start TLS: Connect error" in PHP?

I'm getting:
Warning: ldap_start_tls()
[function.ldap-start-tls]: Unable to
start TLS: Connect error in
/var/www/X.php on line Y
/etc/ldap/ldap.conf:
TLS_CACERT /etc/ssl/certs/ca.crt
ca.crt is the CA which signed the LDAP server certificate. The certificate on the LDAP server is expired and I can't change it.
You can ignore the validity in windows by issuing
putenv('LDAPTLS_REQCERT=never');
in your php code. In *nix you need to edit your /etc/ldap.conf to contain
TLS_REQCERT never
Another thing to be aware of is that it requires version 3 (version 2 is php default):
//$hostnameSSL example would be "ldaps://just.example.com:636" , just make sure it has ldaps://
$con = ldap_connect($hostnameSSL);
ldap_set_option($con, LDAP_OPT_PROTOCOL_VERSION, 3);
To get a better idea of what's going on, you can enable debug logging by:
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
This can be done before the ldap_connect takes place.
The specific scenario presented in the question--with an expired certificate that can't be changed--does appear to require disabling certificate validation on the LDAP client.
However, I suspect a lot of people, like me, reach this page for other root causes of receiving opaque LDAP TLS errors, where disabling validation of TLS certificates is not an appropriate answer.
In my case--using the LDAP Authentication extension for Mediawiki on an Ubuntu 18.04 LTS server, and authenticating against Active Directory on a Windows Server 2012 server--authentication stopped working in January/February 2020. The server certificate and the CA certificate were still both valid, and openssl s_client -verify 2 -connect <AD server>:636 from the Mediawiki server passed just fine.
Eventually I noticed that the signature algorithm in the SSL certificate served by AD/LDAP was SHA1, which I remembered recently suffered from the first known chosen-prefix collision exploit. This led me to investigate the changelog for packages that had recently been updated on the system, which turned up "Mark SHA1 as insecure for certificate signing" in the gnutls28 changelog circa January 8th, 2020. (The chain of dependencies from the php-ldap package in Ubuntu 18.04 goes to php7.2-ldap -> libldap-2.4-2 -> libgnutls30, whose source package is gnutls28.)
I followed some instructions to update the Windows CA to use SHA256 and then selectively followed instructions to renew the AD/LDAP cert, installed the new CA cert on my Mediawiki server, and the problem was solved! Briefly, these steps included:
In an Admin PowerShell on the AD server, run certutil -setreg ca\csp\CNGHashAlgorithm SHA256
In the Certification Authority MMC, right click on the CA -> All Tasks -> Renew CA Certificate
In a blank MMC, add snap-in for Certificates; select Local Computer
Under Personal -> Certificates, find the current entry used by LDAPS (Kerberos Authentication template type) -> All Tasks -> Advanced Options -> Renew This Certificate with the Same Key
In the same window, open the new CA certificate -> Details -> Copy to file -> no private key -> base64-encoded X.509
Copy the resulting file to /usr/share/ca-certificates/ on the Mediawiki server, then run sudo dpkg-reconfigure ca-certificates and select the new CA cert for inclusion.
P.S. For SEO purposes, depending on the mode I was using, error messages included:
ldap_start_tls(): Unable to start TLS: Connect error in /var/www/mediawiki/extensions/LdapAuthentication/LdapAuthenticationPlugin.php in the HTTP error log
ldap_start_tls(): Unable to start TLS: Can't contact LDAP server in [...]
Failed to start TLS. in the Mediawiki debug log (when using wgLDAPEncryptionType = ssl, i.e. encrypted LDAP port, 636)
Failed to bind as CN=foobar,CN=Users,DC=myOrgName,DC=local in the Mediwiki debug log (when using wgLDAPEncryptionType = tls, i.e. STARTTLS on the unencrypted LDAP port, 389)
My solution/workaround is to use
/etc/ldap/ldap.conf:
#TLS_CACERT /etc/ssl/certs/ca.crt
TLS_REQCERT never
If you have any better idea, please post another answer.
The path for ldap.conf in Windows is fixed:
c:\openldap\sysconf\ldap.conf
A restart of the web server may be required to apply changes.
In debian based systems:
Install the package: ldap-utils and in the file
/etc/ldap/ldap.conf, edit the line:
TLS_CACERT /etc/ldap/cacerts/cacert.asc
Create the directory /etc/ldap/cacerts and copy the cacert to
/etc/ldap/cacerts/cacert.asc
Restart apache.
In redhat based systems:
Install the package: openldap-clients and in the file
/etc/openldap/ldap.conf edit the line:
TLS_CACERT /etc/openldap/cacerts/cacert.asc
Create the directory /etc/openldap/cacerts and copy the cacert to
/etc/openldap/cacerts/cacert.asc
Restart httpd
I was able to get this working properly with openldap on Amazon Linux (Elastic Beanstalk PHP 7.0) with MacOS Server 5 LDAP, with TLS set to demand.
in /etc/openldap/ldap.conf:
TLS_REQCERT demand
TLS_CACERT /etc/openldap/certs/yourcacert.pem
(note that if you are not using openldap, the path will be /etc/ldap/certs/yourcacert.pem). This setup did not work until I placed the certificate inside the certs folder; it did not work from any other path.
The certificate to be placed in that path is NOT the TLS certificate of the server. It is the CA (Certificate Authority) certificate of the authority whom issued the server/domain specific TLS certificate. Only the CA certificate placed in that path will allow TLS to work before attempting an LDAP bind in php. Get the CA certificate from your server or download it from the authority's site, they are freely available.
To test if LDAP bind is even working without TLS, set TLS_REQCERT never temporarily (may need to comment # out TLS_CACERT). If you get "Can't connect to LDAP" it is not a TLS error; it simply cannot connect to the server and you likely need to open port 389 (not 636 for TLS).
Remember to restart your Apache server every time you make a change to the config file or certificate.
Some additional help for others, the certificate solution here solved my ldapsearch command line issue, but still PHP complained **Can't contact LDAP server**
Turned out to be SELinux on RHEL7 ( CentOS7 ) blocks HTTPD from using LDAP ports 389 and 636 by default, you can unblock with:
setsebool -P httpd_can_network_connect 1
Check your SELinux audit log file for things being blocked.

Categories