Many Windows developers have a need of some sort to connect to OpenLDAP directory services.  Some use wldap32, others use the DirectoryServices namespace in .NET, others use custom libraries.  Myself, I’m writing an ASPX front-end to our FreeBSD LDAP directory service.

If you are one of the developers in the first two camps, you’ve probably been dumbfounded by one of these error messages:

  • An unexpected operation error occurred
  • A local error occurred
  • TLS negotiation failure

At first, I was inclined to believe this was due to the fact that MS wanted devs to stick with ADAM and not use OpenLDAP.  However, this is not the case.  Each error means something different, and I have workarounds now for all of them that fixes it.

An unexpected operations error occurred

My favourite.  This is due to an OpenLDAP bug that the developers won’t fix.  They have claimed that “Microsoft is the one that is broken by following RFC 2830″…yes, that’s right, an open-source project upset that MS is following an RFC.

Anyway, to fix it you need to apply a one-liner patch (thanks Kirill) to starttls.c, verified to work with OpenLDAP-2.4.19 and CVS HEAD as of this morning (GMT):

=============
--- orig/starttls.c	2004-01-01 21:15:32.000000000 +0200
+++ fixed/starttls.c	2004-05-27 14:14:54.000000000 +0300
@@ -94,6 +94,8 @@
     op->o_conn->c_is_tls = 1;
     op->o_conn->c_needs_tls_accept = 1;

+    rs->sr_rspoid = SLAP_STRDUP(LDAP_EXOP_START_TLS);
+
     rc = LDAP_SUCCESS;

 done:
=============

Recompile OpenLDAP with this change.  Your OpenLDAP is now RFC 2830 compliant and Microsoft APIs (and older Netscape and Novell APIs) can now connect and start TLS with it.

“But wait, Pongo,” you say.  “Now I’m getting a new error!”  Yes, because MS is strange about server certificate processing you will now receive:

A local error occurred (on the LDAP server, “TLS negotiation failure”)

You need the server certificate from the OpenLDAP server (see your slapd.conf file, under TLSCertificateFile.  Mine is in /etc/ssl/keys/ldap).

  1. Copy the file (named chicago-auth.crt in the example) to your Windows computer.
  2. Install the certificate (double-click it) to the Trusted Root Certificate Authorities store.  (I am not sure if this step is required or not.  It was for me for other reasons.)
  3. In your .NET application, add a code block similar to the following:
                lc.SessionOptions.VerifyServerCertificate = Ldap_ServCertCallback;  // Add this line BEFORE StartTLS call
                lc.SessionOptions.StartTransportLayerSecurity(null);

Your Ldap_ServCertCallback function should look something like this:

        private bool Ldap_ServCertCallback(LdapConnection connection, X509Certificate cert)
        {
            X509Certificate realchi = new X509Certificate("chicago-auth.crt");

            if (realchi.GetCertHashString() == cert.GetCertHashString())
                return true;
            else return false;
        }

That’s it. Your .NET application will now happily connect to your OpenLDAP server.

Note that I have not personally tested this workaround with wldap32 (I’m unsure how to set a VerifyServerCertificate callback and I don’t hack the Win32 API anymore anyway), but I have in .NET and it works in both Win32 and ASP.NET applications.

About these ads