I’ve recently bumped into a need to verify certificates deployed for LDAPS on Active Directory. PowerShell remains my tool of choice for such occasions as this.

It is possible to very simply test an LDAPS connection using ADSI (System.DirectoryServices) like this:

A big red error suggests LDAPS is not avaiable of there is some other problem with the LDAP service. Anything else means the connection must have succeeded. We can infer that SSL negotiation also succeeded since we asked for it. Note that Secure is used to bind using the current users credentials, it is not necessary to provide explicit credentials for this. ServerBind removes any chance of the DCLocator becoming involved.

This method doesn’t really reveal very much unless you run a packet sniffer in parallel. I’m much happier when I can dig a bit deeper.

Happily the System.DirectoryServices.Protocols assembly contains just the tools we need to dig. It contains:

  • A means of defining an LDAP connection with a reasonable amount of detail
  • A way of showing negotiated SSL values such as protocols, hashing algorithms, and so on.
  • A callback delegate which will let us take a look at the certificate used for the connection.

Before we start, System.DirectoryServices.Protocols must be imported into the current session.

Constructing the LDAP connection is simple. I elected to use the LdapDirectoryIdentifier, it saves a bit of messing around constructing strings describing the end-point.

Next task is to build the LdapConnection object. Using Kerberos as the AuthType allows us to continue without authenticating again.

Next a few session options should be set. By default the connection will be plain text and LDAPv2 will be used.

If you look at the Connection object you should see an SslInformation property. Once we’ve bound to the directory this will be filled with algorithm information assuming SSL is successfully negotiated.

Getting any information about the certificate back needs a Callback Delegate defining for the VerifyServerCertificate property. Happily doing this needs nothing more complex than a ScriptBlock. I’m going to use a global scoped variable to let that return something to the main code block.

If you follow the link you’ll find the second argument passed into the delegate is X509Certificate (not X509Certificate2). Happily we can cast from one to the other, this exposes a few more properties we can immediately use.

Having assembled all of that, asking the connection to Bind will connect to the directory service and, hopefully, show us the certificate used.

As with the simple version at the top, a big red error suggests the directory service either doesn’t have a certificate or something else went wrong.

Having bound you can inspect these two to see what happened (note that LdapCertificate is the global variable):

Finally, I’ve taken all that and wrapped it into a function which will return that as a handy object.

2 Comments

  1. Your completed function doesn’t load the framework type: Add-Type -Assembly System.DirectoryServices.Protocols

    Reply

  2. Nice Script!

    I’d just add a couple changes:
    1- The parameter ComputerName should accept multiple values and the process go through them accordingly
    2- For the KeyExchangeAlgorithm, it happened in my tests that it returned an “invalid value” so I’d change the line as follow
    KeyExchangeAlgorithm = try {[Security.Authentication.ExchangeAlgorithmType][Int]$Connection.SessionOptions.SslInformation.KeyExchangeAlgorithm} catch {“N/A”};

    Aside from that, very nice script

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *