389 Directory Server Password Storage Schemes Explained

Understand how 389 Directory Server hashes LDAP passwords, inspect userPassword prefixes, change the global storage scheme, migrate legacy hashes after successful binds, and test application compatibility.

Published

Updated

Read time 16 min read

Reviewed byDeepak Prasad

389 Directory Server password storage schemes with PBKDF2-SHA512 default, userPassword hash prefixes, and hash rewrite after bind workflow

LDAP simple binds compare the password a user supplies against the value stored in userPassword. For one-way storage schemes, Directory Server does not retain a decryptable copy of the original password. Instead it applies a configured scheme, stores an encoded result, and verifies future binds against that value. Reversible or clear-text schemes such as CLEAR or AES behave differently and must not be treated as equivalent to one-way hashing.

This guide explains supported schemes, how to inspect prefixes safely, how to change the global or local policy, what happens to existing hashes, how password hash rewrite after bind works, and how to test applications, replicas, and FIPS-related deployments. Password complexity, history, expiration, grace logins, and lockout belong in password policy. That topic is not covered here.

Before you start:

IMPORTANT
This guide covers password hashing, scheme selection, prefix inspection, migration, and hash rewrite after bind. It does not cover password complexity rules, account lockout, manual account disabling, replication agreement tuning, or pass-through authentication. Those topics live in the password policy, lockout, disable-account, replication, and pass-through chapters.

Tested on: Rocky Linux 10.2; 389 Directory Server 3.2.0.

The primary lab uses instance ldap1 on ldap1.example.com with suffix dc=example,dc=com, LDAP port 389, and LDAPS port 636.


How password storage works in 389 Directory Server

When a client sets or changes a password with clear text over a protected connection, Directory Server hashes the supplied value and writes the result to userPassword. Privileged or explicitly enabled workflows can instead store a pre-hashed {SCHEME} value. Later binds hash the supplied password the same way and compare the result to the stored value.

text
User submits a password
        |
        v
Directory Server applies the configured storage scheme
        |
        v
Encoded value is stored in userPassword
        |
        v
Future binds verify the supplied password against that value

One-way schemes do not store a decryptable copy of the original password. If an attacker obtains a hashed value, they must guess passwords and run the same scheme to test each guess. Reversible schemes such as AES and clear-text storage such as CLEAR do not provide the same protection model.

Directory Server stores one-way results with a scheme prefix:

text
{SCHEME}encoded-value

Examples of prefixes you may see during an audit:

text
{PBKDF2-SHA512}...
{SSHA512}...
{SSHA}...

Never publish complete production userPassword values in tickets, logs, or documentation. Inspect prefixes only.


Supported password storage schemes

List the schemes your installed instance actually exposes before you plan a change:

bash
dsconf ldap1 pwpolicy list-schemes

Sample output on the tested host:

output
AES
CLEAR
CRYPT
CRYPT-MD5
CRYPT-SHA256
CRYPT-SHA512
CRYPT-YESCRYPT
GOST_YESCRYPT
MD5
NS-MTA-MD5
PBKDF2
PBKDF2-SHA1
PBKDF2-SHA256
PBKDF2-SHA512
PBKDF2_SHA256
SHA
SHA256
SHA384
SHA512
SMD5
SSHA
SSHA256
SSHA384
SSHA512

The exact plug-in names on your build may differ. For example, PBKDF2_SHA256 is distinct from PBKDF2-SHA256. Use the names returned by list-schemes when you set policy.

Classification Examples Guidance
Preferred default PBKDF2-SHA512 Use for new deployments unless compatibility testing requires otherwise
Strong compatibility option SSHA512 Use only when an integration cannot handle PBKDF2
Other supported schemes PBKDF2_SHA256, PBKDF2-SHA256, PBKDF2-SHA1 Supported does not mean equally recommended
Legacy one-way schemes SSHA, SHA, SMD5, MD5, CRYPT variants Migration or confirmed compatibility only
Reversible or clear storage AES, CLEAR where present Not equivalent to one-way password hashing; avoid for normal LDAP user passwords

Salt prevents identical passwords from producing identical stored values. Iterative schemes such as PBKDF2 increase the work required to test guessed passwords. Unsalted and legacy schemes should not be selected for new deployments. CLEAR exposes the actual password to anyone who can read userPassword.

Red Hat Directory Server documents PBKDF2 as its strongest supported storage-scheme family, with PBKDF2-SHA512 as the default.


Check the current password storage scheme

Read the global password policy first. On the Directory Server host you can call dsconf with the instance name alone:

bash
dsconf ldap1 pwpolicy get

Sample output:

output
Global Password Policy: cn=config
------------------------------------
passwordstoragescheme: PBKDF2-SHA512
passwordchange: on
passwordhistory: off
passwordlockout: off

The passwordstoragescheme line shows which scheme Directory Server uses for newly stored user passwords under the global policy only.

When you administer the instance remotely, connect over LDAPS and pass the Directory Manager password from a protected file. Point OpenLDAP client tools at the instance CA certificate first:

bash
export LDAPTLS_CACERT=/root/ldap1-ca-chain.pem

Run dsconf over LDAPS with that trust file in place:

bash
dsconf -D "cn=Directory Manager" -y /root/ldap1-dm.pw ldaps://ldap1.example.com:636 pwpolicy get

You can also inspect the underlying cn=config entry with an authenticated ldapsearch command:

bash
ldapsearch -x -H ldaps://ldap1.example.com:636 -D "cn=Directory Manager" -y /root/ldap1-dm.pw -b "cn=config" -s base passwordStorageScheme

Sample output:

output
dn: cn=config
passwordStorageScheme: PBKDF2-SHA512

That confirms the same global value the pwpolicy interface reports. It does not prove which scheme applies to a particular user.

Determine the effective policy for a user or subtree

Directory Server checks user-level policies first, then parent-subtree policies, and finally the global policy. A subtree or user-level policy can supersede the global scheme when fine-grained local policies are enabled.

Check whether fine-grained local password policies are enabled:

bash
dsconf ldap1 pwpolicy get | grep -i nsslapd-pwpolicy-local

Sample output on the tested host:

output
nsslapd-pwpolicy-local: off

You can also read the switch directly:

bash
dsconf -D "cn=Directory Manager" -y /root/ldap1-dm.pw ldap1 config get nsslapd-pwpolicy-local

When nsslapd-pwpolicy-local is off, user and subtree policies are ignored and the global policy is enforced.

When nsslapd-pwpolicy-local is on, list local policies:

bash
dsconf ldap1 localpwp list

For each returned policy DN, inspect the effective settings:

bash
dsconf ldap1 localpwp get "uid=user1,ou=people,dc=example,dc=com"

If no local policy applies to that entry, the command reports that no password policy was found and the global policy remains in effect.

Read password policy for full local-policy creation and management.


Understand the default PBKDF2-SHA512 scheme

Directory Server 12 and 13 use PBKDF2-SHA512 as the default scheme for newly stored user passwords.

PBKDF2 is preferable to older SHA-based schemes because it applies salting and repeated iterations, which increases the cost of offline guessing. The exact iteration count is managed by Directory Server for the installed version; treat it as an implementation detail and verify behaviour on your target release rather than hard-coding numbers from another version.

Applications should authenticate with LDAP binds and let Directory Server verify passwords. If an external program retrieves userPassword and checks the hash itself, it must understand the stored prefix. That is a common reason to keep a legacy scheme temporarily during migration.


Check the scheme used by existing users

Audit scheme prefixes without printing complete userPassword values. The pipeline below uses -LLL, disables LDIF wrapping, and extracts only the {SCHEME} prefix. Export the CA path for LDAPS first:

bash
export LDAPTLS_CACERT=/root/ldap1-ca-chain.pem

Run the prefix audit against ou=people:

bash
ldapsearch -LLL -o ldif-wrap=no -x -H ldaps://ldap1.example.com:636 -D "cn=Directory Manager" -y /root/ldap1-dm.pw -b "ou=people,dc=example,dc=com" "(uid=*)" uid userPassword | python3 -c '
import base64
import re
import sys

for block in sys.stdin.read().strip().split("\n\n"):
    uid = ""
    passwords = []

    for line in block.splitlines():
        if line.startswith("uid: "):
            uid = line.partition(": ")[2]
        elif line.startswith("userPassword:: "):
            encoded = line.partition(":: ")[2]
            try:
                passwords.append(
                    base64.b64decode(encoded).decode("utf-8", "replace")
                )
            except Exception:
                pass
        elif line.startswith("userPassword: "):
            passwords.append(line.partition(": ")[2])

    for value in passwords:
        match = re.match(r"\{[^}]+\}", value)
        if uid and match:
            print(uid, match.group())
'

Sample output:

output
user1 {PBKDF2-SHA512}
user2 {PBKDF2-SHA512}

Each line lists a uid and the scheme prefix only. Access to userPassword should be tightly restricted, and prefix-only output is still sensitive enough to protect in logs and tickets.


Pre-hashed passwords and normal password writes

Normal LDAP add and modify operations should submit a clear-text password over LDAPS or STARTTLS and let Directory Server apply the effective policy. That is not universally true for every write path.

Directory Manager can set pre-hashed values, and nsslapd-allow-hashed-passwords controls whether other authorized users may submit them:

bash
dsconf -D "cn=Directory Manager" -y /root/ldap1-dm.pw ldap1 config get nsslapd-allow-hashed-passwords

Sample output:

output
nsslapd-allow-hashed-passwords: off

With the default off, non-Directory Manager users cannot supply values that are already prefixed with {SCHEME}. A value already prefixed with {SCHEME} is treated as pre-hashed in privileged or explicitly enabled workflows. Delegating pre-hashed-password writes can bypass normal hashing and some policy expectations.

LDIF migration files that contain hashes must preserve exact prefixes and encoding. Audit imported hashes after migration rather than assuming they match the new global scheme. For normal add and modify operations, submit the clear-text password only over LDAPS or over LDAP port 389 with STARTTLS, and let Directory Server hash it using the effective password policy. Red Hat requires encrypted connections when transmitting Directory Manager password material; apply the same principle to normal user-password changes.


Change the global password storage scheme

Set the preferred scheme through the password-policy interface:

bash
dsconf ldap1 pwpolicy set --pwdscheme PBKDF2-SHA512

Sample output:

output
Successfully updated global password policy

Verify the change:

bash
dsconf ldap1 pwpolicy get

Sample output:

output
passwordstoragescheme: PBKDF2-SHA512

The change affects passwords stored after the policy update. It does not instantly rewrite every existing userPassword value.

Confirm the exact scheme names your build accepts before you script the change:

bash
dsconf ldap1 pwpolicy set --help

Sample output:

output
--pwdscheme PWDSCHEME
                        The password storage scheme

Test the workflow on a disposable account:

  1. Create a test user with dsidm.
  2. Set a password with dsidm ldap1 account reset_password.
  3. Inspect only the stored scheme prefix.
  4. Authenticate as the test user with ldapwhoami.

Delete the test user when you finish.


Configure a different scheme for a subtree or user

Local password policies can define a storage scheme that differs from the global policy. Typical reasons include temporary application compatibility, a staged migration, or a limited legacy subtree.

Use cases belong here. The full localpwp creation workflow is covered in password policy. When local policies are enabled, list them with:

bash
dsconf ldap1 localpwp list

Running several schemes permanently increases operational complexity. Keep a non-default scheme only when a tested integration requires it, and document the exception until you remove it.


Existing password hashes and migration

Changing the configured scheme does not require knowing users' clear-text passwords.

