mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-01-30 13:30:57 +08:00
ITS#9055 Introduce a combined password scheme
This commit is contained in:
parent
711a96064e
commit
3be82f40d5
@ -9,6 +9,17 @@ userPassword: {TOTP1}GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ
|
||||
|
||||
which encodes the key '12345678901234567890'.
|
||||
|
||||
It can also encode credentials consisting of a TOTP and a static
|
||||
password. The format for this is:
|
||||
|
||||
userPassword: {TOTP1ANDPW}GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ|<some_other_passwd>
|
||||
|
||||
where <some_other_passwd> can be any scheme currently understood
|
||||
by OpenLDAP. For example, using '{SHA}5en6G6MezRroT3XKqkdPOmY/BfQ='
|
||||
would encode the above TOTP with a static password of 'secret'. To
|
||||
authenticate using this scheme, enter the static password immediately
|
||||
followed by the TOTP, for example 'secret123456'.
|
||||
|
||||
|
||||
Building
|
||||
--------
|
||||
@ -33,7 +44,8 @@ cannot use that overlay on the same database as this one.
|
||||
Configuring
|
||||
-----------
|
||||
|
||||
The {TOTP1}, {TOTP256}, and {TOTP512} password schemes should now be recognised.
|
||||
The {TOTP1}, {TOTP256}, {TOTP512}, {TOTP1ANDPW}, {TOTP256ANDPW},
|
||||
and {TOTP512ANDPW} password schemes should now be recognised.
|
||||
|
||||
You can also tell OpenLDAP to use one of these new schemes when processing LDAP
|
||||
Password Modify Extended Operations, thanks to the password-hash option in
|
||||
|
@ -94,11 +94,16 @@ static void HMAC_CTX_free(HMAC_CTX *ctx)
|
||||
#include "slap.h"
|
||||
#include "config.h"
|
||||
|
||||
static LUTIL_PASSWD_CHK_FUNC chk_totp1, chk_totp256, chk_totp512;
|
||||
static LUTIL_PASSWD_HASH_FUNC hash_totp1, hash_totp256, hash_totp512;
|
||||
static LUTIL_PASSWD_CHK_FUNC chk_totp1, chk_totp256, chk_totp512,
|
||||
chk_totp1andpw, chk_totp256andpw, chk_totp512andpw;
|
||||
static LUTIL_PASSWD_HASH_FUNC hash_totp1, hash_totp256, hash_totp512,
|
||||
hash_totp1andpw, hash_totp256andpw, hash_totp512andpw;
|
||||
static const struct berval scheme_totp1 = BER_BVC("{TOTP1}");
|
||||
static const struct berval scheme_totp256 = BER_BVC("{TOTP256}");
|
||||
static const struct berval scheme_totp512 = BER_BVC("{TOTP512}");
|
||||
static const struct berval scheme_totp1andpw = BER_BVC("{TOTP1ANDPW}");
|
||||
static const struct berval scheme_totp256andpw = BER_BVC("{TOTP256ANDPW}");
|
||||
static const struct berval scheme_totp512andpw = BER_BVC("{TOTP512ANDPW}");
|
||||
|
||||
static AttributeDescription *ad_authTimestamp;
|
||||
|
||||
@ -412,6 +417,8 @@ static int totp_bind_response( Operation *op, SlapReply *rs );
|
||||
|
||||
#define TIME_STEP 30
|
||||
#define DIGITS 6
|
||||
#define DELIM '|' /* a single character */
|
||||
#define TOTP_AND_PW_HASH_SCHEME "{SSHA}"
|
||||
|
||||
static int chk_totp(
|
||||
const struct berval *passwd,
|
||||
@ -423,7 +430,7 @@ static int chk_totp(
|
||||
Operation *op;
|
||||
Entry *e;
|
||||
Attribute *a;
|
||||
long t = time(0L) / TIME_STEP;
|
||||
long t, told = 0;
|
||||
int rc;
|
||||
myval out, key;
|
||||
char outbuf[32];
|
||||
@ -439,13 +446,14 @@ static int chk_totp(
|
||||
if (rc != LDAP_SUCCESS) return LUTIL_PASSWD_ERR;
|
||||
|
||||
/* Make sure previous login is older than current time */
|
||||
t = op->o_time / TIME_STEP;
|
||||
a = attr_find(e->e_attrs, ad_authTimestamp);
|
||||
if (a) {
|
||||
struct lutil_tm tm;
|
||||
struct lutil_timet tt;
|
||||
if (lutil_parsetime(a->a_vals[0].bv_val, &tm) == 0 &&
|
||||
lutil_tm2time(&tm, &tt) == 0) {
|
||||
long told = tt.tt_sec / TIME_STEP;
|
||||
told = tt.tt_sec / TIME_STEP;
|
||||
if (told >= t)
|
||||
rc = LUTIL_PASSWD_ERR;
|
||||
}
|
||||
@ -507,6 +515,59 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int chk_totp_and_pw(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
const struct berval *cred,
|
||||
const char **text,
|
||||
const void *mech)
|
||||
{
|
||||
char *s;
|
||||
int rc = LUTIL_PASSWD_ERR, rc_pass, rc_otp;
|
||||
ber_len_t len;
|
||||
struct berval cred_pass, cred_otp, passwd_pass, passwd_otp;
|
||||
|
||||
/* Check credential length, no point to continue if too short */
|
||||
if (cred->bv_len <= DIGITS)
|
||||
return rc;
|
||||
|
||||
/* The OTP seed of the stored password */
|
||||
s = strchr(passwd->bv_val, DELIM);
|
||||
if (s) {
|
||||
len = s - passwd->bv_val;
|
||||
} else {
|
||||
return rc;
|
||||
}
|
||||
if (!ber_str2bv(passwd->bv_val, len, 1, &passwd_otp))
|
||||
return rc;
|
||||
|
||||
/* The password part of the stored password */
|
||||
s++;
|
||||
ber_str2bv(s, 0, 0, &passwd_pass);
|
||||
|
||||
/* The OTP part of the entered credential */
|
||||
ber_str2bv(&cred->bv_val[cred->bv_len - DIGITS], DIGITS, 0, &cred_otp);
|
||||
|
||||
/* The password part of the entered credential */
|
||||
if (!ber_str2bv(cred->bv_val, cred->bv_len - DIGITS, 0, &cred_pass)) {
|
||||
/* Cleanup */
|
||||
memset(passwd_otp.bv_val, 0, passwd_otp.bv_len);
|
||||
ber_memfree(passwd_otp.bv_val);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc_otp = chk_totp(&passwd_otp, &cred_otp, mech, text);
|
||||
rc_pass = lutil_passwd(&passwd_pass, &cred_pass, NULL, text);
|
||||
if (rc_otp == LUTIL_PASSWD_OK && rc_pass == LUTIL_PASSWD_OK)
|
||||
rc = LUTIL_PASSWD_OK;
|
||||
|
||||
/* Cleanup and return */
|
||||
memset(passwd_otp.bv_val, 0, passwd_otp.bv_len);
|
||||
ber_memfree(passwd_otp.bv_val);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int chk_totp1(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
@ -534,6 +595,33 @@ static int chk_totp512(
|
||||
return chk_totp(passwd, cred, TOTP_SHA512, text);
|
||||
}
|
||||
|
||||
static int chk_totp1andpw(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
const struct berval *cred,
|
||||
const char **text)
|
||||
{
|
||||
return chk_totp_and_pw(scheme, passwd, cred, text, TOTP_SHA1);
|
||||
}
|
||||
|
||||
static int chk_totp256andpw(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
const struct berval *cred,
|
||||
const char **text)
|
||||
{
|
||||
return chk_totp_and_pw(scheme, passwd, cred, text, TOTP_SHA256);
|
||||
}
|
||||
|
||||
static int chk_totp512andpw(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
const struct berval *cred,
|
||||
const char **text)
|
||||
{
|
||||
return chk_totp_and_pw(scheme, passwd, cred, text, TOTP_SHA512);
|
||||
}
|
||||
|
||||
static int passwd_string32(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
@ -554,6 +642,74 @@ static int passwd_string32(
|
||||
return LUTIL_PASSWD_OK;
|
||||
}
|
||||
|
||||
static int hash_totp_and_pw(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
struct berval *hash,
|
||||
const char **text)
|
||||
{
|
||||
struct berval otp, pass, hash_otp, hash_pass;
|
||||
ber_len_t len;
|
||||
char *s;
|
||||
int rc = LUTIL_PASSWD_ERR;
|
||||
|
||||
/* The OTP seed part */
|
||||
s = strchr(passwd->bv_val, DELIM);
|
||||
if (s) {
|
||||
len = s - passwd->bv_val;
|
||||
} else {
|
||||
return rc;
|
||||
}
|
||||
if (!ber_str2bv(passwd->bv_val, len, 0, &otp))
|
||||
return rc;
|
||||
|
||||
/* The static password part */
|
||||
s++;
|
||||
ber_str2bv(s, 0, 0, &pass);
|
||||
|
||||
/* Hash the OTP seed */
|
||||
rc = passwd_string32(scheme, &otp, &hash_otp);
|
||||
|
||||
/* If successful, hash the static password, else cleanup and return */
|
||||
if (rc == LUTIL_PASSWD_OK) {
|
||||
rc = lutil_passwd_hash(&pass, TOTP_AND_PW_HASH_SCHEME,
|
||||
&hash_pass, text);
|
||||
} else {
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
|
||||
/* If successful, allocate memory to combine them, else cleanup
|
||||
* and return */
|
||||
if (rc == LUTIL_PASSWD_OK) {
|
||||
/* Add 1 character to bv_len to hold DELIM */
|
||||
hash->bv_len = hash_pass.bv_len + hash_otp.bv_len + 1;
|
||||
hash->bv_val = ber_memalloc(hash->bv_len + 1);
|
||||
if (!hash->bv_val)
|
||||
rc = LUTIL_PASSWD_ERR;
|
||||
} else {
|
||||
memset(hash_otp.bv_val, 0, hash_otp.bv_len);
|
||||
ber_memfree(hash_otp.bv_val);
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
|
||||
/* If successful, combine the two hashes with the delimiter */
|
||||
if (rc == LUTIL_PASSWD_OK) {
|
||||
AC_MEMCPY(hash->bv_val, hash_otp.bv_val, hash_otp.bv_len);
|
||||
hash->bv_val[hash_otp.bv_len] = DELIM;
|
||||
AC_MEMCPY(hash->bv_val + hash_otp.bv_len + 1,
|
||||
hash_pass.bv_val, hash_pass.bv_len);
|
||||
hash->bv_val[hash->bv_len] = '\0';
|
||||
}
|
||||
|
||||
/* Cleanup and return */
|
||||
memset(hash_otp.bv_val, 0, hash_otp.bv_len);
|
||||
memset(hash_pass.bv_val, 0, hash_pass.bv_len);
|
||||
ber_memfree(hash_otp.bv_val);
|
||||
ber_memfree(hash_pass.bv_val);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int hash_totp1(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
@ -599,6 +755,51 @@ static int hash_totp512(
|
||||
return passwd_string32(scheme, passwd, hash);
|
||||
}
|
||||
|
||||
static int hash_totp1andpw(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
struct berval *hash,
|
||||
const char **text)
|
||||
{
|
||||
#if 0
|
||||
if (passwd->bv_len != SHA_DIGEST_LENGTH) {
|
||||
*text = "invalid key length";
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
#endif
|
||||
return hash_totp_and_pw(scheme, passwd, hash, text);
|
||||
}
|
||||
|
||||
static int hash_totp256andpw(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
struct berval *hash,
|
||||
const char **text)
|
||||
{
|
||||
#if 0
|
||||
if (passwd->bv_len != SHA256_DIGEST_LENGTH) {
|
||||
*text = "invalid key length";
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
#endif
|
||||
return hash_totp_and_pw(scheme, passwd, hash, text);
|
||||
}
|
||||
|
||||
static int hash_totp512andpw(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
struct berval *hash,
|
||||
const char **text)
|
||||
{
|
||||
#if 0
|
||||
if (passwd->bv_len != SHA512_DIGEST_LENGTH) {
|
||||
*text = "invalid key length";
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
#endif
|
||||
return hash_totp_and_pw(scheme, passwd, hash, text);
|
||||
}
|
||||
|
||||
static int totp_op_cleanup(
|
||||
Operation *op,
|
||||
SlapReply *rs )
|
||||
@ -782,6 +983,12 @@ totp_initialize(void)
|
||||
rc = lutil_passwd_add((struct berval *) &scheme_totp256, chk_totp256, hash_totp256);
|
||||
if (!rc)
|
||||
rc = lutil_passwd_add((struct berval *) &scheme_totp512, chk_totp512, hash_totp512);
|
||||
if (!rc)
|
||||
rc = lutil_passwd_add((struct berval *) &scheme_totp1andpw, chk_totp1andpw, hash_totp1andpw);
|
||||
if (!rc)
|
||||
rc = lutil_passwd_add((struct berval *) &scheme_totp256andpw, chk_totp256andpw, hash_totp256andpw);
|
||||
if (!rc)
|
||||
rc = lutil_passwd_add((struct berval *) &scheme_totp512andpw, chk_totp512andpw, hash_totp512andpw);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -27,6 +27,12 @@ to the user's key and delivered to the user through SMS or some other channel.
|
||||
When prompted to authenticate, the user merely enters the six-digit code provided by
|
||||
the prover.
|
||||
|
||||
Additionally, the overlay can also authenticate TOTP passwords
|
||||
combined with a static password. To do this, utilize one of the
|
||||
{TOTP1ANDPW}, {TOTP256ANDPW}, or {TOTP512ANDPW} password schemes
|
||||
and append the static password scheme value to the end of the
|
||||
userPassword attribute, separated by a pipe (|) character.
|
||||
|
||||
This implementation complies with
|
||||
.B RFC 6238 TOTP Time-based One Time Passwords
|
||||
and includes support for the SHA-1, SHA-256, and SHA-512 HMAC
|
||||
@ -39,7 +45,8 @@ value should correspond to that used by the the prover (authenticator).
|
||||
|
||||
.SH CONFIGURATION
|
||||
Once the module is loaded with the moduleload command from the synopsis,
|
||||
the {TOTP1}, {TOTP256}, and {TOTP512}
|
||||
the {TOTP1}, {TOTP256}, {TOTP512}
|
||||
{TOTP1ANDPW}, {TOTP256ANDPW}, and {TOTP512ANDPW}
|
||||
password schemes will be recognized.
|
||||
|
||||
On the databases where your users reside you must configure the
|
||||
@ -68,6 +75,11 @@ is needed to properly implement TOTP, provisions need to be made to propagate
|
||||
the authTimestamp attribute to other servers that are providing authentication
|
||||
services.
|
||||
|
||||
The hash functions for the {TOTP1ANDPW}, {TOTP256ANDPW}, and {TOTP512ANDPW}
|
||||
schemes expect the secret to be entered in the form:
|
||||
<OTP seed><DELIM><static password>, where DELIM is currently defined
|
||||
as the pipe character (|).
|
||||
|
||||
.SH BUGS
|
||||
The time step is hard-coded to thirty seconds. This should be OK for many use cases,
|
||||
but it would be nice if the value
|
||||
@ -85,9 +97,6 @@ While in most cases
|
||||
this is probably better than the alternative length of four digits, there may be
|
||||
cases where a four-digit value is preferred.
|
||||
|
||||
There is currently no way to require a separate PIN code with the authenticator
|
||||
code.
|
||||
|
||||
In cases where password-hash lists multiple mechanisms, the TOTP key will also
|
||||
be changed at the same time. This is likely to be undesirable behavior.
|
||||
|
||||
@ -96,3 +105,5 @@ be changed at the same time. This is likely to be undesirable behavior.
|
||||
.SH ACKNOWLEDGEMENT
|
||||
This work was developed by Howard Chu of Symas Corporation for inclusion in
|
||||
OpenLDAP Software.
|
||||
|
||||
Password + TOTP support added by Greg Veldman on behalf of SCinet.
|
||||
|
Loading…
Reference in New Issue
Block a user