LDAP and password encryption strength

Given the focus on security breaches leaking account information the last few years, we have taken a fresh look at how secure our LDAP passwords really are, and if we can let OpenLDAP use a modern hash algorithm.

So what is a modern hash? Articles on the net usually mention SHA-512, PBKDF-2, brypt and scrypt. The latter is considered better as it consumes an arbitrarily large amount of memory and can thus be more resistant to a GPU based attack.

Storing passwords

OpenLDAP can store passwords in cleartext, as encrypted strings, or as hashes (one-way algorithms). Usually one stores the password in the userPassword attribute provided by or inherited from the organization, organizationalUnit or person object class (RFC4519).

The userPassword attribute is in most installations by default protected with ACLs in the server configuration, by only giving administrators or the owner of the object containing the attribute access to this attribute.

The LDAP server content is in it self stored in a local database backend, usually BDB or HDB.

In a worst case scenario, a malicious user can either somehow bypass the LDAP server access protection and retrieve passwords or hashes via the LDAP protocol, or somehow access the OS, get root privileges and read the LDAP server’s database file from the file system. In these cases, a strong password hash is imperative.

OpenLDAP built-in security

If the password content is prepended by a `{}' string, the LDAP server will use the given scheme to encrypt or hash the password. Vanilla OpenLDAP 2.4 supports the following encryption schemes:

  • MD5 MD5 hashed password
  • SMD5 - MD5 with salt
  • SHA - SHA-1 hashed password
  • SSHA - SHA-1 with salt

The SSHA is given as the most secure password scheme supported. Unfortunately attacks against SHA-1 were found back in 2005 and the scheme has been officially frowned upon for a long time. The salt does help, but SHA-1 is getting a bit long in the tooth. To put it mildly.

So is that it?

OpenLDAP pass-through authentication

OpenLDAP can also use external processes to verify and hash passwords. These schemes are:

  • CRYPT - will use the OS’ crypt library as a password handler
  • SASL - will use Cyrus SASL as a password handler

Cyrus SASL was last updated in 2012, but CRYPT is a part of the POSIX API and should be continuously updated. So - can CRYPT give us an up-to-date hash?

Crypt to the rescue

It turns out that Linux based glibc version of crypt support additional encryption schemes through an additional versioning scheme encoded in the password hash sometimes called the modular crypt format:

  • 1 - MD5
  • 2a - Blowfish / bcrypt
  • 5 - SHA-256
  • 6 - SHA-512

The format used for the additional encryption schemes can be expressed according to the modular crypt format: $<id>[$<parameter>=<value>]*[$<salt>][$<hash>] Here the salt and the hash are Base64 encoded strings.

An interesting detail here is the parameter argument to the MCF - for the sha-512 hash a valid argument is rounds=<N>, with a default value of 5000. This implements a key stretching scheme.

So with SHA-512, a long salt and a high ‘rounds’ parameter, we should be able to generate a reasonably secure hash.

OpenLDAP default password variables

You can instruct OpenLDAP to use a strong encryption scheme by default:

password-hash {CRYPT}
password-crypt-salt-format "$6$%.16s"

Or for a cn=config enabled OpenLDAP server:

olcPasswordHash: {CRYPT}
olcPasswordCryptSaltFormat: $6$%.16s

The latter setting’s value is in sprintf(3) format which should only contain one % conversion. The string character count implies the length of the salt, which for crypt can be up to 16 characters long.

In order to gain a longer key stretch, you can use:

password-crypt-salt-format "$6$rounds=50000$%.16s"

I have unfortunately not had the time to test the key-stretching default value, but will update this post with results later.

mkpasswd and LDIF

mkpasswd is a handy utility which can create a MCF formatted hash. In the following example, I read a salt from /dev/random:

$ mkpasswd --rounds 500000 -m sha-512 --salt `head -c 40 /dev/random | base64 | sed -e 's/+/./g' |  cut -b 10-25` 'Try to break this one!'
$6$rounds=500000$KWcfAQjEPsey2aEr$X/E/I9ySD3zO6Z6cfrTo6MrSIMV5oNQuLjxg4kf4nB8f0WZLFuBYlQ86EkHatocuLB0ajd6DsHfmn8Bajoo9u/

Combined with LDIF we get the following hypothetical LDIF string in order to set a secure password for a given account:

dn: uid=lars,ou=Employees,dc=redpill-linpro,dc=com
changetype: modify
replace: userPassword
userPassword: {CRYPT}$6$rounds=500000$KWcfAQjEPsey2aEr$X/E/I9ySD3zO6Z6cfrTo6MrSIMV5oNQuLjxg4kf4nB8f0WZLFuBYlQ86EkHatocuLB0ajd6DsHfmn8Bajoo9u/

Further steps

With the password storage in a better shape, the next step is to ensure that all communication with the LDAP server is encrypted!

Lars Olafsen

Operations Manager at Redpill Linpro

Lars has been in the IT business for around two decades now, working initially both as a developer and systems administrator. He's been with Redpill Linpro for 9 years, and in addition to being one of our operations managers, he still gets the time to solder together pieces of code.

Mulesoft Enterprise Standalone Runtime on Raspberry Pi 3 with docker

The Raspberry Pi 3 is the third generation Raspberry Pi, on this i will be installing Mulesoft enterprise runtime standalone with latest Java 8 running inside a Docker container. The Instance will register itself with Anypoint platform ... [continue reading]

How to use encryption in Mule

Published on January 31, 2017

Norwegian IPv6 year in review

Published on January 24, 2017