0

I am unable to connect to Active Directory with TLS 1.2 using the DirectoryService class. I am able to connect using TLS 1.2 via LDP on Windows, Open Source LDAPAdmin on Windows and LdapConnection in a .Net 4.7.2 console application. I have verified the TLS 1.2 connections using WireShark. Here is some sample code:

static void Main(string[] args)
{
    LdapConnection conn = new LdapConnection("server.domain.com:636");
    var op = conn.SessionOptions;
    op.ProtocolVersion = 3;
    op.SecureSocketLayer = true;
    op.VerifyServerCertificate = (ldapConnection, serverCertificate) =>
    {
        return true;
    };

    conn.AuthType = AuthType.Negotiate;
    var cred = new NetworkCredential("user@domain.com", "password");
    conn.Credential = cred;
    conn.Bind(cred);
    Console.WriteLine("LdapConnection Success");

    // Is not TLS 1.2
    var de = new DirectoryEntry("LDAP://server.domain.com", "user@domain.com", "password", AuthenticationTypes.Secure);
    try
    {
        foreach (var child in de.Children)
        {
            Console.WriteLine(child);
        }
        Console.WriteLine($"{de.Path} Success");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"{de.Path} {ex.Message}");
    }

    //Does not work
    de = new DirectoryEntry("LDAP://server.domain.com:636", "user@domain.com", "password");
    try
    {
        foreach (var child in de.Children)
        {
            Console.WriteLine(child);
        }
        Console.WriteLine($"{de.Path} Success");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"{de.Path} {ex.Message}");
    }

    //Does not work
    de = new DirectoryEntry("LDAP://server.domain.com", "user@domain.com", "password", AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.Secure);
    try
    {
        foreach (var child in de.Children)
        {
            Console.WriteLine(child);
        }
        Console.WriteLine($"{de.Path} Success");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"{de.Path} {ex.Message}");
    }

    //Does not work
    de = new DirectoryEntry("LDAP://server.domain.com:636", "user@domain.com", "password", AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.Secure);
    try
    {
        foreach (var child in de.Children)
        {
            Console.WriteLine(child);
        }
        Console.WriteLine($"{de.Path} Success");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"{de.Path} {ex.Message}");
    }

    Console.ReadKey();
}

Any Idea's how to connect through the DirectoryService class? I have seem many questions about this topic in StackOverflow which is why I included all of the other answers I read about in the sample code.

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
Mike
  • 559
  • 5
  • 21

1 Answers1

0

The correct way to connect via LDAPS with DirectoryEntry is:

e = new DirectoryEntry("LDAP://server.domain.com:636", "user@domain.com", "password");

You don't need to specify AuthenticationTypes.SecureSocketsLayer, since that's the only possible way to connect on port 636, but it also doesn't hurt anything if you do.

My guess is that you have a problem with the certificate. Probably one of two reasons:

  1. The domain name on the certificate does not match the domain name you are using to connect. For example, if you are connecting using the domain name server.domain.com, then the certificate must be issued to (or have a Subject Alternative Name for) server.domain.com. If the domain on the certificate is just domain.com, or just server, then it does not match and it will fail.
  2. The certificate is not issued by an authority that the client computer trusts. It could be self-signed, for example.

It works with LdapConnection because you have this:

op.VerifyServerCertificate = (ldapConnection, serverCertificate) =>
{
    return true;
};

That's your custom code for validating the certificate, which always returns true. So any issue with the cert will be ignored. DirectoryEntry does not give you a way to do that.

You can use the PowerShell code in this answer to download the certificate (make sure to change the domain name) and inspect it. Windows will flag an issue with it (if there is one) when you double-click the .cer file.

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
  • So even though LDAPAdmin works and the server is it's own CA, it appears the cert has chain errors. Strange that both LDAPAdmin and LDP work but when I run my own Certificate Monitoring software, I see the chain error. Thank for pointing me to test the certs again. That is a real bummer there is no way to expose the error to end-users. It makes the API almost unusable. – Mike Jul 14 '22 at 02:44
  • While sniffing packets, LDAPAdmin is able to connect TLS 1.2 on port 389. When I try to force the port using the DirectoryServices API, the API does not attempt to communicate TLS. Is there a way to get the TLS working on port 389 with DirectoryServices? – Mike Jul 14 '22 at 14:16