Repository navigation
ldap_set_option(null, LDAP_OPT_X_TLS_REQUIRE_CERT, $option) can't be overridden #17776
Copy link
Copy link
Closed
Closed
Copy link
Description
Description
The following code:
<?php
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 6);
echo 'Test LDAP_OPT_X_TLS_ALLOW' . PHP_EOL;
if (!ldap_set_option(null, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_ALLOW)) {
echo 'Unable to set LDAP_OPT_X_TLS_ALLOW!' . PHP_EOL;
}
$ldapconn1 = ldap_connect('ldaps://localhost:636');
ldap_set_option($ldapconn1, LDAP_OPT_PROTOCOL_VERSION, 3);
$ldapbind1 = ldap_bind($ldapconn1, 'CN=Administrator,CN=Users,DC=samdom,DC=example,DC=com', 'Passw0rd');
if ($ldapbind1) {
echo 'LDAP bind succeeded (expected)' . PHP_EOL;
} else {
echo 'LDAP bind failed (unexpected)' . PHP_EOL;
}
ldap_unbind($ldapconn1);
echo PHP_EOL;
echo 'Test LDAP_OPT_X_TLS_DEMAND' . PHP_EOL;
if (!ldap_set_option(null, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_DEMAND)) {
echo 'Unable to set LDAP_OPT_X_TLS_DEMAND!' . PHP_EOL;
}
$ldapconn2 = ldap_connect('ldaps://localhost:636');
ldap_set_option($ldapconn2, LDAP_OPT_PROTOCOL_VERSION, 3);
$ldapbind2 = ldap_bind($ldapconn2, 'CN=Administrator,CN=Users,DC=samdom,DC=example,DC=com', 'Passw0rd');
if ($ldapbind2) {
echo 'LDAP bind succeeded (unexpected)' . PHP_EOL;
} else {
echo 'LDAP bind failed (expected)' . PHP_EOL;
}
ldap_unbind($ldapconn2);
EOFResulted in this output:
Test LDAP_OPT_X_TLS_ALLOW
TLS certificate verification: Error, unable to get local issuer certificate
TLS certificate verification: Error, unable to verify the first certificate
LDAP bind succeeded (expected)
Test LDAP_OPT_X_TLS_DEMAND
TLS certificate verification: Error, unable to get local issuer certificate
TLS certificate verification: Error, unable to verify the first certificate
TLS: unable to get peer certificate.
LDAP bind succeeded (unexpected)
But I expected this output instead:
Test LDAP_OPT_X_TLS_ALLOW
TLS certificate verification: Error, unable to get local issuer certificate
TLS certificate verification: Error, unable to verify the first certificate
LDAP bind succeeded (expected)
Test LDAP_OPT_X_TLS_DEMAND
TLS certificate verification: Error, unable to get local issuer certificate
TLS: can't connect: error:0A000086:SSL routines::certificate verify failed (unable to get local issuer certificate).
PHP Warning: ldap_bind(): Unable to bind to server: Can't contact LDAP server in /tmp/ldap.php on line 26
LDAP bind failed (expected)
Full reproducer:
docker run --rm -it docker.io/smblds/smblds:latest /bin/shrm -f /root/.ldaprcapk updateapk add php84-cli php84-ldap
cat > /tmp/ldap.php <<\EOF
<?php
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 6);
echo 'Test LDAP_OPT_X_TLS_ALLOW' . PHP_EOL;
if (!ldap_set_option(null, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_ALLOW)) {
echo 'Unable to set LDAP_OPT_X_TLS_ALLOW!' . PHP_EOL;
}
$ldapconn1 = ldap_connect('ldaps://localhost:636');
ldap_set_option($ldapconn1, LDAP_OPT_PROTOCOL_VERSION, 3);
$ldapbind1 = ldap_bind($ldapconn1, 'CN=Administrator,CN=Users,DC=samdom,DC=example,DC=com', 'Passw0rd');
if ($ldapbind1) {
echo 'LDAP bind succeeded (expected)' . PHP_EOL;
} else {
echo 'LDAP bind failed (unexpected)' . PHP_EOL;
}
ldap_unbind($ldapconn1);
echo PHP_EOL;
echo 'Test LDAP_OPT_X_TLS_DEMAND' . PHP_EOL;
if (!ldap_set_option(null, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_DEMAND)) {
echo 'Unable to set LDAP_OPT_X_TLS_DEMAND!' . PHP_EOL;
}
$ldapconn2 = ldap_connect('ldaps://localhost:636');
ldap_set_option($ldapconn2, LDAP_OPT_PROTOCOL_VERSION, 3);
$ldapbind2 = ldap_bind($ldapconn2, 'CN=Administrator,CN=Users,DC=samdom,DC=example,DC=com', 'Passw0rd');
if ($ldapbind2) {
echo 'LDAP bind succeeded (unexpected)' . PHP_EOL;
} else {
echo 'LDAP bind failed (expected)' . PHP_EOL;
}
ldap_unbind($ldapconn2);
EOF
php84 /tmp/ldap.php- If I reverse the two tests, both tests will fail for LDAP bind instead of both succeeding
If I'm not overlooking something, ldap_set_option(null, LDAP_OPT_X_TLS_REQUIRE_CERT, $option) can't be overridden, but I also don't receive any failure for ldap_set_option(). And $ldapconn = ldap_connect('ldaps://localhost:636'); ldap_set_option($ldapconn, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_ALLOW); doesn't work.
PHP Version
PHP 8.4.3 (with OpenLDAP 2.6.8)
Operating System
Alpine Linux 3.21.2
Activity
cmb69 commentedon Feb 13, 2025
Possibly related: https://openldap-technical.openldap.narkive.com/B9m55wCa/ldap-opt-x-tls-xxx-option-in-ssl-tls-connection
remicollet commentedon Feb 26, 2025
ldap2.php.txt
So from @cmb69 link, setting LDAP_OPT_X_TLS_NEWCTX is enough (attached script)
So it is only about adding
LDAP_OPT_X_TLS_NEWCTXconstantrobert-scheck commentedon Feb 26, 2025
LDAP_OPT_X_TLS_NEWCTXis unfortunately not documented at https://www.php.net/ldap_set_optionldap_set_option()not fail by return code, if it doesn't do what it's supposed to do?LDAP_OPT_X_TLS_NEWCTXis automatically set by PHP ldap extension internally?LDAP_OPT_X_TLS_NEWCTXautomatically internally makes sense to me given thatldap_set_option()doesn't ensure what it's supposed to do (and due to the OpenLDAP API it might be even never able to throw an error)remicollet commentedon Feb 26, 2025
It doesn't exists ;)
Proposal in PR #17939
This is another way...
Will try it
remicollet commentedon Feb 26, 2025
Second proposal in PR #17940
robert-scheck commentedon Feb 26, 2025
Thank you, very much appreciated!
robert-scheck commentedon Feb 26, 2025
I am sorry, but while commuting I came to the conclusion that my report covers only LDAPS (
ldaps://), but not STARTTLS (ldap://). Given this issue came from actual code using only LDAPS, I didn't think about STARTTLS before. Unfortunately, STARTTLS is affected the same way, here is a full reproducer:Fix php#17776 LDAP_OPT_X_TLS_REQUIRE_CERT can't be overridden
1 remaining item
Merge branch 'PHP-8.3' into PHP-8.4
Merge branch 'PHP-8.4'
Fix #17776 LDAP_OPT_X_TLS_REQUIRE_CERT can't be overridden
Fix phpGH-18529: ldap no longer respects TLS_CACERT from ldaprc in ld…
Fix GH-18529: ldap no longer respects TLS_CACERT from ldaprc in ldap_…
Merge branch 'PHP-8.3' into PHP-8.4
Merge branch 'PHP-8.4'
arderyp commentedon May 20, 2025
for some reason, this fix broke my code on Ubuntu 20.4. I can fix it by adding
ldap_set_option($ds, LDAP_OPT_X_TLS_CACERTFILE, '/etc/ssl/certs/ca-certificates.crt'), but this was not needed before. Additionally, this fix did not break my RHEL instalation running the same code and php/php-ldap versions. Neitheropenssl.cafilenoropenssl.capathare defined in php.ini on either my ubuntu or my RHEL servers. Any thoughts why the sudden breakage and new requirement for settingLDAP_OPT_X_TLS_CACERTFILEin the ubuntu environment only?remicollet commentedon May 21, 2025
@arderyp this regression is reported as #18529 (fixed)