Existing users continue to authenticate with their current stored hashes as long as Directory Server still supports those prefixes. A password is stored with the newly configured scheme when:

  • A user changes the password
  • An administrator resets the password
  • A new user password is created
  • Directory Server rewrites the hash after a successful simple bind while nsslapd-enable-upgrade-hash is enabled

There is no safe offline conversion from one one-way hash to another without the original password.

Use a staged migration workflow:

  1. Set the preferred storage scheme.
  2. Confirm new passwords use it.
  3. Keep password hash rewrite on bind enabled unless a verified integration requires otherwise.
  4. Let active users migrate through successful authentication.
  5. Reset passwords for accounts that do not log in during the migration window.
  6. Audit remaining legacy prefixes.
  7. Remove legacy compatibility only after verification.

The lab demonstrated this behaviour on ldap1. After temporarily setting the global scheme to SSHA512, a new test user stored {SSHA512} while an older account keeps its existing prefix until its password is changed or reset, or until a successful simple bind causes an eligible rewrite while nsslapd-enable-upgrade-hash is enabled. A narrow local compatibility policy is safer than temporarily weakening the global scheme for all users.


Password hash rewrite after bind

Check whether Directory Server may rewrite stored hashes after a successful simple bind:

bash
dsconf -D "cn=Directory Manager" -y /root/ldap1-dm.pw ldap1 config get nsslapd-enable-upgrade-hash

Sample output:

output
nsslapd-enable-upgrade-hash: on

When the setting is on, Directory Server can rewrite an eligible stored hash to the scheme currently configured by the applicable policy after a successful simple bind, because it temporarily holds the supplied clear-text password. That rewrite can move a hash to a stronger scheme or to a weaker one if you changed policy for compatibility. Not every stored scheme is eligible.

Check which schemes are excluded from rewrite-on-bind:

bash
dsconf -D "cn=Directory Manager" -y /root/ldap1-dm.pw ldap1 config get nsslapd-scheme-list-no-upgrade-hash

Sample output:

output
nsslapd-scheme-list-no-upgrade-hash: CRYPT,CLEAR

Passwords stored with an excluded scheme are not rewritten after a successful bind even when nsslapd-enable-upgrade-hash is enabled. Those accounts require a password reset, a policy-approved migration path, or removal from the exclusion list after compatibility testing.

Before you temporarily set a weaker global scheme, disable rewrite-on-bind so existing PBKDF2-SHA512 passwords are not downgraded during login:

bash
dsconf -D "cn=Directory Manager" -y /root/ldap1-dm.pw ldap1 config replace nsslapd-enable-upgrade-hash=off

After you restore the preferred scheme:

bash
dsconf ldap1 pwpolicy set --pwdscheme PBKDF2-SHA512

Re-enable hash rewrite so successful binds can migrate eligible passwords again:

bash
dsconf -D "cn=Directory Manager" -y /root/ldap1-dm.pw ldap1 config replace nsslapd-enable-upgrade-hash=on

To preserve a legacy hash format for an integration that reads userPassword directly, leave rewrite disabled until that integration no longer needs the legacy prefix.

On the tested host, a user created under SSHA512 kept the {SSHA512} prefix after a successful bind while rewrite was disabled. With rewrite enabled and the global scheme set back to PBKDF2-SHA512, the same account migrated to {PBKDF2-SHA512} after the next successful bind.


Configure the Directory Manager storage scheme

Normal user passwords and the Directory Manager password use separate settings.

Setting Purpose
passwordStorageScheme in password policy Hashes normal users' userPassword values
nsslapd-rootpwstoragescheme Hashes the Directory Manager password
nsslapd-rootpw Stores the Directory Manager password hash

Inspect the Directory Manager scheme:

bash
dsconf -D "cn=Directory Manager" -y /root/ldap1-dm.pw ldap1 config get nsslapd-rootpwstoragescheme

Sample output:

output
nsslapd-rootpwstoragescheme: PBKDF2-SHA512

Set the scheme Directory Server should use for future Directory Manager password processing:

