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:
1) 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:
1) 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:
2) 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.
3) 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
4) 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