From eade5c17ead650b0735295214bbec84872465e87 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 27 May 2025 19:03:56 +0200 Subject: [PATCH] Fix GH-18529: additional inheriting of TLS int options This is for LDAP_OPT_X_TLS_PROTOCOL_MIN and LDAP_OPT_X_TLS_PROTOCOL_MAX It also adds a test that uses LDAPCONF with TLS max version lower than the minimum TLS server version so it should always fail. However it does not fial for the second case without this change which confirms that the change works as expected. Closes GH-18676 --- .github/scripts/setup-slapd.sh | 3 ++ NEWS | 6 ++- ext/ldap/ldap.c | 32 ++++++++++++--- .../tests/ldap_start_tls_rc_max_version.conf | 1 + .../tests/ldap_start_tls_rc_max_version.phpt | 41 +++++++++++++++++++ ext/ldap/tests/skipifbindfailure.inc | 33 +++++++++++++++ 6 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 ext/ldap/tests/ldap_start_tls_rc_max_version.conf create mode 100644 ext/ldap/tests/ldap_start_tls_rc_max_version.phpt diff --git a/.github/scripts/setup-slapd.sh b/.github/scripts/setup-slapd.sh index fcaa67d0a5f..f6b976783c7 100755 --- a/.github/scripts/setup-slapd.sh +++ b/.github/scripts/setup-slapd.sh @@ -72,6 +72,9 @@ olcTLSCertificateKeyFile: /etc/ldap/ssl/server.key add: olcTLSVerifyClient olcTLSVerifyClient: never - +add: olcTLSProtocolMin +olcTLSProtocolMin: 3.3 +- add: olcAuthzRegexp olcAuthzRegexp: uid=usera,cn=digest-md5,cn=auth cn=usera,dc=my-domain,dc=com - diff --git a/NEWS b/NEWS index 4fa5dda65c3..06427de7f96 100644 --- a/NEWS +++ b/NEWS @@ -2,7 +2,11 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.3.25 -OpenSSL: +- LDAP: + . Fixed bug GH-18529 (additional inheriting of TLS int options). + (Jakub Zelenka) + +- OpenSSL: . Fixed bug GH-18986 (OpenSSL backend: incorrect RAND_{load,write}_file() return value check). (nielsdos, botovq) . Fix error return check of EVP_CIPHER_CTX_ctrl(). (nielsdos) diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c index 769e6caa277..0b0a0c21df4 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -3732,7 +3732,8 @@ PHP_FUNCTION(ldap_rename_ext) */ static int _php_ldap_tls_newctx(LDAP *ld) { - int val = 0, i, opts[] = { + int val = 0, i; + int str_opts[] = { #if (LDAP_API_VERSION > 2000) LDAP_OPT_X_TLS_CACERTDIR, LDAP_OPT_X_TLS_CACERTFILE, @@ -3752,21 +3753,42 @@ static int _php_ldap_tls_newctx(LDAP *ld) #endif 0}; - for (i=0 ; opts[i] ; i++) { + for (i=0 ; str_opts[i] ; i++) { char *path = NULL; - ldap_get_option(ld, opts[i], &path); + ldap_get_option(ld, str_opts[i], &path); if (path) { /* already set locally */ ldap_memfree(path); } else { - ldap_get_option(NULL, opts[i], &path); + ldap_get_option(NULL, str_opts[i], &path); if (path) { /* set globally, inherit */ - ldap_set_option(ld, opts[i], path); + ldap_set_option(ld, str_opts[i], path); ldap_memfree(path); } } } +#ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN + int int_opts[] = { + LDAP_OPT_X_TLS_PROTOCOL_MIN, +#ifdef LDAP_OPT_X_TLS_PROTOCOL_MAX + LDAP_OPT_X_TLS_PROTOCOL_MAX, +#endif + 0 + }; + for (i=0 ; int_opts[i] ; i++) { + int value = 0; + + ldap_get_option(ld, int_opts[i], &value); + if (value <= 0) { /* if value is not set already */ + ldap_get_option(NULL, int_opts[i], &value); + if (value > 0) { /* set globally, inherit */ + ldap_set_option(ld, int_opts[i], &value); + } + } + } +#endif + return ldap_set_option(ld, LDAP_OPT_X_TLS_NEWCTX, &val); } diff --git a/ext/ldap/tests/ldap_start_tls_rc_max_version.conf b/ext/ldap/tests/ldap_start_tls_rc_max_version.conf new file mode 100644 index 00000000000..0cd03f8b8e1 --- /dev/null +++ b/ext/ldap/tests/ldap_start_tls_rc_max_version.conf @@ -0,0 +1 @@ +TLS_PROTOCOL_MAX 3.2 \ No newline at end of file diff --git a/ext/ldap/tests/ldap_start_tls_rc_max_version.phpt b/ext/ldap/tests/ldap_start_tls_rc_max_version.phpt new file mode 100644 index 00000000000..359785f8b5a --- /dev/null +++ b/ext/ldap/tests/ldap_start_tls_rc_max_version.phpt @@ -0,0 +1,41 @@ +--TEST-- +ldap_start_tls() - Basic ldap_start_tls test +--EXTENSIONS-- +ldap +--ENV-- +LDAPCONF={PWD}/ldap_start_tls_rc_max_version.conf +--SKIPIF-- + "OpenLDAP", + "min_version" => 20600, +]; +require_once __DIR__ .'/skipifbindfailure.inc'; +?> +--FILE-- + +--EXPECT-- +bool(false) +bool(false) +bool(false) diff --git a/ext/ldap/tests/skipifbindfailure.inc b/ext/ldap/tests/skipifbindfailure.inc index 1a0d0c6d199..81c7998cfbb 100644 --- a/ext/ldap/tests/skipifbindfailure.inc +++ b/ext/ldap/tests/skipifbindfailure.inc @@ -10,4 +10,37 @@ if ($skip_on_bind_failure) { ldap_unbind($link); } + +if (isset($require_vendor)) { + ob_start(); + phpinfo(INFO_MODULES); + $phpinfo = ob_get_clean(); + + // Extract the LDAP section specifically + if (preg_match('/^ldap\s*$(.*?)^[a-z_]+\s*$/ims', $phpinfo, $ldap_section_match)) { + $ldap_section = $ldap_section_match[1]; + + // Extract vendor info from the LDAP section only + if (preg_match('/Vendor Name\s*=>\s*(.+)/i', $ldap_section, $name_match) && + preg_match('/Vendor Version\s*=>\s*(\d+)/i', $ldap_section, $version_match)) { + + $vendor_name = trim($name_match[1]); + $vendor_version = (int)$version_match[1]; + + // Check vendor name if specified + if (isset($require_vendor['name']) && $vendor_name !== $require_vendor['name']) { + die("skip Requires {$require_vendor['name']} (detected: $vendor_name)"); + } + + // Check minimum version if specified + if (isset($require_vendor['min_version']) && $vendor_version < $require_vendor['min_version']) { + die("skip Requires minimum version {$require_vendor['min_version']} (detected: $vendor_version)"); + } + } else { + die("skip Cannot determine LDAP vendor information"); + } + } else { + die("skip LDAP extension information not found"); + } +} ?>