bash
dsconf -D "cn=Directory Manager" -y /root/ldap1-dm.pw ldap1 config replace nsslapd-rootpwstoragescheme=PBKDF2-SHA512

Changing nsslapd-rootpwstoragescheme does not rehash the existing Directory Manager password. It controls how a future plain-text nsslapd-rootpw value or pwdhash -D operation is processed. Change the Directory Manager password over an encrypted connection to store it with the new scheme.

Illustrative LDAPS example. Replace the placeholder with your approved secret-handling method. Trust the server CA before you connect:

bash
export LDAPTLS_CACERT=/root/ldap1-ca-chain.pem

Set the new Directory Manager password over LDAPS:

bash
dsconf -D "cn=Directory Manager" -y /root/ldap1-dm.pw ldaps://ldap1.example.com:636 config replace nsslapd-rootpw='NEW_DIRECTORY_MANAGER_PASSWORD'

Directory Server stores the supplied value using the scheme configured in nsslapd-rootpwstoragescheme. Do not publish a production password in documentation, tickets, or shell history. The -y option protects the existing Directory Manager bind password only. The new password shown in this example is still a command-line argument. Use the Directory Server web console or a temporary root-readable LDIF file submitted over LDAPS when the new secret must not appear in shell history.

Do not use curly braces in a plain-text Directory Manager password supplied through nsslapd-rootpw. Directory Server interprets text inside braces as a password-storage-scheme prefix, which can make the Directory Manager unable to bind.

Generate a disposable test hash with the instance configuration. The password below is for lab use only; command-line arguments can appear in shell history and process listings:

bash
pwdhash -D /etc/dirsrv/slapd-ldap1 'temporary-test-password'

Sample output (prefix only):

output
{PBKDF2-SHA512}100000$27Drpq3V...

pwdhash -D uses the Directory Manager storage scheme configured for the selected instance. For broader password-policy administration, including password administrators and local policies, see password policy.


Application compatibility, replication, and FIPS considerations

Before you change schemes in production, test applications that:

  • Retrieve userPassword
  • Verify hashes outside Directory Server
  • Synchronize password values
  • Expect an SSHA or CRYPT prefix
  • Use legacy RADIUS or authentication integrations
  • Import or export LDAP password hashes

Prefer LDAP bind authentication instead of reading password hashes wherever possible. Red Hat notes that some FreeRADIUS configurations may not support PBKDF2-SHA512, which can require a temporary compatibility decision.

Replicated entries retain their stored userPassword values. Every replica must understand the prefixes present in the directory, and password-policy configuration should stay consistent across suppliers. LDIF imports that contain pre-hashed passwords preserve the supplied scheme, while plain-text passwords supplied during normal add or modify operations are stored using the applicable policy. Test mixed-version upgrades before you enable a new scheme in production. Detailed replication password-policy behaviour belongs in the replication chapter.

In a FIPS-targeted deployment, test the configured scheme, existing legacy hashes, Directory Manager authentication, password changes, hash rewrite after successful binds, and imported values on the actual platform. Recognizing a scheme name in Directory Server does not, by itself, establish compliance. Host FIPS mode, NSS behaviour, and the applicable validation boundary also matter. Read Enable and verify FIPS mode for the full enablement workflow.


Verify and test a storage-scheme change

Run the instance health check and review password-scheme findings:

bash
dsctl ldap1 healthcheck

With PBKDF2-SHA512 configured, the tested run reported no issues. After temporarily setting the global scheme to weak SSHA, the same check reported a high-severity finding:

output
Check: config:passwordscheme
Your configured scheme (SSHA) for 'passwordStorageScheme' is not secure
===== End Of Report (1 Issue found) =====

Restore the preferred scheme before you leave the instance in production:

bash
dsconf ldap1 pwpolicy set --pwdscheme PBKDF2-SHA512

Use this matrix during a controlled change:

