mechanism.) This program has more extensive Perl module dependencies
than the other programs in this distribution.
+ A new configuration option, minimum_different, can be set to require
+ that passwords contain at least that many unique characters. This can
+ be used to reject long strings of identical characters or short
+ patterns, which may pass other checks but still be too easy to guess.
+
krb5-strength 2.2 (2013-12-16)
More complex character class requirements can be specified with the
The following additional settings are supported in the [appdefaults]
section of krb5.conf when running under either Heimdal or MIT Kerberos.
+ minimum_different
+
+ If set to a numeric value, passwords with fewer than this number of
+ unique characters will be rejected. This can be used to reject, for
+ example, passwords that are long strings of the same character or
+ repetitions of small numbers of characters, which may be too easy to
+ guess.
+
minimum_length
If set to a numeric value, passwords with fewer than that number of
* Developed by Derrick Brashear and Ken Hornstein of Sine Nomine Associates,
* on behalf of Stanford University
* Extensive modifications by Russ Allbery <eagle@eyrie.org>
- * Copyright 2006, 2007, 2009, 2012, 2013
+ * Copyright 2006, 2007, 2009, 2012, 2013, 2014
* The Board of Trustees of the Leland Stanford Junior University
*
* See LICENSE for licensing terms.
return strength_error_system(ctx, "cannot allocate memory");
data->cdb_fd = -1;
- /* Get minimum length information from krb5.conf. */
+ /* Get minimum length and character information from krb5.conf. */
+ strength_config_number(ctx, "minimum_different", &data->minimum_different);
strength_config_number(ctx, "minimum_length", &data->minimum_length);
/* Get simple character class restrictions from krb5.conf. */
}
+/*
+ * Check if a password has a sufficient number of unique characters. Takes
+ * the password and the required number of characters.
+ */
+static bool
+has_minimum_different(const char *password, long minimum)
+{
+ size_t unique;
+ const char *p;
+
+ /* Special cases for passwords of length 0 and a minimum <= 1. */
+ if (password == NULL || password[0] == '\0')
+ return minimum <= 0;
+ if (minimum <= 1)
+ return true;
+
+ /*
+ * Count the number of unique characters by incrementing the count if each
+ * subsequent character is not found in the previous password characters.
+ * This algorithm is O(n^2), but passwords are short enough it shouldn't
+ * matter.
+ */
+ unique = 1;
+ for (p = password + 1; *p != '\0'; p++)
+ if (memchr(password, *p, p - password) == NULL) {
+ unique++;
+ if (unique >= (size_t) minimum)
+ return true;
+ }
+ return false;
+}
+
+
/*
* Check a given password. Takes a Kerberos context, our module data, the
* password, the principal the password is for, and a buffer and buffer length
if (data->nonletter && only_alpha_space(password))
return strength_error_class(ctx, ERROR_LETTER);
+ /* If desired, check for enough unique characters. */
+ if (data->minimum_different > 0)
+ if (!has_minimum_different(password, data->minimum_different))
+ return strength_error_class(ctx, ERROR_MINDIFF);
+
/*
* If desired, check that the password satisfies character class
* restrictions.
* Developed by Derrick Brashear and Ken Hornstein of Sine Nomine Associates,
* on behalf of Stanford University
* Extensive modifications by Russ Allbery <eagle@eyrie.org>
- * Copyright 2006, 2007, 2009, 2012, 2013
+ * Copyright 2006, 2007, 2009, 2012, 2013, 2014
* The Board of Trustees of the Leland Stanford Junior University
*
* See LICENSE for licensing terms.
#define ERROR_ASCII "password contains non-ASCII or control characters"
#define ERROR_DICT "password found in list of common passwords"
#define ERROR_LETTER "password is only letters and spaces"
+#define ERROR_MINDIFF "password does not contain enough unique characters"
#define ERROR_SHORT "password is too short"
#define ERROR_USERNAME "password based on username or principal"
* checking for at least the MIT plugin.
*/
struct krb5_pwqual_moddata_st {
+ long minimum_different; /* Minimum number of different characters */
long minimum_length; /* Minimum password length */
bool ascii; /* Whether to require printable ASCII */
bool nonletter; /* Whether to require a non-letter */
"name": "digits",
"principal": "test@EXAMPLE.ORG",
"password": "the perils 0of all good dogs"
+ },
+ {
+ "name": "mindiff (1 character)",
+ "principal": "test@EXAMPLE.ORG",
+ "password": "11111111111111111111",
+ "code": "KADM5_PASS_Q_CLASS",
+ "error": "password does not contain enough unique characters"
+ },
+ {
+ "name": "mindiff (2 characters)",
+ "principal": "test@EXAMPLE.ORG",
+ "password": "1b1b1b1b1b1b1b1b1b1b",
+ "code": "KADM5_PASS_Q_CLASS",
+ "error": "password does not contain enough unique characters"
+ },
+ {
+ "name": "mindiff (3 characters)",
+ "principal": "test@EXAMPLE.ORG",
+ "password": "1bc1bc1bc1bc1bc1bc1b",
+ "code": "KADM5_PASS_Q_CLASS",
+ "error": "password does not contain enough unique characters"
+ },
+ {
+ "name": "mindiff (4 characters)",
+ "principal": "test@EXAMPLE.ORG",
+ "password": "1bcd1bcd1bcd1bcd1bcd",
+ "code": "KADM5_PASS_Q_CLASS",
+ "error": "password does not contain enough unique characters"
+ },
+ {
+ "name": "mindiff (5 characters)",
+ "principal": "test@EXAMPLE.ORG",
+ "password": "1bcde1bcde1bcde1bcde",
+ "code": "KADM5_PASS_Q_CLASS",
+ "error": "password does not contain enough unique characters"
+ },
+ {
+ "name": "mindiff (6 characters)",
+ "principal": "test@EXAMPLE.ORG",
+ "password": "1bcdef1bcdef1bcdef1b",
+ "code": "KADM5_PASS_Q_CLASS",
+ "error": "password does not contain enough unique characters"
+ },
+ {
+ "name": "mindiff (7 characters)",
+ "principal": "test@EXAMPLE.ORG",
+ "password": "1cdbfge1cdbeg1fcdbef",
+ "code": "KADM5_PASS_Q_CLASS",
+ "error": "password does not contain enough unique characters"
+ },
+ {
+ "name": "mindiff (8 characters)",
+ "principal": "test@EXAMPLE.ORG",
+ "password": "1dbegchf1cdbfgh1ebcd"
+ },
+ {
+ "name": "mindiff (9 characters)",
+ "principal": "test@EXAMPLE.ORG",
+ "password": "bcd1fgei1bhdefchig1b"
}
]
* Test for the Heimdal shared module API.
*
* Written by Russ Allbery <eagle@eyrie.org>
- * Copyright 2009, 2013
+ * Copyright 2009, 2013, 2014
* The Board of Trustees of the Leland Stanford Junior University
*
* See LICENSE for licensing terms.
main(void)
{
char *path, *krb5_config, *krb5_config_empty, *tmpdir;
- char *setup_argv[10];
+ char *setup_argv[12];
size_t i, count;
struct kadm5_pw_policy_verifier *verifier;
void *handle;
is_password_test(verifier, &principal_tests[i]);
/* Add simple character class restrictions. */
- setup_argv[5] = (char *) "require_ascii_printable";
- setup_argv[6] = (char *) "true";
- setup_argv[7] = (char *) "require_non_letter";
+ setup_argv[5] = (char *) "minimum_different";
+ setup_argv[6] = (char *) "8";
+ setup_argv[7] = (char *) "require_ascii_printable";
setup_argv[8] = (char *) "true";
- setup_argv[9] = NULL;
+ setup_argv[9] = (char *) "require_non_letter";
+ setup_argv[10] = (char *) "true";
+ setup_argv[11] = NULL;
run_setup((const char **) setup_argv);
/* Run the simple character class tests. */
* Test for the MIT Kerberos shared module API.
*
* Written by Russ Allbery <eagle@eyrie.org>
- * Copyright 2010, 2013
+ * Copyright 2010, 2013, 2014
* The Board of Trustees of the Leland Stanford Junior University
*
* See LICENSE for licensing terms.
main(void)
{
char *path, *dictionary, *krb5_config, *krb5_config_empty, *tmpdir;
- char *setup_argv[10];
+ char *setup_argv[12];
const char*build;
size_t i, count;
krb5_context ctx;
vtable->close(ctx, data);
/* Add simple character class configuration to krb5.conf. */
- setup_argv[5] = (char *) "require_ascii_printable";
- setup_argv[6] = (char *) "true";
- setup_argv[7] = (char *) "require_non_letter";
+ setup_argv[5] = (char *) "minimum_different";
+ setup_argv[6] = (char *) "8";
+ setup_argv[7] = (char *) "require_ascii_printable";
setup_argv[8] = (char *) "true";
- setup_argv[9] = NULL;
+ setup_argv[9] = (char *) "require_non_letter";
+ setup_argv[10] = (char *) "true";
+ setup_argv[11] = NULL;
run_setup((const char **) setup_argv);
/* Obtain a new Kerberos context with that krb5.conf file. */
# Test suite for basic Heimdal external strength checking functionality.
#
# Written by Russ Allbery <eagle@eyrie.org>
-# Copyright 2009, 2012, 2013
+# Copyright 2009, 2012, 2013, 2014
# The Board of Trustees of the Leland Stanford Junior University
#
# See LICENSE for licensing terms.
# Install the krb5.conf file for simple character class restrictions.
$krb5_conf = create_krb5_conf(
{
+ minimum_different => 8,
require_ascii_printable => 'true',
require_non_letter => 'true',
}