The first element of security that we will examine is network security. Most clients connect to OpenLDAP over a network interface, and client requests, as well as the server's responses, are transferred over a network.
The LDAP protocol, by default, sends and receives messages in clear text. In this case no attempt is made to obscure the data as it is being transmitted across the network. Sending in clear text has a few advantages:
But these advantages come at the cost of security. Other devices on the network may be able to intercept these unencrypted transmissions and read their contents and in doing so, they may obtain sensitive information. On a small Local Area Network (LAN) the risks may be smaller (though still present). On a large scale network, such as the Internet, the dangers are much greater.
In this section we will walk through the process of configuring Secure Sockets Layer (SSL) and Transport Layer Security (TLS) encryption to protect data as it is transmitted over a network. SSL and TLS are very similar, to the point where the terms are often used (acceptably) as synonyms. TLS though, is a refinement of SSL, and has been implemented in ways that are more flexible than the typical SSL implementation. The StartTLS method of securing a connection is an example.
OpenLDAP provides two methods for encrypting network traffic. The first is to have OpenLDAP listen on a special port for requests (port 636, the LDAPS port, is used by default). Transmissions on this port will automatically be encrypted. This method is older, introduced as an addition to LDAP v2, but it is no longer the preferred method.
The second method, which is part of the LDAP v3 standard, is to allow clients connecting over the standard port (usually port 389) to request to switch from clear text transmissions to encrypted transmissions. I will cover both configurations here.
Secure Sockets Layer (SSL) is a security process, originally developed by Netscape Communications for their web browser, designed to provide a safe way of exchanging trusted information between a server and any client on the network. There are two major features of the SSL process: establishing authenticity and conducting securely encrypted transactions.
As SSL developed and evolved it was handed over to a standard body, the Internet Engineering Task Force (IETF), for standardization and continued development. IETF renamed it Transport Layer Security (TLS) and released version 1.0 (as RFC 2246). SSL 3.0 and TLS 1.0 do not have any notable differences, and most servers that support one also support the other. Because of their similarity and shared heritage, I refer to them jointly as SSL/TLS.
Proving authenticity and providing encryption are the two major features of SSL/TLS. In regards to the first, SSL/TLS provides a way to establish the authenticity of the server (and, if desired, the client too). What this means is that SSL/TLS makes it possible for the client to be reasonably sure that the server belongs to whom it claims to belong.
Consider the case of online banking. If I use my browser to log on to my bank's website and conduct a few transactions, I want to be sure that the website I am connected to really is my bank's website, and not some other website masquerading as my bank. SSL/TLS provides tools to establish the authenticity of the server using X.509 certificates. An X.509 certificate has three important pieces of information:
A certificate is designed as a sort of assurance that a server is associated with a particular individual or organization. When I contact a server that I believe to be my bank's, I want some assurance that it is, in fact, my bank's server. So one piece of information contained in the certificate is information about who owns the certificate. We can inspect this information ourselves, but since the certificate has a digital signature, it is also possible for software to computationally verify this—in a way much more reliable than reading the certificate and simply trusting that the certificate is accurate.
The digital signature is an encrypted bit of information. It is encrypted with a special "private" key that is owned by a Certificate Authority. The CA can then issue a public key that client software can use to verify that the certificate was in fact signed by the CA. The CA then, plays a very important role in establishing trust. We will discuss public and private keys in the Encryption section.
Certificate Authorities are responsible for issuing certificates. Ideally, a CA is a trusted source that can verify the authenticity of the certificate, and provide assurance that the certificate is really owned by the organization or individual that claims to own it.
There are a number of commercial CAs that provide certificate generation services for a price. To obtain a certificate through these services, an organization or individual must provide a certain amount of information that can be used to verify that the person or organization signing up for the certificate is legitimate. Once investigation of this material has been done, and the person or organization has paid the requisite fee, the CA issues a digitally-signed certificate.
The certificates of large CAs are included by default in most SSL-aware applications, such as popular web browsers (like Mozilla Firefox) and SSL libraries (like OpenSSL). These certificates include the public keys necessary for verifying digital signatures. Thus, when a client gets an X.509 certificate that is signed by one of these CAs, it has all of the tools it needs to verify the certificate's authenticity.
But it is possible, and often useful, for an organization or individual to simply create a locally used CA, and then use that CA to generate certificates for in-house applications. This is what we will do when we create a certificate for OpenLDAP.
Of course, certificates generated this way may not be considered reliable to users outside of your organization, but hosting an individual or organization-wide CA can be an effective way to add security to your own network, without having to purchase certificates from a commercial vendor.
Not all CAs use the same form of authoritative signing (and not all CAs charge for certificates). Some CAs, such as Cacert.org, use what is called a web of trust technique for establishing authenticity. In the web of trust the authenticity of a certificate is established by peers who can play the role of assuring that the certificate is owned by the person or organization that it claims to be owned by. For more information visit http://www.cacert.org/.
We have discussed the first role of SSL/TLS, establishing authenticity. Next we will turn to the second role of SSL/TLS; providing encryption services.
SSL/TLS provides the features required for sending encrypted messages back and forth between the client and the server. In a nutshell the process goes like this: the server sends the client its certificate, and inside the certificate (among other things) is the server's public key. The public key is the first half of a pair of keys. A public key can be used for encrypting a message, but not decrypting it. A second key, the private key, is then used for decrypting a message. The server keeps its private key to itself, but gives out its public key to any client that requests it. Clients can then send messages to the server that only the server can decrypt and interpret.
Depending on the configuration the client also sends the server its public key, which the server can use to send messages that only the client can decrypt. At this point, each can transmit encrypted messages to the other.
But there is a drawback to using public/private keys: they are slow and resource-intensive. Rather than trading all information through these public/private key combos, the client and server then negotiate a set of temporary symmetric encryption keys (which use the same key to encrypt and decrypt messages) that they will both use for the duration of the session. All traffic between the two clients is encrypted using these keys. Once the session is complete, both the client and server discard the temporary keys.
For a more detailed introduction to SSL and TLS, as well as pointers to further sources of information, see the Wikipedia entry for Transport Layer Security: http://en.wikipedia.org/wiki/Transport_Layer_Security.
As it is typically implemented, SSL requires that the server listen for encrypted traffic on a port separate from the one it uses for unencrypted traffic. All traffic that comes over the SSL port is assumed to be SSL-encrypted traffic. This means that every server that needs to provide both cleartext and encrypted services must listen on at least two different ports.
The multi-port requirement seemed to some to be unnecessary, inelegant, and wasteful. There is no reason why the client should not be able to request on a cleartext (non-SSL) connection that further communication between the client and server be encrypted. The client and server could then perform all of the SSL/TLS negotiation over the same connection, and not have to switch to another SSL/TLS-only port. This suggestion was standardized in RFC2487 as StartTLS.
Which to Pick: StartTLS or LDAPS?
The standardized way of implementing SSL/TLS in LDAP v.3 is to use the StartTLS method. This method should be implemented whenever possible. However, external considerations (such as network firewalling or clients without StartTLS support) may require that you use LDAPS and a dedicated SSL/TLS-protected port. LDAPS support is now listed as deprecated, though it is not yet slated for removal from OpenLDAP. Both options can be used on the same server.
In a StartTLS-supporting server, if the client sends the server the command STARTTLS
then the server will begin the TLS encryption process. Assuming the TLS negotiation is successful, the client and server will then continue their transactions using encrypted traffic.
StartTLS has the obvious advantage of requiring only one listening port per server. And, it makes it possible for clients and servers to communicate in cleartext for unimportant data, and then switch over to TLS when security becomes important. Since encryption is resource intensive, requiring extra processing power to encrypt and decrypt messages, streamlining services the StartTLS way can improve performance and free up resources for other tasks.
There is a drawback for StartTLS though. Since both encrypted and cleartext traffic are sent over the same port, the method of simply blocking a port to prevent insecure data transmissions (by using a firewall for instance) is not effective with StartTLS. Security measures must be capable of inspecting transmissions at the protocol level.
In order to improve security services in such cases, OpenLDAP provides methods of testing the security strength factor (SSF) of a connection to see if it is encrypted (and if so, if the encryption scheme is strong enough). We will look at SSF in more detail later in this chapter in the section on Using Security Strength Factors.
At this point, you should have a fairly good idea of how SSL and TLS function. Now we will move on to more practical matters. We will create our own CA, and our own certificate, and then configure OpenLDAP to support SSL/TLS and StartTLS.
In order to create a Certificate Authority and generate certificates, you will need to have OpenSSL installed. Since many Ubuntu packages, including the OpenLDAP packages, require OpenSSL, it should be installed already.
If you build from source, as detailed in Appendix A, you may also enable support for SSL/TLS using the OpenSSL libraries.
The first thing we will need to do is create our new CA.
While it is possible to manually configure your CA using the openssl
command line tool, it is much simpler to use the CA.pl
Perl script that is included with OpenSSL. This script streamlines many of the configuration options for OpenSSL, and the first thing that we will use it for is creating the environment for our new CA.
Ubuntu maintains documentation on creating a new Certificate Authority the "long way" (creating all of the files by hand). This documentation is detailed and well worth reading. While I will follow the conventions established there, I will be using the CA.pl
script to do most of the heavy lifting (https://help.ubuntu.com/community/OpenSSL).
You can put the CA environment anywhere on your system. Some prefer to keep CA files with the rest of the SSL configuration at /etc/ssl/
. Others prefer keeping the certificate authority in a user directory so that it does not get overwritten during system upgrades (an unlikely, but possible, event). In keeping with the Ubuntu suggestion to keep CA info in a user's home directory, I will just put mine in my home directory, /home/mbutcher/
:
$ cd ~ $ /usr/lib/ssl/misc/CA.pl -newca
Note that the CA.pl
script is not in $PATH
, so you will need to type in the entire path to the script.
The argument -newca
instructs CA.pl
to set up a new certificate authority environment. This will generate a directory structure along with a number of files.
The first thing that CA.pl
will do is prompt you to enter a CA file:
$ /usr/lib/ssl/misc/CA.pl -newca CA certificate filename (or enter to create)
Hit Enter to create a new CA certificate. CA.pl
will then generate a new key and then prompt you for a password:
CA certificate filename (or enter to create) Making CA certificate Generating a 1024 bit RSA private key ....++++++ ...................................++++++ unable to write 'random state' writing new private key to './demoCA/private/cakey.pem' Enter PEM pass phrase: Verifying - Enter PEM pass phrase: -----
Once you have entered and re-entered your password, CA.pl
will collect some information from you about your organization:
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]:Illinois Locality Name (eg, city) []:Chicago Organization Name (eg, company) [Internet Widgits]:Example.Com Organizational Unit Name (eg, section) []: Common Name (eg, YOUR name) []:Matt Butcher Email Address []:matt@example.com Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:mypassword An optional company name []:Example.Com
CA.pl
walks you through the process of creating a main certificate. The highlighted lines in the code listing are those where you will have to provide information at an interactive prompt. After setting the country, state, and city name for my locale, we set the Organization Name to Example.Com. While we left the Organizational Unit field blank, you can use that to further specify what part of the organization this CA is a member of.
Usually the Common Name and Email Address fields should contain information about the organization. Sometimes Common Name is used for the server name (as will be the case when we create our certificate). Sometimes, it is used for contact information. In the case that follows, we used my name and email. If the CA is to be the "official" CA for your organization, you should set this to the official contact person for certificate inquiries.
Next, CA.pl
will begin the process of generating a certificate request for the CA certificate. In other words, CA.pl
will create a new certificate that will be the CA's own certificate. The first step in doing this is to create a certificate request. We will need to set a challenging password for the certificate request. We can also set a company name too. With the above information, CA.pl
will continue the process of generating a new certificate:
Using configuration from /usr/lib/ssl/openssl.cnf Enter pass phrase for ./demoCA/private/cakey.pem: Check that the request matches the signature Signature ok Certificate Details: Serial Number: bf:2f:58:47:b1:6d:31:4d Validity Not Before: Oct 10 21:34:28 2006 GMT Not After : Oct 9 21:34:28 2009 GMT Subject: countryName = US stateOrProvinceName = Illinois organizationName = Example.Com commonName = Matt Butcher emailAddress = matt@example.com X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 07:92:9B:35:CB:B7:EE:92:A8:33:61:B0:DC:F7:88:E9:4F:06:9F:7F X509v3 Authority Key Identifier: keyid:07:92:9B:35:CB:B7:EE:92:A8:33:61:B0:DC:F7:88:E9:4F:06:9F:7F Certificate is to be certified until Oct 9 21:34:28 2009 GMT (1095 days) Write out database with 1 new entries Data Base Updated
We will be prompted to enter a pass phrase. This is the pass phrase we created first (when prompted to Enter PEM pass phrase). If we enter the pass phrase correctly, CA.pl
will generate our new certificate and display its contents on the screen.
We have now created a Certificate Authority. Now we are ready to start generating a certificate to be used by SLAPD.
Due to a bug in some versions of CA.pl
, you may have to cd
into the ./demoCA
directory (the directory that CA.pl -newca
created) and add a symbolic link to itself: ln -s ./demoCA
. This is because CA.pl
occasionally expects to find files in the current directory (./
), which it assumes to be demoCA/
, and sometimes it expects to find files in ./demoCA
(which, of course, is equivalent to demoCA/demoCA/
). You can also fix this simply by editing the dir=
line under [CA_default]
in the /etc/ssl/openssl.cnf
file, and setting it to an absolute path.
Creating a certificate is a two-step process:
Let's see these steps in detail.
The first step in creating a valid SSL certificate is to create a Certificate Request. In the process, we will specify what information we want to show up on the certificate.
There are a few ways to generate Certificate Requests. For example, you can use the openssl
command line tool and specifying a number of command line parameters. But, following our previous example, we will use CA.pl
and let the application prompt us for information as is necessary.
To generate a new request we will run CA.pl -newreq
. In the next example the highlighted lines are lines that require us to enter information:
$ /usr/lib/ssl/misc/CA.pl -newreq Generating a 1024 bit RSA private key .....++++++ .....................++++++ unable to write 'random state' writing new private key to 'newkey.pem' Enter PEM pass phrase: Verifying - Enter PEM pass phrase: ----- 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]:Illinois Locality Name (eg, city) []:Chicago Organization Name (eg, company) [Internet Widgits]:Example.Com Organizational Unit Name (eg, section) []: Common Name (eg, YOUR name) []:example.com Email Address []:matt@example.com Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: Request is in newreq.pem, private key is in newkey.pem
This should look familiar. It is similar in most respects to the process of generating a Certificate Authority.
First, we will be prompted to enter a pass phrase. We will use this pass phrase in a few moments.
Next, we will be asked to supply information about the organization that this certificate will represent. As before the fields are Country Name, State/Province Name, Locality, Organization Name, Organizational Unit, Common Name (of the contact person), and the Email for the contact person. Again, as before, we entered the information for Example.Com.
This time, however, we set the Common Name field to be the domain name of the server that the certificate is for—example.com
. It is very important that you use the correct domain name for the server. During the certificate negotiation process clients will check the Common Name field to see if it matches the domain name of the server. If the names do not match the user may get an error message, or the client application may simply terminate the connection.
The extra password and optional company name are sometimes used in the certificate request process. Since we are doing the requesting and the signing ourselves we don't need to complete either of these fields.
Now we should have two files in the CA directory:
newreq.pem
, which contains a base-64 encoded representation of our certificate requestnewkey.pem
, which contains the base-64 encoded private keyWe are now ready to move on to the second step.
The Certificate Request has all of the information required for a certificate, but it still lacks the digital signature of the CA. The next step, then, will be to use the CA we created previously to sign this new certificate. To do this, we will run CA.pl -signreq
:
$ /usr/lib/ssl/misc/CA.pl -signreq Using configuration from /usr/lib/ssl/openssl.cnf Enter pass phrase for ./demoCA/private/cakey.pem: Check that the request matches the signature Signature ok Certificate Details: Serial Number: ba:49:df:f5:8e:7e:77:c2 Validity Not Before: Oct 12 21:23:49 2006 GMT Not After : Oct 12 21:23:49 2007 GMT Subject: countryName = US stateOrProvinceName = Illinois localityName = Chicago organizationName = Example.Com commonName = example.com emailAddress = matt@example.com X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 47:DD:90:8F:79:90:2E:C0:CC:B3:95:62:35:C4:D8:6C:5D:A2:EE:88 X509v3 Authority Key Identifier: keyid:6B:FB:66:33:5D:DB:CC:40:42:D7:71:F7:F0:D0:7C:94:3E:8F:CD:58 Certificate is to be certified until Oct 12 21:23:49 2007 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 Signed certificate is in newcert.pem
The CA.pl -signcert
command looks for newreq.pem
and then begins the signing process. First, we need to enter the pass phrase for the CA. If that is correct, then CA.pl
will display the certificate in newreq.pem
and ask if we want to sign it. Finally, it will ask us to commit these changes.
Once the changes are committed a new file will be created, named newcert.pem
.
There are two important files that we now have:
newkey.pem
, which contains the private keynewcert.pem
, which contains the signed certificate.We've just got a few loose ends to tie up, and then we can move on to configuring SLAPD to use SSL/TLS.
We have only three more steps to do, here. The first one has to do with the pass phrase we set on our certificate.
Be very careful here! When generating our certificate request, we set a pass phrase on the certificate. This encrypted the newkey.pem
file with a pass phrase.
If you use a key file that is encrypted with a pass phrase, then every time you use this certificate, you will have to enter a password. This means, in our case, that every time we start OpenLDAP, we will have to enter a pass phrase. Unless we have stringent security requirements (and are willing to put up with the hassle of typing the pass phrase every time we start or restart the server), we probably do not want the key file to be encrypted.
So, we will need to create an unencrypted version of the key file using the openssl
command:
$ openssl rsa < newkey.pem > clearkey.pem
This is what we get:
Enter pass phrase: writing RSA key
In this example the command openssl rsa
executes the OpenSSL RSA tool, which will decrypt the key. Using < newkey.pem
, we sent the file contents of newkey.pem
into openssl
to be decrypted. Then, using > clearkey.pem
we directed openssl
to write the cleartext key file to the clearkey.pem
file. In order to complete this operation, openssl
prompts for the pass phrase. Now clearkey.pem
has the unencrypted private key for our certificate.
The openssl Program
The openssl
program performs dozens of SSL-related functions, from generating certificates to emulating a network-based SSL client. Its syntax is notoriously difficult though. That is why we have been using the CA.pl
wrapper script to perform common tasks. But some tasks can only be done with the openssl
command. Should you need them though, openssl
has excellent man pages: man openssl
.
The second task is to move our new certificate and key to a useful location on the server, and give the PEM files useful names as well. If this certificate is to be used by lots of different services, it might make sense to locate it in the shared directory. But for our cases we will only be using the SSL certificate for LDAP, so we can put the files in /etc/ldap/
(or /usr/local/etc/openldap/
if you built from source).
The two files with which we are concerned are newcert.pem
and clearkey.pem
. We need to rename and move those two keys:
$ sudo mv cacert.pem /etc/ldap/example.com.cert.pem $ sudo mv clearkey.pem /etc/ldap/example.com.key.pem
Now, we need to set permissions and ownership on the certificate files. Since we did not add a pass phrase to the key, we should also make sure that only the OpenLDAP user can read the key file:
$ sudo chown root:root /etc/ldap/example.com.*.pem $ sudo chmod 400 /etc/ldap/example.com.key.pem
The first line changes the owner and group of the two PEM files to the root
user and the root
group. The second line sets the mode so that only the owner can read the file, and no one else has any access.
If you are running OpenLDAP as a user other than root (and it is a good idea to do so), then the files should be owned by that user instead of root; for example chown oenldap example.com.*.pem
.
The third task is to install the CA's public certificate so that other applications on the system can use that certificate to verify the authenticity of the certificate we just generated. First, we need to copy the CA certificate to the local certificate database for Ubuntu. In the process we will give it a user-friendly name:
$ sudo cp cacert.pem /usr/share/ca-certificates/Example.Com-CA.crt
Then, edit the /etc/ca-certificates.conf
file, and add Example.Com.crt
at the end of the file.
Finally, run update-ca-certificates
:
$ sudo update-ca-certificates Updating certificates in /etc/ssl/certs....done.
The CA certificate has now been installed. The /etc/ssl/certs
directory is now the authoritative source for CA certificates.
If you want, you can do a little clean-up in the CA directory. Delete the encrypted key file and the certificate request file, both of which are in the demoCA/
directory:
$ rm newkey.pem newreq.pem
Also, make sure clearkey.pem
is no longer present in the demoCA/
directory.
Now we are ready to configure OpenLDAP to use our new certificates. First, we will configure StartTLS support, which is the easiest, then we will configure SSL/TLS support on the LDAPS port, port 636.
In the previous sections we created our new certificate and key, and placed the two files in the /etc/ldap
directory. In this section we will set up StartTLS (which we introduced earlier in this chapter in the StartTLS section). Setting up StartTLS requires only a few extra lines in the slapd.conf
file.
Again, StartTLS is the standard way (according to RFC 4511) of providing SSL/TLS security to OpenLDAP. For security reasons support for StartTLS should be provided whenever practical.
In the slapd.conf
file, just before the BDB Database Configuration
section, insert the SSL/TLS options:
########### # SSL/TLS # ########### TLSCACertificatePath /etc/ssl/certs/ TLSCertificateFile /etc/ldap/example.com.cert.pem TLSCertificateKeyFile /etc/ldap/example.com.key.pem
Basically, there are only three directives we need to specify to get StartTLS working:
TLSCACertificatePath
, tells SLAPD where to find all of the CA certificates that it will need for verifying certificates. The definitive location is, as we saw before, the /etc/ssl/certs/
directory.TLSCertificateFile
, specifies the location of the signed certificate.TLSCertificateKeyFile
, specifies the location of the corresponding key file, which has the private encryption key for the certificate.There are a handful of other TLS-specific directives that allow you to provide detailed constraints on TLS connections (such as which suites of ciphers can be used, and whether the client needs to provide a certificate to the server). Complete documentation on these can be found in the TLS section of the slapd.conf
man page: man slapd.conf
.
That's all we need to get SLAPD to perform StartTLS. Restart SLAPD so that the changes take effect.
We do need to add a directive or two to ldap.conf
—the configuration file that the OpenLDAP clients use. As with SLAPD, we need to direct the clients to the correct location of the new CA certificate so that they can verify the server certificate.
At the bottom of the ldap.conf
file we can add the appropriate directive:
TLS_CACERTDIR /etc/ssl/certs
Clients will use this directive to locate the CA certificates for checking digital signatures on the certificates they get from servers. If you know that you are only going to use certificates signed by a specific CA, you can use the TLS_CACERT
directive to point to a specific CA certificate file, instead of a directory containing one or more certificates.
By default, OpenLDAP clients always perform a check on the digital signatures. If a server sends a certificate that was signed by a CA other than those at /etc/ssl/certs/
(or whatever directory TLS_CACERTDIR
points to), then the client will close the connection and print an error message to the screen.
Sometimes though, the correct CA certificate is not available, and it is worthwhile to get the encryption support of TLS even if it is not possible to verify the identity of the server.
In such cases you may find it necessary to change the way OpenLDAP clients perform identification checks. For example, it might be desirable to try to verify the certificate, but to continue with the connection even if there is no appropriate CA locally. To accomplish this, use the following directive in slapd.conf
:
TLS_REQCERT allow
In this case, if there is no CA certificate or if the certificate sent cannot be verified, the session will continue, rather than exiting with an error message. TLS_REQCERT
has a few different levels of checking, ranging from strict
(always verify) to never
(do not even bother trying to verify certificates).
At this point, we can use ldapsearch
to test a connection. To instruct a client to use StartTLS, we need to use the -Z
flag. But if just -Z
is specified, if the client fails TLS negotiation with the server, it will continue with the transaction in clear text. In other words, with -Z
, TLS is preferred, but not required. To make TLS required, we will add an extra z to the flag, making it -ZZ
:
$ ldapsearch -LLL -x -W -D 'cn=Manager,dc=example,dc=com' -H \ ldap://example.com -ZZ '(uid=manny)'
This should prompt for a password and then return one result:
Enter LDAP Password: dn: uid=manny,ou=Users,dc=example,dc=com sn: Kant uid: immanuel uid: manny ou: Users objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson givenName: Manny cn: Manny Kant
If the result comes back like this, then TLS was successfully configured. But TLS can be difficult to get configured because it is strict by design. Small errors in configuration (like using a domain name that differs from the one in the CN field of the certificate) can prevent TLS from working. Consider this example:
$ ldapsearch -LL -x -W -D 'cn=Manager,dc=example,dc=com' -H \ ldap://localhost -ZZ '(uid=manny)' ldap_start_tls: Connect error (-11) additional info: TLS: hostname does not match CN in peer certificate
In this case, the host name specified on the command line (localhost
) differed from the one in the CN field of the certificate (example.com
). Even though, in this case, the two domain names are hosted on the same system, TLS will not accept the mismatch.
Other common errors in TLS are:
TLSCertificateFile
and the TLSCertificateKeyFile
directivesldap.conf
While OpenLDAP can be forgiving in many areas, TLS configuration is not one of them. It pays to take extra care when configuring TLS and SSL.
Now that we have configured TLS, we need to take only a few additional steps to enable SSL/TLS on its own port. The traditional port for running dedicated TLS/SSL-protected LDAP traffic is port 636, the LDAPS port.
Most of the time it is better to use StartTLS. However, network considerations (like clients that do not support StartTLS or policies dictating mandatory blocking on ports that allow non-encrypted text) might warrant using LDAPS.
Keep in mind that LDAPS and StartTLS can both be used for the same server. SLAPD can accept LDAPS traffic on a dedicated port, and continue to provide the StartTLS feature on an LDAP port.
Getting SLAPD to listen on this port requires passing an additional parameter when starting slapd
. In Ubuntu, as with other Debian-based distributions, configuration parameters can be set in the /etc/defaults/slapd
file. In that file we just need to set SLAPD_SERVICES
. When the start script is executed, SLAPD will start all of the services listed here.
SLAPD_SERVICES="ldap:/// ldaps:///"
The given code tells SLAPD to listen on all available IP addresses on both the default LDAP (port 389) and the default LDAPS (port 636). If we wanted SLAPD to only listen on one address for LDAP traffic, but all addresses for LDAPS traffic, we could replace the above with:
SLAPD_SERVICES="ldap://127.0.0.1/ ldaps:///"
Here, the ldap://127.0.0.1/
tells SLAPD to only listen on the loopback address for LDAP traffic, while ldaps:///
indicates that SLAPD should listen for LDAPS traffic on all of the IP addresses configured for this host. You will need to restart SLAPD in order for these changes to take effect.
Similarly, if you built from source and want to start slapd
directly, the -h
command line flag lets you specify which services to start:
/usr/local/libexec/slapd -h "ldap:/// ldaps:///"
That is all there is to configuring LDAPS. We can now test it with ldapsearch
:
ldapsearch -LL -x -W -D 'cn=Manager,dc=example,dc=com' -H \ ldaps://example.com '(uid=manny)'
There are two crucial differences between this ldapsearch
and the ones we used when testing StartTLS:
-H
flag is ldaps://
rather than ldap://
.-Z
or -ZZ
flag here. Those flags tell the client to send the StartTLS command, and SSL/TLS over a dedicated port do not recognize the StartTLS command.If you get an error doing the given search, but StartTLS is working properly, the first place to look is at the firewall settings. Typically, firewalls allow traffic on port 389, but block 636. It is also useful to make sure that the server is actually listening on port 636. You can check this from a shell prompt using netstat –tcp -l
, which will print out a list of what ports are being used. If LDAPS (636) does not show up, then check /etc/defaults/slapd
again to make sure that the SLAPD_SERVICES
directive is set correctly.
In some cases it is useful to be able to connect to SLAPD over LDAPS and watch the certificate processing. The openssl
program can do this with its built-in s_client
client application:
$ openssl s_client -connect example.com:636
The -connect
parameter takes a host name followed by a colon and a port number. When this command is run, openssl
will connect to a remote server using SSL, and perform the certificate negotiation. The entire negotiation process is written to the screen. If certificate negotiation succeeds, then openssl
leaves the connection open, and you can type in raw protocol commands at the command line. To exit, just hit CTRL+C.
Now we have both StartTLS and TLS/SSL working. We have one more short item to cover in this section, and then we will move on to authentication.
There are advantages to running StartTLS. It is simpler to configure, it is easier (in many respects) to debug, and complex transactions can switch back and forth from cleartext to encryption as needed.
But there is one clear drawback: we can use a standard firewall to block non-encrypted traffic when all clear text goes over one port and all encrypted traffic goes over another. But when both go over the same port, many firewalls can't do much to verify that the traffic is secure.
But OpenLDAP does provide some tools for implementing this sort of security in SLAPD, instead of in a firewall.
OpenLDAP can examine the integrity and encryption state of a connection and, based on those features, assign a Security Strength Factor (SSF) to that connection. An SSF is a numeric representation of the strength of the protective measures used.
Most of the SSF numbers simply reflect the key length of the encryption cipher. For example, since the maximum key length for DES is 56, when a connection is protected using DES, the SSF is 56. Triple-DES (3DES), which is the cipher used by default in Ubuntu's OpenSSL configuration, has a key length of 112. Hence, its SSF is also 112. The AES cipher, which is strong and can be computed quickly, can use different key sizes. AES-128 uses a 128-bit key, while AES-256 uses a 256-bit key. In the case of AES then, the SSF will reflect the key size.
There are two special SSF numbers: 0 and 1. An SSF of 0 indicates (as might be expected) that no security measures have been implemented. An SSF of 1 indicates that only integrity checking on the connection is being done.
OpenLDAP can use SSF information to determine whether a client is allowed to connect to the directory. SSF information can also be used in ACLs and in SASL configuration, effectively allowing complex rules to be built as to what conditions a client connection must satisfy before getting access to perform certain operations on the directory.
We will look at SASL authentication and ACLs later in this chapter, but right now we will look at using SSFs in the security
directive in slapd.conf
as a way of specifying how secure a connection must be in order to access the database.
The security
directive can be used in two different contexts in slapd.conf
. If it is put near the top of the file, before any backend databases are defined, then it is placed in the global context and will apply to all connections. On the other hand, if the security directive is placed within a backend definition, then it will only be applied to that particular database. For example, consider a case where there are two backends:
include /etc/ldap/schema/core.schema modulepath /usr/local/libexec/openldap moduleload back_hdb # Other configuration directives ... # DB 1: database hdb suffix "ou=Users,dc=example,dc=com" # More directives for DB 1... # DB 2: database bdb suffix "ou=System,dc=example,dc=com" # More directives for DB 2...
This partial example of a slapd.conf
file defines two directory backends. Now, if the security
directive is used before the first database is defined (namely before the line that says database hdb
), then it will be applied globally to all connections.
But if we wanted to allow non-encrypted connections to DB 2, but allow only well-encrypted connections to DB 1 (which houses all of our user entries), we could use separate security
directives:
include /etc/ldap/schema/core.schema modulepath /usr/local/libexec/openldap moduleload back_hdb loglevel stats # Other configuration directives ... # DB 1: database hdb suffix "ou=Users,dc=example,dc=com" security ssf=112 # More directives for DB 1... # DB 2: database bdb suffix "ou=System,dc=example,dc=com" security ssf=0 # More directives for DB 2...
Note the addition of the two highlighted lines—two separate security
directives, one for each database backend.
Now, restarting the directory (note that the loglevel
is set to stats
), we can test out the security parameters with ldapsearch
. First, we will try to search the Users
OU with a non-TLS connection:
$ ldapsearch -x -W -D 'uid=matt,ou=Users,dc=example,dc=com' -b \ 'ou=Users,dc=example,dc=com' '(uid=david)' uid
In the log we see entries like this:
conn=0 fd=12 ACCEPT from IP=127.0.0.1:48758 (IP=0.0.0.0:389) conn=0 op=0 BIND dn="uid=matt,ou=Users,dc=example,dc=com" method=128 conn=0 op=0 RESULT tag=97 err=13 text=confidentiality required conn=0 fd=12 closed (connection lost) connection_read(12): no connection!
The third line indicates that the server returned error number 13: confidentiality required
. This is because we did not do anything to protect the connection. Using simple authentication (which is not encrypted) and failing to use TLS/SSL resulted in the client connection having an effective SSF of 0.
Next, let's do the same search with TLS turned on:
$ ldapsearch -x -W -D 'uid=matt,ou=Users,dc=example,dc=com' -b \ 'ou=Users,dc=example,dc=com' -Z '(uid=david)' uid
Note that in this example, the -Z
flag is included to send the StartTLS command. Now, the server log says:
conn=1 fd=12 ACCEPT from IP=127.0.0.1:44684 (IP=0.0.0.0:389) conn=1 op=0 STARTTLS conn=1 op=0 RESULT oid= err=0 text= conn=1 fd=12 TLS established tls_ssf=256 ssf=256 conn=1 op=1 BIND dn="uid=matt,ou=Users,dc=example,dc=com" method=128 conn=1 op=1 BIND dn="uid=matt,ou=Users,dc=example,dc=com" mech=SIMPLE ssf=0 conn=1 op=1 RESULT tag=97 err=0 text=
There are a few things to note about this result. On the second line, OpenLDAP reports that it is doing StartTLS. Two lines later it reports: TLS established tls_ssf=256 ssf=256
. This line indicates that the TLS connection has an SSF of 256 (since the connection is using AES-256), and that the total SSF of the connection is 256.
If you look a few lines lower, on the second line that begins BIND
, you will notice that there another SSF is reported: ssf=0
. Why?
OpenLDAP measures SSF on various aspects of the connection. First, as we can see above, it checks the SSF of the network connection. TLS/SSL connections are assigned an SSF based on their cipher strength.
But during the bind phase when the client authenticates to the directory, OpenLDAP also measures the SSF of the authentication mechanism. The simple (mech=SIMPLE
) authentication mechanism does not encrypt the password, and so it is always given an SSF of 0.
The total SSF for the connection, however, remains at 256, with the TLS SSF being 256 and the SASL SSF at 0.
The security
directive that we have looked at so far is basic. It simply requires that the overall SSF be 112 (3DES encryption) or greater, but we can make it more specific.
For example, we can simply require that any TLS connection have at least a 128 bit key:
security tls=128
This will require that all incoming connections use TLS with a strong (128 bit or greater) cipher.
In some cases it is desirable to define which TLS/SSL ciphers or cipher families will be used. This cannot be done with the security
directive. Instead, you will need to use the TLSCipherSuite
directive, which will allow you to give a detailed specification for which ciphers are acceptable for TLS/SSL connections.
Or, if we only wanted to define a strong SSF for connections that try to perform a simple bind (as opposed to an SASL bind), then we can specify an SSF just for simple binding:
security simple_bind=128
This will require that some strong TLS cipher be used to protect the authentication information.
You can also use the update_ssf
keyword in the security
directive to set the SSF necessary for updating operations. Thus you could specify that only low-grade encryption is needed for reading the directory, but high-grade encryption must be used for performing updates to directory information:
security ssf=56 update_ssf=256
In the coming section, we will look at SASL configuration. You can use the security
directive to set SSF for SASL binding as well using the sasl=
and update_sasl=
phrases.
Finally, in rare cases where OpenLDAP is listening on a local socket (that is, ldapi://
), you can use security transport=112
(or whatever cipher strength you desire) to ensure that traffic coming over that socket is encrypted.
At this point, we have completed our examination of SSL and TLS. Next, we will move on to the second of our three aspects of security: authentication.