Skip to content

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

@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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions