OpenLDAP Server With Server-Side SSL/TLS and Client Authentication

Note

This independently authored paper is obsolete.

Reviewers of this papers have indicated that they believe the paper suffers from a number of significant technical errors and offers poor advice in a number of areas. As the author is unreachable and this paper is quite old, the paper has has been classified as obsolete.

It is strongly recommended that users of OpenLDAP Software consult the OpenLDAP Administrator's Guide for a detailed and up-to-date discussion of TLS/SSL use in OpenLDAP Software.

Note added by Kurt Zeilenga (7 March 2006, updated 27 March 2013)

Author: D. Kent Soper
Version: 1.0
Date: June 5, 2003


Table of Contents


1.0 Overview

OpenLDAP has the ability to enable SSLv3 capabilities. Similar to SSL is Transport Layer Security (TLSv1). While SSL operates on a secure connection (ldaps://:636) and is a Netscape-defined protocol, TLS offers the same encryption on regular LDAP connections (ldap://:389) and is an industry standard (RFC 2830). Both types of secure connections are set up identically. It is only the URL that is different. This document explains the steps necessary to set up an OpenLDAP server and make an SSL connection to it.

It should be noted that the steps taken in this document ensure an LDAP version 3 level of compliance.

1.1 Acknowledgment

None of the details here would be possible without the information taken from the "OpenLDAP Administrator's Guide" or the help received from Kurt Zeilenga, one of the main OpenLDAP contributors. OpenLDAP is a large set of software tools and I could not have set up the SSL portion without advice and tips from Kurt. Thank you very much, Kurt!

2.0 Software

Of course OpenLDAP is required, but in what form? RPM or tarball from the OpenLDAP web site? The latter is preferred because it guarantees the most current software. More importantly, building the sources from tarball allows one to create a customized server by selecting desired options out of the nearly one hundred available (see section 3.0 "Configure, Build, and Install OpenLDAP" ).

The OpenLDAP download site offers two download sources: release and stable. For this document, the release version was used on advice from Kurt. Frequently, release versions make it to stable status quickly as was the case for me. Advanced users may also want to check out the test release if available. Also, older releases may have an update available for users who haven't upgraded to the current development level.

If OpenLDAP is installed already and you are downloading the tarball, you should locate current OpenLDAP objects and avoid using them altogether. Why? It would be undesirable if an older LDAP standalone daemon (slapd) is started instead of the newly created one, since the daemon would not refer to the recently created server and configuration files!

Before installing the tarball, use "find" or "locate" and take note of the locations and dates of the following (which may not exist on your machine):

It is not recommended that you uninstall an old version of OpenLDAP. Doing so may break dependencies. The best thing to do is to avoid using the slapd daemon and client commands associated with the old OpenLDAP software. By doing this, you'll be able to bypass the older configuration files (slapd.conf and ldap.conf).

Actually, older version OpenLDAP client commands may be used to access the directory. The real issue on the client side is configuring the correct ldap.conf associated with the client. This issue is left for the user to decide.

2.1 Additional Software

Besides OpenLDAP, other development software may be required as dictated by the selected OpenLDAP configuration options.

The best practice for installing missing software is:

  1. Run the configure script (see section 3.2.1 "configure") with your options.
  2. Look for error messages involving missing header files or libraries.
  3. Consult the Linux distro CDs and install the necessary rpm. Almost all missing rpms are the development releases of the form package-devel-release.arch.rpm. To ensure compatibility, it is a good idea to verify client and development software have similar release values. They should be equal if they come from the same distribution. For example:
    • openssl-0.9.6g-18.i586.rpm
    • openssl-devel-0.9.6g-18.i586.rpm

2.1.1 Database Backend

One of the OpenLDAP options you should set during the OpenLDAP build is your desired database backend. Slapd comes with a variety of different database backends you can choose from. The two most commonly used are BDB, a high-performance transactional database backend and LDBM, a lightweight DBM based backend.

The default backend is BDB which means Sleepycat Software Berkley DB 4.1 will be utilized (--enable-bdb configure option). If that is not the desired database, then disable it (--disable-bdb configure option) and select another type.

It may be easier to use one of the many LDBM backends (GDBM, Berkley DB, MDBM, or BCompact). Although many of the database clients are installed already, you will still need to install the development rpms, as discussed in section 2.1. I chose the LDBM route (--enable-ldbm) and installed both the GDBM and Berkely DB rpms. Both were installed because I wanted to see which database OpenLDAP selects when more than one is available. However, only one database needs to be present.

Indeterminate of the database backend employed, the OpenLDAP software handles all of the database transactions transparently once OpenLDAP is installed and running. Therefore, the database does not need to be configured or initiated.

2.1.2 Software for this Example

You do not need to use the software levels in this example but you should use at a minimum OpenLDAP 2.1. More important is the use of a current version of Linux and its distributed rpms than searching for the software levels listed. The levels are listed only for reference. Current Linux levels may be determined from the distributor's website.

Your list could be shorter or longer depending upon the options selected during configuration and the software already installed on your Linux machine. In addition, SuSE and RedHat have differing dependencies, i.e., a RedHat box would not have a SASL dependence on the installation of Heimdal.

Operating system: SuSE 8.1
OpenLDAP: 2.1.17

Additional rpms
OpenSSL openssl-devel-0.9.6g-18
GDBM gdbm-devel-1.8.0-671
Berkley DB db-devel-4.0.14-182
Cyrus SASL cyrus-sasl-devel-1.5.27-256
DES* des-4.04b-501
Heimdal* heimdal-devel-0.4e-186
PAM pam-devel-0.76-36

* required by Cyrus SASL

3.0 Configure, Build, and Install OpenLDAP

At a minimum, the document "OpenLDAP Quick Start Guide" should be reviewed before attempting to install OpenLDAP. If problems persist, the comprehensive "OpenLDAP Administrator's Guide" can be helpful. Hopefully, this document will provide enough detail to perform the task at hand.

It is assumed the OpenLDAP source has been unpacked and the user has changed to the top level OpenLDAP directory at this stage of the document:

% tar zxf openldap-VERSION.tgz
% cd openldap-VERSION

At the top level of the OpenLDAP distribution are two files worth skimming:
README lists required software levels for OpenLDAP 2.1 and documentation sites.
INSTALL lists installation steps and suggests files to configure.

Note: a simple default install of OpenLDAP is not an option if SSL is to be enabled. A little extra work will be required.

3.1 Configure Options

As mentioned already, there are over one hundred options that can be configured. To view a complete list, type:
% ./configure --help

Here is a short list of some common options [default value]:

3.1.1 Example Configure Options

This example uses these features:

--prefix=/usr

A preference to avoid installing everything into /usr/local. Also, LDAP client commands are installed to usr/bin/ (overwrite and void old LDAP client commands).

--with-tls and --enable-slapd
The whole purpose of this exercise.

--with-cyrus-sasl
At first this option was not selected, but the OpenLDAP Admin Guide states that the system "will not be fully LDAPv3 compliant unless it detects a usable Cyrus SASL installation."

--enable-crypt
Cryptic passwords are always good.

--enable-ldbm and --disable-bdb
Turn off BDB and turn on LDBM style database backend.

Default options turned on: --enable-debug and --enable-cleartext

Options avoided: --enable-kerberos (not part of this exercise)

3.2 Build and Install

After selecting the configure options, follow these steps to build and install the OpenLDAP system. Do not proceed until each step is completed error-free.

3.2.1 configure

The form of this command is:
[ [ env ] settings ] ./configure options

([ ] represents optional segments of the command)
(Some shells do not require the use of 'env')
(Usually 'options' are optional but not for this example)

Settings may be any of these (from Admin Guide):

Table 1: Configuration Flags

VARIABLE DESCRIPTION
CC Specify alternative C Compiler
CFLAGS Specify additional compiler flags
CPPFLAGS Specify C preprocessor flags
LDFLAGS Specify linker flags
LIBS Specify additional entries

Example command using environment settings:

% env CPPFLAGS="-I/usr/local/incude" LDFLAGS="-L/usr/local/lib" \
./configure --with-tls

Here is the actual command used to configure the test system:

% ./configure --prefix=/usr --with-tls --enable-slapd --with-cyrus-sasl \
--enable-crypt --enable-ldbm --disable-bdb

Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
Restrictions apply, see COPYRIGHT and LICENSE files.
Configuring OpenLDAP 2.1.17-Release ...
checking host system type... i686-pc-linux-gnu

( ... A few hundred lines of output ... )

Please run "make depend" to build dependencies
%

Successful configuration will end with "Please run 'make depend' to build dependencies". If this message is not displayed, examine the output for missing headers or libraries. See section 2.1 "Additional Software" if software is missing.

3.2.2 make depend

Enter the following command to build dependencies and look for errors:
% make depend

3.2.3 make

Enter the following command to build the system and look for errors:
% make

Missing libraries will be discovered during 'make'. Also, this part should take a long time to execute (more than five minutes).

3.2.4 make test

This command is optional but testing the standalone system is recommended. This command also has a long execution time.

% make test

If all goes well, the system has been built as configured! Otherwise return to the configure, make depend, and make steps to find the problem.

3.2.5 make install

Enter the following command to install the binaries and man pages. Most installs require 'root' privileges.

% su root -c 'make install'

Tip: the installed man pages can be the best source of OpenLDAP answers in some instances.

4.0 Certificate Creation

To enable an SSL/TLS connection to the server, a server certificate is needed by the SSL/TLS protocols. Also, in an SSL handshake the server certificate only provides a secure, encrypted connection to the server. If client authentication is desired, then a client certificate and key pair must be presented to the LDAP server.

There are two ways to create and install a server certificate. Both methods involve creating the server certificate, sending it to OpenLDAP clients, and making appropriate changes to the OpenLDAP configuration files. Also, both methods involve OpenSSL commands that query the user for information used to create the certificate.

When asked for a 'Common Name', you must enter the fully-qualified distinguished name of the server, e.g. myserver.com, and not 'your name' as is suggested by the OpenSSL prompt. This common mistake is the cause of over 90% of server certificate errors!

4.1 Self Signed Certificate

The first way to create a server certificate is to use OpenSSL and create a self signed server certificate. From a command line:

% openssl req -newkey rsa:1024 -x509 -nodes -out server.pem -keyout server.pem -days 365

OpenLDAP only works with unencrypted keys and the '-nodes' argument prevents encryption of the private key.

The next step would involve configuring OpenLDAP with the location of server.pem. Self-signed certificate usage is discouraged and their configuration is not discussed in detail in this document because of these two downsides:
1. The private key is included in the certificate which will be transported to all OpenLDAP client machines.
2. Interpreting error messages from OpenSSL commands (see section 6.1 "SSL Connection Check".) The following output from an "openssl s_client ..." command is not an actual error (output edited for clarity):

Self Signed Certificate Output

% openssl s_client -connect localhost:636 -showcerts
CONNECTED(00000003)
depth=0 /O=Example Org/OU=Example Unit/CN=myserver.com/Email=me@example.com
verify error:num=18:self signed certificate
verify return:1
( deleted output )
---
Key-Arg : None
Start Time: 1050024298
Timeout : 300 (sec)
Verify return code: 18 (self signed certificate)

For these reasons it is strongly recommended to use CA signed certificates!

However, to configure a self-signed certificate, only three entries in slapd.conf need to be set (see section 5.1.1):

TLSCACertificateFile server.pem
TLSCertificateFile server.pem
TLSCertificateKeyFile server.pem

4.2 CA Issued Certificate

If you have access to a trusted Certificate Authority (CA), then step through the CA process to get a CA certificate, server certificate and server private key. See section 5.0 for info on how to configure your server with these items.

However, if a trusted CA is not available, OpenSSL makes the same process quick and easy.

The steps:
1. Create any directory for creating and signing your certificates.
For example, /var/myca.

% mkdir /var/myca

2. Change to /var/myca and run the OpenSSL CA script (in /usr/share/ssl/misc/ on my box):

% cd /var/myca/
% /usr/share/ssl/misc/CA.sh -newca
CA certificate filename (or enter to create) <enter>

Making CA certificate ...
Using configuration from /etc/ssl/openssl.cnf
Generating a 1024 bit RSA private key
..........................++++++
.........................++++++
writing new private key to './demoCA/private/./cakey.pem'
Enter PEM pass phrase: <ca pass>
Verifying password - Enter PEM pass phrase: <ca pass again>
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:Texas
Locality Name (eg, city) []:Austin
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Example Org
Organizational Unit Name (eg, section) []:Example Unit
Common Name (eg, YOUR name) []:example.com
Email Address []:.
%

This creates demoCA/cacert.pem and demoCA/private/cakey.pem (CA cert and private key).

3. Make your server certificate signing request (CSR):

% openssl req -newkey rsa:1024 -nodes -keyout newreq.pem -out newreq.pem
Using configuration from /etc/ssl/openssl.cnf
Generating a 1024 bit RSA private key
..............++++++
..........................++++++
writing new private key to 'newreq.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:Texas
Locality Name (eg, city) []:Austin
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Example Org
Organizational Unit Name (eg, section) []:Example Org Unit
Common Name (eg, YOUR name) []:myserver.com
Email Address []:ldap@myserver.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: <pass>
An optional company name []:.
%

The result is newreq.pem.

4. Have the CA sign the CSR:

% /usr/share/ssl/misc/CA.sh -sign
Using configuration from /etc/ssl/openssl.cnf
Enter PEM pass phrase: <ca pass>
Check that the request matches the signature
Signature ok
The Subjects Distinguished Name is as follows
countryName :PRINTABLE:'US'
stateOrProvinceName :PRINTABLE:'Texas'
localityName :PRINTABLE:'Austin'
organizationName :PRINTABLE:'Example Org'
organizationalUnitName:PRINTABLE:'Example Org Unit'
commonName :PRINTABLE:'myserver.com'
emailAddress :IA5STRING:'ldap@myserver.com'
Certificate is to be certified until Apr 10 18:58:58 2004 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=US, ST=Texas, L=Austin, O=Example Org, OU=Example Unit, CN=example.com
Validity
Not Before: Apr 11 18:58:58 2003 GMT
Not After : Apr 10 18:58:58 2004 GMT
Subject: C=US, ST=Texas, L=Austin, O=Example Org, OU=Example Org Unit, CN=myserver.com/Email=ldap@myserver.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
< ... >
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
D0:C0:9D:46:30:65:2A:9C:63:63:6A:E6:FE:E4:AC:F7:21:F8:33:61
X509v3 Authority Key Identifier:
keyid:31:2E:0D:FB:A0:74:5A:0B:4B:C5:C4:E0:69:7F:32:6D:AF:46:82:F1
DirName:/C=US/ST=Texas/L=Austin/O=Example Org/OU=Example Unit/CN=example.com
serial:00

Signature Algorithm: md5WithRSAEncryption
< ... >
-----BEGIN CERTIFICATE-----
< ... >
-----END CERTIFICATE-----
Signed certificate is in newcert.pem
%

This creates newcert.pem (server certificate signed by CA) with private key, newreq.pem.

5. Now the certificates can be moved to the desired certificate repository and renamed.
I prefer /usr/var/openldap-data as my certificate directory.

% cp demoCA/cacert.pem /usr/var/openldap-data/cacert.pem
% mv newcert.pem /usr/var/openldap-data/servercrt.pem
% mv newreq.pem /usr/var/openldap-data/serverkey.pem
% chmod 400 /usr/var/openldap-data/serverkey.pem

The last command makes the private key read-only by the user who runs slapd. A 'chown' command will be necessary if the owner of the server key is not the same as the user who runs slapd. The certificates should be publicly readable.

6. Make the CA certificate available to your LDAP clients.
If the client is on the same machine, copy cacert.pem to a location accessible by the client. If clients are on other machines, then cacert.pem will have to be copied to those machines and also made accessible.


This process requires a few more steps than creating a self signed certificate, but the benefits gained outweigh any extra time spent creating the CA.

4.3 Client Certificate

Client certificates are created similarly to server certificates. Using the steps outlined in section 4.2 "CA Issued Certificate", the only changes are as follow:

Step 1 and 2: Do nothing ... the CA does not need to be created again. The plan is to use the same CA certificate to sign the client certificate.

Step 3: Same command but actually enter the client's name instead of the server name when prompted for the Common Name. Of course, all of the other responses should be descriptive of the client as well as defining the client's subject DN.

Step 4: Same command with the same resulting files for the cert and private key. Good thing the last certificate was renamed in step 5!

Step 5: Now the certificates can be moved to the user's desired certificate repository and renamed.
(For example, /home/user/certs.)

% mv newcert.pem /home/user/certs/ldap.client.pem
% mv newreq.pem /home/user/certs/keys/ldap.client.key.pem
% chmod 400 /home/user/certs/keys/ldap.client.key.pem

The last command makes the private key read-only by the user who runs the LDAP client. A 'chown' command will be necessary if the owner of the server key is not the same as the user who runs the client. The certificate should be publicly readable.

Step 6: Shouldn't have to do anything here after the previous 'mv' commands were executed.

With the certificates created, only one more step remains before the server can be started: LDAP configuration.

5.0 OpenLDAP Configuration

To configure your OpenLDAP system, there are three areas to consider: server (slapd.conf), client(ldap.conf), and directory (schema). Please note that this section will discuss the requirements for server side SSL and client authentication although a system may be configured without client authentication. A table summarizing all of the pertinent SSL configuration variations will be presented in 5.4 Configuration Summary.

5.1 Server

Most of the configuration occurs in the slapd daemon configuration file, slapd.conf. Verify that the file corresponding to your new slapd daemon is the one that is being edited before proceeding. Also, the Admin Guide chapter, "Administration Guide, section 5: The slapd Configuration File", goes into more detail than this section and should be reviewed.

5.1.1 Example slapd.conf

The slapd.conf file contains many comments that are very helpful. One of the first states that the file should not be world readable. If it doesn't already have 600 protection mode, make it so.

Here is the example slapd.conf with important comments and entries in bold. It is displayed in its entirety due to the importance of the file.

#######################################################################
# $OpenLDAP$
#
# See slapd.conf(5) for details on configuration options.
# This file should NOT be world readable.
#
include /usr/etc/openldap/schema/core.schema
include /usr/etc/openldap/schema/cosine.schema
include /usr/etc/openldap/schema/inetorgperson.schema
include /usr/etc/openldap/schema/misc.schema
include /usr/etc/openldap/schema/openldap.schema

# Define global ACLs to disable default read access.

# Do not enable referrals until AFTER you have a working directory
# service AND an understanding of referrals.
#referral ldap://root.openldap.org

pidfile /usr/var/slapd.pid
argsfile /usr/var/slapd.args

# Load dynamic backend modules:
# modulepath /usr/libexec/openldap
# moduleload back_bdb.la
# moduleload back_ldap.la
# moduleload back_ldbm.la
# moduleload back_passwd.la
# moduleload back_shell.la

# Sample security restrictions
#
# Disallow clear text exchange of passwords
# disallow bind_simple_unprotected
#
# Require integrity protection (prevent hijacking)
# Require 112-bit (3DES or better) encryption for updates
# Require 63-bit encryption for simple bind
# security ssf=1 update_ssf=112 simple_bind=64

# Sample access control policy:
# Root DSE: allow anyone to read it
# Subschema (sub)entry DSE: allow anyone to read it
# Other DSEs:
# Allow self write access
# Allow authenticated users read access
# Allow anonymous users to authenticate
# Directives needed to implement policy:
# access to dn.base="" by * read
# access to dn.base="cn=Subschema" by * read
access to *
by self write
by users read
by anonymous auth
#
# if no access controls are present, the default policy is:
# Allow read by all
#
# rootdn can always write!

# CA signed certificate and server cert entries:

TLSCipherSuite HIGH:MEDIUM:+SSLv2
TLSCACertificateFile /usr/var/openldap-data/cacert.pem
TLSCertificateFile /usr/var/openldap-data/servercrt.pem
TLSCertificateKeyFile /usr/var/openldap-data/serverkey.pem

# Use the following if client authentication is required
TLSVerifyClient
demand
# ... or not desired at all
#TLSVerifyClient
never

#######################################################################
# ldbm database definitions
#######################################################################

database ldbm
#suffix "dc=my-domain,dc=com"
#rootdn "cn=Manager,dc=my-domain,dc=com"
suffix "dc=myserver,dc=com"
rootdn "cn=Manager,dc=myserver,dc=com"

# Cleartext passwords, especially for the rootdn, should
# be avoided. See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
#rootpw secret
rootpw {SSHA}/nM76XvHqgByMF/mplwZ4EuP6EjSPCFc

# The database directory MUST exist prior to running slapd AND
# should only be accessible by the slapd and slap tools.
# Mode 700 recommended.
directory /usr/var/openldap-data

# Indices to maintain
index objectClass eq

#######################################################################

The important directives in slapd.conf are described in Table 2.

Table 2: LDAP Server Directives

DIRECTIVE VALUE DESCRIPTION
include filename additional configuration files or schema
TLSCipherSuite cipher suite spec describes what ciphers will be accepted
TLSCACertificateFile filename file that contains the certificates of all trusted CA certs
TLSCACertificatePath directory directory containing CA certificates. Usually this or TLSCACertificateFile is used.
TLSCertificateFile filename server certificate filename
TLSCertificateKeyFile filename server private key filename
TLSVerifyClient level Client Authentication: level of checks to perform on incoming client certs ( never | allow | try | demand,hard )
database type database definition ( bdb | ldap | ldbm | shell | null | sql and others )
suffix dn suffix DN suffix of queries passed to database backend
rootdn dn DN that is not subject to access control for the database
rootpw password password or hash of password for rootdn
directory directory database directory which must exist prior to starting slapd

There are other variables that may be used. Table 2 summarizes a basic set of server configuration directives.

5.2 Client

Depending on the OpenLDAP system installed, "man ldap.conf" may or may not return all of the information available. If 'TLS OPTIONS' is not displayed, go to the newly installed OpenLDAP system and run the command again. OpenLDAP clients on other machines may not have updated man pages.

The ldap.conf file sets system-wide defaults for LDAP clients.

If user-specific values are required, then the same ldap.conf directives should be applied to ldaprc or .ldaprc files in the user home or current working directories. User-specific entries override global LDAP settings.

If implementing client authentication, it is required to add the client certificate and key pair to an ldaprc or .ldaprc file.

5.2.1 LDAP Client Configuration Directives

In the following table, user-only refers to ldaprc or .ldaprc file directives and are not global LDAP directives.

Table 3: LDAP Client Directives

DIRECTIVE VALUE DESCRIPTION
BASE dn default base (DN form) to use when performing ldap operations
BINDDN dn default bind DN to use when performing ldap operations user-only
HOST name[:port] name of LDAP servers to connect to (separate by spaces)
PORT number default port used when connecting to LDAP servers. 636 = SSL!
SIZELIMIT number search return limit (0 = unlimited search)
TIMELIMIT number search time limit (0 = unlimited time)
TLS level whether clients should use TLS by default (never | hard)
use of this directive is discouraged; incompatible with LDAPv3 StartTLS request
TLS_CACERT filename specifies the file that contains all of the CA certificates the client recognizes
TLS_CACERTDIR directory used if TLS_CACERT fails
TLS_REQCERT level specifies what checks to perform on a server certificate ( never | allow | try | demand,hard )
TLS_CERT filename Client Authentication: specifies the client certificate user-only
TLS_KEY filename Client Authentication: specifies the private key for TLS_CERT entry user-only

5.2.2 Example ldap.conf

Example ldap.conf:
#
# Global LDAP settings
#

# See ldap.conf(5) for details
# This file should be world readable but not world writable.
HOST myserver.com
PORT 636

TLS_CACERT /etc/ssl/certs/cacert.pem
TLS_REQCERT demand

This configuration will connect to ldaps://myserver.com:636 without the need to specify the host and port in client commands.

5.2.3 Example ldaprc

The ldaprc file is used to override global LDAP values and to set the certificate and private key used to establish client authentication.

Example ldaprc (in user's home or current directory):

#
# User specific LDAP settings
#

# Override global directive (if set)
TLS_REQCERT demand

# client authentication
TLS_CERT /home/ldap-user/certs/client.cert.pem
TLS_KEY /home/ldap-user/certs/keys/client.key.pem

This minimal configuration is all that is required for client authentication.

5.3 Schema

In slapd.conf, schema are listed near the top of the file. Initial slapd.conf files may contain one schema with several commented schemas. The example slapd.conf file added a few other schemas found in the schema directory.

Example slapd.conf schema entries:

include /usr/etc/openldap/schema/core.schema
include /usr/etc/openldap/schema/cosine.schema
include /usr/etc/openldap/schema/inetorgperson.schema
include /usr/etc/openldap/schema/misc.schema
include /usr/etc/openldap/schema/openldap.schema

No additional configuration is necessary to get the server up and running.

5.4 Configuration Summary

There are varying degrees of SSL configuration one may institute. Table 3 summarizes the various directives and values that can be used to set up basic server side SSL ("basic") up to strict server side and client side SSL ("best").

Table 4: SSL/TLS Directives

File Directive Basic OK Good Better Best
slapd.conf TLSCACertificateFile
or
TLSCACertificatePath
x x x x x
TLSCertificateFile x x x x x
TLSCertificateKeyFile x x x x x
TLSCipherSuite - x x x x
TLSVerifyClient never never allow try demand
ldap.conf TLS_CACERT - x x x x
TLS_CACERTDIR (optional) - x x x x
TLS_REQCERT never never allow try demand
ldaprc or .ldaprc TLS_CERT - - - x x
TLS_KEY - - - x x

KEY
- : no entry
x : use directive and enter filename or directory
Note: TLSVerifyClient default is 'never' and TLS_REQCERT default is 'demand'

6.0 Testing the Server

The server is now ready to be started!

% /usr/libexec/slapd -d127 -h "ldap:/// ldaps:///"

This starts the server running on the two default ports of 389 (ldap://) and 636 (ldaps://). On my box, the slapd daemon resides in the /usr/libexec/ directory. The "-d127" is a debug level and a value of '-1' will produce max debug output.

There is another way to start the server. A script called "ldap" exists (usually in /etc/rc.d/init.d) that can be edited to start your LDAP server. Initially, it probably won't reflect any of the newly created slapd values such as the path to the slapd executable nor will it have the flexibility to start LDAP on specific ports. I find it much easier to use the above command in a separate window and then be able to view debug output.

If alternate ports are desired, you can also start the server like this:

% /usr/libexec/slapd -d9 -h "ldaps:/// ldaps://:12345"

This command only starts the server on SSL ports 636 and 12345. It also uses a debug level of '9' which will display SSL connect information (and less of the other gorp associated with '-d -1').

How do you know if the server is really doing anything? OpenSSL has a utility that verifies the SSL connection and you can also add some entries and then search for them via an OpenLDAP client.

6.1 SSL Connection Check

To check the SSL connection, try this command:

% openssl s_client -connect localhost:636 -showcerts -state -CAfile <ca cert>

If the LDAP server is not executing on your client machine, "localhost" must be substituted with the server name, e.g. "myserver.com".

Also, to verify the server certificate, you must provide the client CA certificate to the CAfile argument. Why does the CA certificate have to be specified if it already is in ldap.conf? Because the command is an OpenSSL client command and not an LDAP client command.

The command can also be used to verify a TLS connection on non-ldaps ports, e.g. port 389.

Good output looks like this (edited):

OpenSSL Output Using Server Side SSL

% openssl s_client -connect myserver.com:636 -showcerts -state \
-CAfile /var/cacert/cacert.pem

CONNECTED(00000003)
SSL_connect:before/connect initialization
SSL_connect:SSLv2/v3 write client hello A
SSL_connect:SSLv3 read server hello A
depth=1 /C=US/ST=Texas/L=Austin/O=Example Org/OU=Example Unit/CN=example.com
verify return:1
depth=0 /C=US/ST=Texas/L=Austin/O=Example Org/OU=Example Org Unit/CN=myserver.com/Email=ldap@myserver.com
verify return:1
SSL_connect:SSLv3 read server certificate A
SSL_connect:SSLv3 read server done A
SSL_connect:SSLv3 write client key exchange A
SSL_connect:SSLv3 write change cipher spec A
SSL_connect:SSLv3 write finished A
SSL_connect:SSLv3 flush data
SSL_connect:SSLv3 read finished A
---
( ... Certificate chain output deleted ... )
---
No client certificate CA names sent
---
SSL handshake has read 1804 bytes and written 314 bytes
---
New, TLSv1/SSLv3, Cipher is DES-CBC3-SHA
Server public key is 1024 bit
SSL-Session:
Protocol : TLSv1
Cipher : DES-CBC3-SHA
Session-ID: E7E1D275B86A9695BEB1B15E4C0E681F55505016A6AC9F4E55B88FD...
Session-ID-ctx:
Master-Key: 2DC9724A4978BEF82B7FCCE6FA3E72C55C3D6A915AD7B7FC8E0F...
Key-Arg : None
Start Time: 1050452423
Timeout : 300 (sec)
Verify return code: 0 (ok)
---

The command will hang after the final return code output. This is normal. "Control-c" will end the command.

The line "No client certificate CA names sent" is indicative of a server side SSL set up. If client authentication had been configured, the OpenSSL command and output would resemble this:

OpenSSL Output Using Client Authentication

% openssl s_client -connect myserver.com:636 -state \
-CAfile /var/cacert/cacert.pem \
-cert /home/ldap-user/certs/client.cert.pem \
-key /home/ldap-user/certs/keys/client.key.pem

CONNECTED(00000003)
SSL_connect:before/connect initialization
SSL_connect:SSLv2/v3 write client hello A
SSL_connect:SSLv3 read server hello A
depth=1 /C=US/ST=Texas/L=Austin/O=Example Org/OU=Example Unit/CN=example.com
verify return:1
depth=0 /C=US/ST=Texas/L=Austin/O=Example Org/OU=Example Org Unit/CN=myserver.com/Email=ldap@myserver.com
verify return:1
SSL_connect:SSLv3 read server certificate A
SSL_connect:SSLv3 read server certificate request A
SSL_connect:SSLv3 read server done A
SSL_connect:SSLv3 write client certificate A
SSL_connect:SSLv3 write client key exchange A
SSL_connect:SSLv3 write certificate verify A
SSL_connect:SSLv3 write change cipher spec A
SSL_connect:SSLv3 write finished A
SSL_connect:SSLv3 flush data
SSL_connect:SSLv3 read finished A
---
( ... Certificate chain output deleted ... )
subject=/C=US/ST=Texas/L=Austin/O=Example Org/OU=Example Org Unit/CN=myserver.com/Email=ldap@myserver.com
issuer=/C=US/ST=Texas/L=Austin/O=Example Org/OU=Example Unit/CN=example.com
---
Acceptable client certificate CA names
/C=US/ST=Texas/L=Austin/O=Example Org/OU=Example Unit/CN=example.com

---
SSL handshake has read 1916 bytes and written 2102 bytes
---
New, TLSv1/SSLv3, Cipher is DES-CBC3-SHA
Server public key is 1024 bit
SSL-Session:
Protocol : TLSv1
Cipher : DES-CBC3-SHA
Session-ID: 96B9C18DAC585050EDC30C1BB7792A6C33C44F2DDB98EBAEBEC68B270...
Session-ID-ctx:
Master-Key: 540C7F9FAD1CBE503C9A3BA5D47A76A005BDEEEB1908F270669D32...
Key-Arg : None
Start Time: 1052237883
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
Note the extra SSL handshake output in bold.

6.2 OpenLDAP client commands

OpenLDAP has several client commands. Most common: ldapsearch, ldapadd, ldapmodify, and ldapdelete. This document will show example commands but will not explain the details of their operation. Please consult the man pages for more details.

The sections that follow show examples that add entries to the LDAP directory and then search the directory for various entries.

6.2.1 Adding Entries

Using any editor, copy and paste the following LDIF file to "init.ldif". Any leading and trailing white space should be eliminated. Change the DN values to mirror your slapd.conf suffix values. For example if your suffix is "dc=ldap,dc=com", then the DN entries below would be "dn: dc=ldap,dc=com".

init.ldif

#init.ldif
dn: dc=myserver,dc=com
objectclass: dcObject
objectclass: organization
o: Example Org
dc: myserver

dn: cn=my-name,dc=myserver,dc=com
objectclass: organizationalRole
cn: my-name

dn: ou=my system,dc=myserver,dc=com
objectclass: organizationalUnit
ou: my system
description: Test organizational unit to hold admin user

dn: cn=mr admin,ou=my system,dc=myserver,dc=com
objectclass: person
userPassword: testpass
description: mr admin test user
cn: mr admin
sn: admin

Now add the LDIF entries to the LDAP database (using your rootdn):

% ldapadd -x -D "cn=Manager,dc=myserver,dc=com" -W -f init.ldif

You will be prompted for the rootpw because of the "-W" argument. If successful, you will see four "adding new entry <entry>" lines.

To ensure an SSL connection, you can specify a host with: "-H ldaps://myserver.com". This argument is needed if the host is not set on a stand alone client.

6.2.2 Searching the Directory

Use the following commands to search the directory. To understand the different command flags, consult the man pages for ldapsearch. In all of the commands that follow, the argument ' -D "cn=Manager,dc=myserver,dc=com" ' is necessary because of this access block in slapd.conf:
access to *
by self write
by users read
by anonymous auth

If this block had been commented out as in a default slapd.conf , then none of the "-D" arguments would be needed in the ldapsearch commands here and in the following sections.

Return all entries

Client on same machine:

% ldapsearch -x -b 'dc=myserver,dc=com' -D "cn=Manager,dc=myserver,dc=com" '(objectclass=*)' -W

Stand alone LDAP client:

% ldapsearch -x -b 'dc=myserver,dc=com' -D "cn=Manager,dc=myserver,dc=com" '(objectclass=*)' -H ldaps://myserver.com -W

The output should look like:

version: 2

#
# filter: (objectclass=*)
# requesting: ALL
#

# myserver, com
dn: dc=myserver,dc=com
objectClass: dcObject
objectClass: organization
o: Example Org
dc: myserver

# my-name, myserver, com
dn: cn=my-name,dc=myserver,dc=com
objectClass: organizationalRole
cn: my-name

# my system, myserver, com
dn: ou=my system,dc=myserver,dc=com
objectClass: organizationalUnit
ou: my system
description: Test organizational unit to hold admin user

# mr admin, my system, myserver, com
dn: cn=mr admin,ou=my system,dc=myserver,dc=com
objectClass: person
userPassword:: dGVzdHBhc3M=
description: mr admin test user
cn: mr admin
sn: admin

# search result
search: 2
result: 0 Success

# numResponses: 5
# numEntries: 4
%

Return some entries (part one)

Command with output:

% ldapsearch -x -b 'cn=my-name,dc=myserver,dc=com' -D"cn=Manager,dc=myserver,dc=com" -H ldaps://myserver.com '(objectclass=*)' -w secret
version: 2

#
# filter: (objectclass=*)
# requesting: ALL
#

# my-name, myserver, com
dn: cn=my-name,dc=myserver,dc=com
objectClass: organizationalRole
cn: my-name

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

Return some entries (part two)
Command with output:

% ldapsearch -x -b 'ou=my system,dc=myserver,dc=com' -D"cn=Manager,dc=myserver,dc=com" -H ldaps://myserver.com '(objectclass=*)' -w secret
version: 2

#
# filter: (objectclass=*)
# requesting: ALL
#

# my system, myserver, com
dn: ou=my system,dc=myserver,dc=com
objectClass: organizationalUnit
ou: my system
description: Test organizational unit to hold admin user

# mr admin, my system, myserver, com
dn: cn=mr admin,ou=my system,dc=myserver,dc=com
objectClass: person
userPassword:: dGVzdHBhc3M=
description: mr admin test user
cn: mr admin
sn: admin

# search result
search: 2
result: 0 Success

# numResponses: 3
# numEntries: 2

7.0 Using TLS

Up to this point, most of the document has dealt with SSL and not TLS. SSL connections are always encrypted while TLS connections give the client the option to upgrade to an encrypted connection.

TLS requires the same configuration settings as SSL. Upon examination, all of the important SSL directives start with "TLS" in section 5.4 "Configuration Summary" which should have tipped you off to the dual relationship.

However, simply accessing ldap://:389 does not ensure a TLS encrypted connection. Accessing ldaps:// is not a TLS connection either. In order to use TLS over an ldap:// connection, add a ldap_start_tls_s() call to your client code:

int rc, port=389;
int ldap_version=LDAP_VERSION3;
LDAP *ld;
...
ld=ldap_init("myserver.com", port);
ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
rc = ldap_start_tls_s(ld, NULL, NULL);
...

Another difference between SSL and TLS in the above code is that SSL doesn't use ldap_init(). Instead it uses ldap_initialize(**LDAP, string) where the string is a URI, e.g. "ldaps://myserver.com:636". Attempting to use ldap_init() over SSL will cause a broken pipe error. Also, attempting to call ldap_start_tls_s() when an SSL connection is already utilized will also be in error.

Another TLS method that can be used is to add a "-Z" or "-ZZ" flag to client commands:

% ldapsearch -x -b 'dc=myserver,dc=com' -D "cn=Manager,dc=myserver,dc=com" '(objectclass=*)' -H ldaps://myserver.com -W -ZZ
...

The "-ZZ" flag forces TLS handshake to be successful. The single "-Z" flag tries to enable TLS and will proceed without using encrypted connections if the TLS handshake fails.

It would be nice to set a TLS configuration directive in either slapd.conf or ldap.conf but my attempts to do so have not resulted in a successful TLS handshake in the server output. OpenLDAP documentation does suggest using a "Start TLS" call in a configuration file which has not been successful for me.

8.0 Summary

As can be seen, enabling SSL/TLS on an OpenLDAP server and client can be achieved quickly. If client authentication is desired, then only a few more steps and changes are required. OpenLDAP manages the SSL connection once it knows where the server and CA certificates (client side) reside.

Although enabling an SSL connection to a server is straight forward if the steps outlined in this document are followed, problems can arise when trying to execute the LDAP client. OpenLDAP is sophisticated software with several nuances that take experience to understand and use correctly. Execution errors can arise when the following occurs:

  • Incorrect slapd.conf and ldap.conf entries.
  • Punctuation errors between slapd.conf entries (suffix, rootdn, rootpw) and the OpenLDAP client commands.
  • Accessing OpenLDAP server ports that have not been started.
  • Calling a "start tls" command on an SSL port. Calling this command on any SSL/TLS port is an error.
  • Making changes to the wrong slapd.conf and ldap.conf configuration files.
  • Incorrect password.
  • Not using a fully qualified domain name in the server certificate (very common!).

    ... just to name a few. However most problems with OpenLDAP are the result of human error and they will appear less frequently as OpenLDAP is more often utilized.