Performing a secure LDAP query using STUNNEL

Introduction

A problem has arisen recently in a project implementation.  The vendor supplied software cannot use LDAPS to query our LDAP servers over a secure connection. They only support the clear-text LDAP queries.

A possible fix for this solution would be to use the software package stunnel (http://www.stunnel.org) to create a secure SSL connection between the application server and the LDAP server.

What is STUNNEL?

Stunnel is a program that allows you to encrypt arbitrary TCP connections inside SSL (Secure Sockets Layer) available on both UNIX and Windows. Stunnel can allow you to secure non-SSL aware daemons and protocols (like POP, IMAP, LDAP, etc) by having stunnel provide the encryption, requiring no changes to the daemon’s code.

The stunnel program uses the OpenSSL library to provide the necessary encryption routines.  The source code for each of these packages has been released under the GNU General Public License.  This allows for free distribution and use of the resulting binaries.

Overview of System

The software application needs to query an LDAP server to obtain information.  It understands how to bind and authenticate using certificates, but it is unable to establish a secure SSL connection to the LDAP server.  So any data passed between the application server and the LDAP server would be in clear-text.  This puts the data at risk of being intercepted as it travels across the network.  The data being queried from the LDAP server in our case is considered to be confidential and would pose liability issues if it were appropriated and misused.

The stunnel program will be used as a shim between the application server and the LDAP server to communicate over an encrypted network connection.  Stunnel will be configured to work in ‘client’ mode and be running on the application server and listening on TCP port 389.  When a connection is established to this port on the application server the stunnel server will establish an SSL encrypted connection to the LDAP server on TCP port 636.  The encryption uses a public key obtained during the setup of the stunnel server and stored locally.

The LDAP service running on the LDAP server is already configured to accept SSL connections on TCP port 636.  Due to the nature of TCP listener daemon multiple connections can be established between the machines.

It appears as if the application program establishes a new connection to the LDAP Server every time it queries for information.  This is not efficient but should not pose a problem for this configuration.

Implementation and Configuration

The compilation, installation, and configuration of the stunnel program are simple and straight forward.  These procedures will be detailed below to allow for recreation if necessary.  The stunnel binaries and configuration files will be incorporated into the server images so most of the following will be for reference purposes only.

Obtaining the stunnel source code

The source code package can be downloaded from www.stunnel.org or one of the official mirror sites.  The version currently being used is 4.55.

Using either web browser or a command utility such as wget, the compressed tar file of the stunnel source code will need to be retrieved. The PGP signature file is also available and can be used to verify the authenticity of the source code.  To verify the signature, the maintainer’s PGP Public key, available at http://mike.mirt.net/pgp.asc, and a copy of PGP or GNU-PG will also be needed.

To retrieve the file from www.stunnel.org directly using wget:

$ wget http://www.stunnel.org/download/stunnel/src/stunnel-4.55.tar.gz
–15:41:06–  http://www.stunnel.org/download/stunnel/src/stunnel-4.05.tar.gz => `stunnel-4.05.tar.gz’
Connecting to http://www.stunnel.org:80… connected!
HTTP request sent, awaiting response… 200 OK
Length: 341,191 [application/x-tar]
0K ………. ………. ………. ………. ………. 15% @  88.81 KB/s
50K ………. ………. ………. ………. ………. 30% @ 145.35 KB/s
100K ………. ………. ………. ………. ………. 45% @ 145.77 KB/s
150K ………. ………. ………. ………. ………. 60% @ 145.35 KB/s
200K ………. ………. ………. ………. ………. 75% @ 159.74 KB/s
250K ………. ………. ………. ………. ………. 90% @ 145.77 KB/s
300K ………. ………. ………. …                  100% @ 141.25 KB/s
15:41:10 (134.08 KB/s) – `stunnel-4.05.tar.gz’ saved [341191/341191]

$ wget http://www.stunnel.org/download/stunnel/src/stunnel-4.05.tar.gz.asc
=> `stunnel-4.05.tar.gz.asc’

Connecting to http://www.stunnel.org:80… connected!

HTTP request sent, awaiting response… 200 OK
Length: 189 [text/plain]
0K                                                       100% @ 184.57 KB/s
15:42:37 (184.57 KB/s) – `stunnel-4.05.tar.gz.asc’ saved [189/189]
$

Verifying the signature will be left as an exercise for the reader.

After downloading and verifying the authenticity of the source code tarball, the tarball will need to be unzipped and untarred to complete the next steps.  A command line that will do this is:

$ gunzip –c stunnel-4.55.tar.gz | tar xvf –

The file will be decompressed to stdout and the tar command will use the stream from stdin and separate the files from the tarball.

Configuring and Compiling the stunnel program

After the source code has been extracted from the compressed tarball, the source code and necessary build files will need to be prepared for the hardware platform and operating system.  This is also the opportunity to activate some of the non-default features of the resulting binaries.

To prevent other systems from connecting to the stunnel server, tcp-wrapper can be used to limit the access.  Stunnel has the ability to use the tcp-wrapper model if it is enabled when the binaries are built. To enable this option the configure command must be run with the switch –with-tcp-wrappers.

The configure command that was used is:

$ cd stunnel-4.55
$ ./configure –with-tcp-wrappers
checking for a BSD-compatible install… /usr/bin/install -c
checking whether build environment is sane… yes
checking whether make sets $(MAKE)… yes
.
.
.
config.status: creating doc/Makefile
config.status: creating tools/Makefile
config.status: creating tools/stunnel.conf-sample
config.status: creating tools/stunnel.init
$

After the build environment has been created, use the “make” command to build the binary files and the SSL certificate.  The certificate will be necessary if stunnel will be used in server mode, but to use it client mode it will not be used.  Even though it does not need the certificate the stunnel program will not start if it does not have a valid certificate.

$ make
Making all in src
make[1]: Entering directory `./../stunnel-4.05/src’
/bin/sh ../libtool –mode=compile gcc -DPACKAGE_NAME=\”stunnel\” -DPACKAGE_TARNAME=\”stunnel\” -DPACKAGE_VERSION=\”4.05\” –
.
.
.
Making all in tools
make[1]: Entering directory `./../stunnel-4.05/tools’
if test -r “/dev/urandom”; \
then dd if=”/dev/urandom” of=stunnel.rnd bs=256 count=1; \
RND=”-rand stunnel.rnd”; \
else RND=””; fi; \
/usr/bin/openssl req -new -x509 -days 365 -nodes $RND \
-config ./stunnel.cnf -out stunnel.pem -keyout stunnel.pem; \
test 0 -eq 0 || /usr/bin/openssl gendh $RND 512 >> stunnel.pem

1+0 records in
1+0 records out

Generating a 1024 bit RSA private key
…………++++++
………………++++++
writing new private key to ‘stunnel.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) [PL]:US
State or Province Name (full name) [Some-State]:Pennsylvania
Locality Name (eg, city) []:Pittsburgh
Organization Name (eg, company) [Stunnel Developers Ltd]: Acme, Inc
Organizational Unit Name (eg, section) []:Widgets Calibration
Common Name (FQDN of your server) [localhost]:foo.acme.com

/usr/bin/openssl x509 -subject -dates -fingerprint -noout \
-in stunnel.pem
subject= /C=US/ST=Pennsylvania/L=Pittsburgh/O=Acme Inc/OU=Widget Calibration/CN=foo.acme.com
notBefore=Jun 16 20:47:49 2004 GMT
notAfter=Jun 16 20:47:49 2005 GMT

MD5 Fingerprint=7A:18:8E:2D:83:3E:F1:1E:1C:D9:37:76:A4:11:B8:4C

make[1]: Leaving directory `./../stunnel-4.05/tools’
make[1]: Entering directory `./../stunnel-4.05′
make[1]: Nothing to be done for `all-am’.
make[1]: Leaving directory `./../stunnel-4.05′
$

To install the binaries and default configuration files on the current machines, in the same build directory type:

$ make install

This command will install the binaries and configuration files into their default location.  For consistency after the compiled and configured, an installation package will be built containing the stunnel binaries and configuration files.

Configuring STUNNEL

In this instance, the desired use of stunnel was to allow a non-SSL secured LDAP client to communicate with an SSL secured LDAP server.  The LDAP client and the stunnel daemon will be running on the same machine.  So it will be necessary to configure stunnel to function in client mode.

The directory that stunnel uses by default to hold its configuration files is /etc/stunnel/  This directory will contain the configuration file (stunnel.conf), the server certificates file (stunnel.pem) containing both the public and private key for the stunnel server, and the public certificates database (certs.pem).

Server Certificate

The stunnel package ships with a pre-generated key pair in stunnel.pem and a new one is created during the build process.  You can generate a new key-pair using the openssl command or going to the http://www.stunnel.org/pem/.

If you have openssl installed the following command can be used to generate the key-pair:

$ openssl req -new -x509 -days 365 -nodes -config stunnel.cnf \
–out stunnel.pem -keyout stunnel.pem

This creates a private key, and self-signed certificate. If stunnel was compiled to use Diffie-Hellman, these parameters will need to be generated for the key-pair.  By default Diffie-Hellman is not enabled.  The stunnel FAQ can provide the necessary steps on how to do this. You can find more information about this at http://www.stunnel.org/faq/certs.html#ToC5.

To verify that the certificate, you can generate a fingerprint for the certificate with the following command:

$ openssl x509 -subject -dates -fingerprint -in stunnel.pem

The fingerprint for the certificate will be displayed on the screen.  You can save this information for later verification of the certificate.  The fingerprint for this certificate should never change.  If it does then the certificate has been modified and should no longer be trusted.

Client Certificates

Configuring stunnel to act as a client, the public keys from the servers that will be communicating with will need to be retrieved and stored locally in advance.  This key is used to encrypt the data as it passes between the stunnel client and the secure LDAP server.

To obtain the public keys from the servers that are going to be connected with, openssl can be used to obtain them.  A web browser such as Netscape may also be used to acquire these keys, but them the key file format may need to be convert using openssl.

To obtain the public keys using openssl the command would look like:

$ echo | openssl s_client –host [server’s hostname or ip address] –port 636 –showcerts >> certs.pem

The command above appends the returned public key to the file certs.pem.  If the stunnel process is to be set up to talk to multiple servers, it will be necessary to obtain the keys for each server, and append them to this file.

Modifying stunnel.conf

This is the configuration file for the stunnel program.  Only a couple of modifications need to be made to the default.  Ensure that the server certificate file is in the correct place.  It is set with the line:

Cert=/etc/stunnel/stunnel.pem

Make sure the userid and groupid exist on the machine stunnel is running on.  The default setting are for nobody and nogroup respectively.  The group nogroup did not exist on the machine this stunnel was being installed on so the setgid line was changed to reflect this:

Setuid = nobody
Setgid = nobody

To make stunnel function in client-only mode add the following line to the configuration file:

Client=yes

The default configuration file has several services predefined.  These service definitions can be removed or commented out.  Add the entries for the services that will need to be secured.  The port that the local LDAP client is to connect to and the hostname and port number of the server it will be connecting to.  Multiple entries can be made, but a separate port on the local machine must be designated.

Sample entries to allow an LDAP client to connect to port 389, and then have stunnel open an encrypt session to an LDAPS server running on port 636 on a remote host foo.bar.com would look like:

[ldap]
Accept = 389
Connect = foo.bar.com:636

As long as the service name is changed in the square bracket and the accepting port is different multiple entries can be made in this file.

Configuring the Operating System

On a UNIX machine there are two models to execute stunnel so that it responds to connection.  The program can be executed when ever a network connection is made to a specified port using inetd or it equivalent or stunnel can be executed as a daemon that is always running and listening for connections.  How to do this is beyond the scope of this document.

To prevent other machines from connecting to stunnel no matter how it is configured tcp-wrappers will need to be configured.  During then build process this had been enabled.  The tcp-wrapper typically use the file /etc/hosts.allow and /etc/hosts.deny to determine what other machines can and can not connect to the services running.  For the example above, the hosts.allow file would need an entry similar to the one below to only allow connections from itself to use the stunnel instance:

Ldap:  localhost

The ldap element used in the example above actually refers to a service name.  Service names are defined as port and protocol pairs in the /etc/services file.  In the example above the ldap is defined as the service that runs on port 389.

Advertisements