5.2 - StartTLS

As we have seen in the previous chapter, LDAPS has some drawbacks. There is a better alternative for securing communications between the client and server – startTLS.

The idea is to use an existing connection to send a message to the server and request it to be encrypted. We keep going with the current connection, on the same port, but the exchanged data will continue as encrypted.

The startTLS extended operation is used for this. It’s a pure LDAP request that blocks other requests on the connection until it becomes secured. Of course, if some operations are pending, the operation will not be executed until the pending operations are completed.

How to use it

It’s quite simple. You just have to inform an opened connection to send the startTLS extended operation. It can be done at any time. Here is a quick example:

try ( LdapNetworkConnection connection = 
   new LdapNetworkConnection( Network.LOOPBACK_HOSTNAME, getLdapServer().getPort() ) )
{
    connection.connect();

    Entry admin = connection.lookup( "uid=admin,ou=system" );

    // startTLS
    connection.startTls();
    ...

As you can see, we’ll used the startTLS() method, and it occurred in the middle of an LDAP session. (There previously was data transmission with the server in clear text).

You can also send the startTLS request prior to a bind, protecting the entire session:

try ( LdapNetworkConnection connection = 
   new LdapNetworkConnection( Network.LOOPBACK_HOSTNAME, getLdapServer().getPort() ) )
{
    // startTLS
    connection.startTls();

    Entry admin = connection.lookup( "uid=admin,ou=system" );
    ...

That’s about it…

Advanced usage

We just saw basic usage of the startTLS extended operation. Keep in mind that behind the scene, a TLS session will be established, which requires some negotiation between the client and the server. It’s not different from the establishement of an LDAPS connection, except that we’re doing it on top of an existing LDAP connection. Still, the client and the server must exchange ciphers, certificates, and agree on which protocol version to use. You probably need more control.

The startTLS() method uses an LdapConnectionConfig instance for parameters in order to define things like – TrustManagers, allowed ciphers, enabled protocol versions, KeyManager instances, etc. You simply need an LdapConnectionConfig instance, and load it with instructions. for example, if you want to use a specific TrustManager that doesn’t verify the server’s certificate:

LdapConnectionConfig tlsConfig = new LdapConnectionConfig();
tlsConfig.setLdapHost( Network.LOOPBACK_HOSTNAME );
tlsConfig.setLdapPort( getLdapServer().getPort() );
tlsConfig.setTrustManagers( new NoVerificationTrustManager() );

try ( LdapNetworkConnection connection = 
        new LdapNetworkConnection( tlsConfig ) )
{
    // Connect
    connection.connect();

    // At this point, we are not oo a secured connection
    connection.bind( "uid=admin,ou=system", "secret" );

    // At this point, we are not oo a secured connection. Let's secure it
    connection.startTls();
    ...

In this example, the startTls call uses the parameter that was loaded into the tlsConfig instance.

Here’s what isn’t supported

The LDAP StartTLS RFC requires more than securing connections. Typically, it’s possible to stop securing a connection, using a Graceful Closure operation. That feature isn’t currently supported.