On Mon, 18 Jun 2007, Markus Moeller wrote:
Does anybody have some sample code of how to use LDAP_OPT_X_TLS_ALLOW in a client program with ldap_start_tls_s ?
Is it a bug if it doesn't work ?
...
I am new to Openldap and TLS/SSL. I have two small test programs (see details below). The first uses ldap_init the second ldap_initalize. My observation is:
- Using ldap_init, ldap_start_tls_s and set LDAP_OPT_X_TLS_ALLOW (empty
ldap.conf) It does not connect on port 389 nor 636
Don't confuse ports with protocols. The 'ldap' protocol, which is normally served on port 389, has an operation for initiating TLS. That operation is performed using the ldap_start_tls_s() function. The 'ldaps' protocol, which is normally served on port 636, runs over SSL from the get-go (the first data sent by the client is an SSL CLIENT-HELLO). As such, the client must know which protocol the server is expecting when it connects. This is part of why ldap_init() and ldap_open() are deprecated: they pass a host and port without passing the protocol. Don't use them: use ldap_initialize() instead.
Next, it should be clear from the above that you cannot use ldap_start_tls_s() when the server is expecting the 'ldaps' protocol. That call in you code is failing, but you aren't checking the return code so you didn't know that.
As Howard has separately noted, the LDAP_OPT_X_TLS option is deprecated. The setting you use actually has no effect.
So, to back up:
- Using ldap_init, ldap_start_tls_s and set LDAP_OPT_X_TLS_ALLOW (empty
ldap.conf) It does not connect on port 389 nor 636
It's failing on port 636 because the server is (presumably) expecting ldaps and you're doing ldap. It's probably failing on port 389 because your client can't validate the server's cert because it can't find the CA that signed the server's cert. That last bit is a guess but matches with this:
- Using ldap_init,ldap_start_tls_s and set LDAP_OPT_X_TLS_ALLOW (emprty
ldap.conf and only TLS_REQCERT ALL in ldaprc) It does not connect on port 636 but it does on port 389
I think you mean your ldaprc had "TLS_REQCERT ALLOW". If so, port 389 now succeeds because you've disabled the checking of the signatures on the server's cert.
It's failing on port 636 because the server is (presumably) expecting ldaps and you're doing ldap.
- Using ldap_initialize and set LDAP_OPT_X_TLS_ALLOW (empty ldap.conf) It does not connect on port 389 nor 636
This can't work, because it tries to do ldaps when the server is expecting ldap: ./ldap_test ldaps://w2k3.windows2003.home:389
This doesn't work because the client can't find the CA that signed the server's cert. ./ldap_test ldaps://w2k3.windows2003.home:636
- Using ldap_initialize and set LDAP_OPT_X_TLS_ALLOW (empty ldap.conf and
only TLS_REQCERT ALL in ldaprc) It does not connect on port 389 but it does on port 636
Again, I presume you mean your ldaprc contains "TLS_REQCERT ALLOW".
It doesn't work on port 389 because the server is expecting ldap and the client is doing ldaps. It works on port 636 because you've disabled the checking of the signatures on the server's cert.
My first question is why does
val = LDAP_OPT_X_TLS_ALLOW; ldap_set_option (ld, LDAP_OPT_X_TLS, &val);
not work ?
I'm guess that you meant to use LDAP_OPT_X_TLS_REQUIRE_CERT as the second argument to ldap_set_option(). That's the equivalent of the TLS_REQCERT entry in the ldaprc of ldap.conf.
Simply changing that won't do anything, because ldap_set_option() will start failing, though you would have never known that because you don't actually check return codes. CHECK ALL RETURN CODES AND INCLUDE THE OUTPUT OF ldap_err2string() IN YOUR ERROR MESSAGES.
The LDAP_OPT_X_TLS_REQUIRE_CERT option can only be set globally and not for particular LDAP handles. So, you need to invoke ldap_set_option() with a NULL first argument, ala: { int reqcert = LDAP_OPT_X_TLS_ALLOW; ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &reqcert); if (ret != LDAP_OPT_SUCCESS) { fprintf(stderr, "unable to set require cert option: %s\n", ldap_err2string(ret)); } }
BTW, the desciption on the ldap.conf(5) manpage of the TLS_REQCERT setting's 'allow' and 'try' values (i.e., LDAP_OPT_X_TLS_ALLOW and LDAP_OPT_X_TLS_TRY) is incorrect. 'try' is really the same as 'hard' and 'demand', while 'allow' requires that the server's cert match the hostname used in the URL that was used to connect.
I filed an ITS about this (#4941) back in April, but it's still marked as incoming. <rant>Dear Maintainers, not applying patches to the docs is a *great* way to encourage better docs!</rant>
Secondly why behaves ldap_init different to ldap_initialize ?
Because ldap_init() only does the ldap protocol, while ldap_initialize() lets you do either and you told it to do ldaps.
Thirdly what do I need to do to be able to use TLS/SSL on either port 389 or 636 ?
Use ldap_initialize(). Then, if the URL specified "ldap:", call ldap_start_tls_s().
Philip Guenther