Test Expected result
Newly created password Uses the configured scheme
Existing legacy password Still authenticates
Successful bind with rewrite enabled Hash rewrites to the effective configured scheme where eligible
Successful bind with rewrite disabled Original prefix remains
Administrative password reset Uses the configured scheme
Directory Manager password Uses nsslapd-rootpwstoragescheme
Application authentication Continues working
Replicated password Works on every replica

Record prefix-only audits before and after the change so you can prove migration progress without exposing full hashes.


Troubleshoot password storage schemes

Symptom Likely cause Fix
New passwords still use the old scheme Local password policy overrides the global policy, or the password was not actually changed Run dsconf ldap1 pwpolicy get and dsconf ldap1 localpwp list; reset the password on the server that accepted the update
Existing hashes do not change after login nsslapd-enable-upgrade-hash is off, the bind failed on the inspected server, the stored hash is not eligible for rewrite, or the scheme is listed in nsslapd-scheme-list-no-upgrade-hash Confirm nsslapd-enable-upgrade-hash: on, verify the bind succeeded, check nsslapd-scheme-list-no-upgrade-hash, and recheck the entry on the same replica
Application authentication fails after migration The application reads and verifies userPassword locally instead of binding Test LDAP binds, temporarily keep a compatible scheme for that integration, or update the application
Imported password does not authenticate Wrong scheme prefix, broken base64, unsupported scheme, or double hashing Inspect only the prefix, validate LDIF formatting, and re-import with a supported scheme
Directory Manager cannot bind after a manual hash edit Wrong nsslapd-rootpwstoragescheme, missing braces, curly braces in a plain-text password, or pwdhash aimed at the wrong instance directory Regenerate with pwdhash -D /etc/dirsrv/slapd-INSTANCE and restore from backup if needed
Health check reports a weak scheme Global policy, local policy, or Directory Manager storage still uses a legacy algorithm Identify which policy entry owns the finding and move it to PBKDF2-SHA512 when compatibility testing permits

Summary

  1. Use PBKDF2-SHA512 unless a tested integration requires another scheme.
  2. Keep user and Directory Manager storage settings separate.
  3. Changing the scheme does not immediately rewrite existing hashes.
  4. Use password hash rewrite on bind and administrative resets for migration.
  5. Audit local policies and legacy password prefixes.
  6. Test applications, replicas, imports, and FIPS environments before you enforce the change in production.

What's Next


References


Frequently Asked Questions

1. What is the default password storage scheme in 389 Directory Server?

Current Directory Server releases default to PBKDF2-SHA512 for newly stored user passwords. dsconf INSTANCE pwpolicy get shows the global scheme only. Check dsconf INSTANCE localpwp list and localpwp get POLICY_DN before deciding which scheme applies to a particular user or subtree.

2. Does changing the storage scheme rewrite every existing userPassword value immediately?

No. Existing hashes keep their current prefix until the password is changed, reset, or rewritten after a successful simple bind when nsslapd-enable-upgrade-hash is on. Plan migration around logins and administrative resets rather than expecting an instant directory-wide rewrite.

3. What is the difference between passwordStorageScheme and nsslapd-rootpwstoragescheme?

passwordStorageScheme in the global or local password policy hashes normal user userPassword values. nsslapd-rootpwstoragescheme hashes the Directory Manager password stored in nsslapd-rootpw. Change and verify each setting separately.

4. Can I migrate SSHA passwords to PBKDF2 without knowing the clear-text password?

No. One-way hashes cannot be converted offline. Enable the preferred scheme, keep password hash rewrite on bind enabled unless a verified integration requires otherwise, let active users authenticate, and reset passwords for dormant accounts. Audit remaining legacy prefixes afterward.

5. Why would an application fail after I enable PBKDF2-SHA512?

Some integrations read userPassword and verify the hash locally instead of performing an LDAP bind. Those programs may only understand SSHA, CRYPT, or MD5 prefixes. Test binds and hash retrieval before you change production policy, and keep a compatibility subtree only when a verified integration requires it.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …