Skip to content

ldap_set_option(null, LDAP_OPT_X_TLS_REQUIRE_CERT, $option) can't be overridden #17776

Closed
@robert-scheck

Description

@robert-scheck

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);
EOF

Resulted 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:

  1. docker run --rm -it docker.io/smblds/smblds:latest /bin/sh
  2. rm -f /root/.ldaprc
  3. apk update
  4. apk 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
  1. php84 /tmp/ldap.php
  2. 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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions