Search code examples
c#ldapdirectoryservicesstarttls

Using StartTLS with LDAP from System.DirectoryServices


I'm trying to connect to an LDAP server which requires StartTLS, but having no luck - whenever I use either the SessionOptions.StartTransportLayerSecurity(..) or set SessionOptions.SecureSocketLayer to true, I get exceptions.

Here's the code I'm using:

using (var connection = new LdapConnection(new LdapDirectoryIdentifier(config.LdapServer, config.Port, false, false)))
{
    connection.SessionOptions.ProtocolVersion = 3;
    connection.Credential = new NetworkCredential(config.BindDN, config.BindPassword);
    connection.SessionOptions.VerifyServerCertificate += (conn, cert) => {return true;};
    connection.AuthType = AuthType.Basic;
    //connection.SessionOptions.SecureSocketLayer = true;
    connection.SessionOptions.StartTransportLayerSecurity(null); // throws here, same if done after bind.
    connection.Bind();

    ... do stuff with connection
}

The resulting exception is "TlsOperationException: An unspecified error occurred", which happens when invoking the StartTransportLayerSecurity method.

I've tested the code against both and OpenLDAP server and Active Directory, but neither works.

Does anyone know how to get StartTLS working with System.DirectoryServices?


Solution

  • After a bit more work on this issue I found that I was running up against a couple of issues:

    1. There was a bug in the code where the port number was being incorrectly changed to the SSL port (636) when connecting to AD in our test suite (doh!).
    2. The OpenLDAP test server (that was a replica of our customers) was using openldap-2.4.18 - which has known issues with StartTLS.

    After applying a patch to OpenLDAP (as discussed here - http://www.openldap.org/lists/openldap-bugs/200405/msg00096.html) we were able to fix #2 - at which point we started getting a different error "A local error occurred".

    Though originally we had this code:

    connection.SessionOptions.VerifyServerCertificate 
        += (conn, cert) => {return true;};
    

    We had removed it while testing, and because the OpenLDAP server was using a self-signed cert, that was not in a trusted store. Re-introducing that callback resolved this issue, though we now make it a configurable option i.e. "Verify Server Certificate Y/N" so customers need to opt into skipping the check (mostly for our QA team to use).

    Thanks Steffen for pointing me in the direction of OpenLDAP versions which lead me to this solution.