02 Mar 2024

Custom password complexity in OpenBSD

In OpenBSD it might not be obvious how to modify the default required password complexity and what the default requirements are. Most people probably use SSH keys instead of password login, but you should have a good password policy to fall back on if needed (or for the sake of an audit). There are a few hints here and there, but the best one is probably the obvious one in passwd(1)

The new password should be at least six characters long and not purely alphabetic. A mixture of both lower and uppercase letters, numbers, and meta-characters is encouraged.

The quality of the password can be enforced by specifying an external checking program via the “passwordcheck” variable in login.conf(5).

So the complexity is hard coded. If we look at the source code for passwd it leads us to pwd_check.c

min_len = (int)login_getcapnum(lc, "minpasswordlen", 6, 6);
    if (min_len > 0 && strlen(password) < min_len) {
        fprintf(stderr, "Please enter a longer password.\n");
        return (0);
    }

At least 6 characters long (max is 72 bytes), UTF-8 characters can be 1 to 4 bytes long.

The remaining default requirements are defined using regex.

struct pattern patterns[] = {
    {
        "^[0-9]*$",
        REG_EXTENDED|REG_NOSUB,
        "Please don't use all-digit passwords."
    },
    {
        "^[a-z]{1,9}$",
        REG_EXTENDED|REG_NOSUB,
        "Please don't use an all-lower case password."
    },
    {
        "^[a-z]{1,6}[0-9]+$",
        REG_EXTENDED|REG_NOSUB|REG_ICASE,
        "Please use a more complicated password."
    },
    {
        "^([a-z][0-9]){1,4}$",
        REG_EXTENDED|REG_NOSUB|REG_ICASE,
        "Please use a more complicated password."
    },
    {
        "^([0-9][a-z]){1,4}$",
        REG_EXTENDED|REG_NOSUB|REG_ICASE,
        "Please use a more complicated password."
    }
};

Setup custom password quality checker

In order to provide our own password requirements for local accounts, we need to use an external tool. In ports there is a suitable application for this called passwdqc.

# pkg_info -q passwdqc
complexity checker for passwd(1) and password generator

passwdqc is a simple password strength checking module for password
changing programs, such as passwd(1).  In addition to checking regular
passwords, it offers support for passphrases and can provide randomly
generated ones.  All features are optional and can be (re-)configured
without rebuilding.

Maintainer: The OpenBSD ports mailing-list <[email protected]>

WWW: https://www.openwall.com/passwdqc/

To enable passphrase quality checking using pwqcheck(1) globally, add
the following lines at the end the "default" class in login.conf(5).

    :passwordcheck=/usr/local/bin/pwqcheck -1:\
    :passwordtries=0:

Install it with pkg_add passwdqc and follow the instructions and don’t forget to run cap_mkdb /etc/login.conf afterwards. Adapt /etc/passwdqc.conf if needed and update login.conf and add this to the default login class:

:passwordcheck=/usr/local/bin/pwqcheck -1 config=/etc/passwdqc.conf:\

The options can be supplied on the command line as well.

The rules can easily be verified by running the command manually and then type in a password to verify the settings:

/usr/local/bin/pwqcheck -1 config=/etc/passwdqc.conf

Check passwdqc.conf(5) for more details.

Tweaking password policies in passwdqc.conf

There are four character classes that can be tweaked using the min parameter:

The number specified for each position is minimium length of the password.

Example:

N0

Passwords such as abc or 123 which consists of single character class are okay, which is really crappy so this is disabled.

N1

Passwords such as abc123 which consists of two character classes are okay.

N2

Password is for passphrase, silly thing.

N3

Passwords such as aB3^ which consists of three character classes are okay.

N4

Passwords such as aB3^© which consists of four character classes are okay.

So lets disable all but the fourth and set it to 72:

min=disabled,disabled,disabled,disabled,72
max=72

NOTE

The password length is max 72 bytes. UTF-8 characters can be 1-4 bytes long, so if you have smörgåsbord as password, it will be 11 characters long but occupy 13 bytes. It is a deep rabbit hole…but if you just skip non-ascii characters you can probably safely count on that 1 character equals 1 byte and therefore can use 72 characters password as minimium and max.

Configure password expiry defaults

Create a new account and expire immediately, forcing user to set a new password at first login

Expire existing account

Make sure the users login class has

        :password-dead=2w:\
        :password-warn=2w:

Explaination from login.conf (5)

 password-dead      time       0           Length of time a password may
                                           be expired but not quite dead
                                           yet.  When set (for both the
                                           client and remote server
                                           machine when doing remote
                                           authentication), a user is
                                           allowed to log in just one more
                                           time after their password (but
                                           not account) has expired.  This
                                           allows a grace period for
                                           updating their password.

 password-warn      time       2w          If the user's password will
                                           expire within this length of
                                           time then warn the user of
                                           this.                                               

When logging in using SSH, the password warning will look like this:

Your password will expire in 5 days.

Set the expiry to yesterday force the user to change password at next login

sh usermod -f "Mar 14 2024" muppet

This is what the SSH Prompt will look like:

WARNING: Your password has expired.

 You must change your password now and login again!

 Changing password for muppet.

 Old password:

Locking an account

Lock account for login (works for SSH too):

usermod -Z eris 

SSH Login with a locked account will behave like wrong password and log like this in /var/log/authlog

sshd[4993]: User eris not allowed because shell /bin/ksh- does not exist
sshd[4993]: Failed password for invalid user eris from <ip> port 52309 ssh2

Logins from console will log you in and immediately kick you out because of a non-existent shell.

Unlock account

usermod -U eris