1 /* slapd-totp.c - Password module and overlay for TOTP */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2015-2018 The OpenLDAP Foundation.
6 * Portions Copyright 2015 by Howard Chu, Symas Corp.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
18 * This work includes code from the lastbind overlay.
30 #include <ac/stdlib.h>
32 #include <ac/string.h>
33 /* include socket.h to get sys/types.h and/or winsock2.h */
34 #include <ac/socket.h>
37 #include <openssl/sha.h>
38 #include <openssl/hmac.h>
40 #define TOTP_SHA512_DIGEST_LENGTH SHA512_DIGEST_LENGTH
41 #define TOTP_SHA1 EVP_sha1()
42 #define TOTP_SHA256 EVP_sha256()
43 #define TOTP_SHA512 EVP_sha512()
44 #define TOTP_HMAC_CTX HMAC_CTX *
46 #if OPENSSL_VERSION_NUMBER < 0x10100000L
47 static HMAC_CTX *HMAC_CTX_new(void)
49 HMAC_CTX *ctx = OPENSSL_malloc(sizeof(*ctx));
56 static void HMAC_CTX_free(HMAC_CTX *ctx)
59 HMAC_CTX_cleanup(ctx);
63 #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
65 #define HMAC_setup(ctx, key, len, hash) \
66 ctx = HMAC_CTX_new(); \
67 HMAC_Init_ex(ctx, key, len, hash, 0)
68 #define HMAC_crunch(ctx, buf, len) HMAC_Update(ctx, buf, len)
69 #define HMAC_finish(ctx, dig, dlen) \
70 HMAC_Final(ctx, dig, &dlen); \
74 #include <nettle/hmac.h>
76 #define TOTP_SHA512_DIGEST_LENGTH SHA512_DIGEST_SIZE
77 #define TOTP_SHA1 &nettle_sha1
78 #define TOTP_SHA256 &nettle_sha256
79 #define TOTP_SHA512 &nettle_sha512
80 #define TOTP_HMAC_CTX struct hmac_sha512_ctx
82 #define HMAC_setup(ctx, key, len, hash) \
83 const struct nettle_hash *h=hash;\
84 hmac_set_key(&ctx.outer, &ctx.inner, &ctx.state, h, len, key)
85 #define HMAC_crunch(ctx, buf, len) hmac_update(&ctx.state, h, len, buf)
86 #define HMAC_finish(ctx, dig, dlen) \
87 hmac_digest(&ctx.outer, &ctx.inner, &ctx.state, h, h->digest_size, dig);\
91 # error Unsupported crypto backend.
97 static LUTIL_PASSWD_CHK_FUNC chk_totp1, chk_totp256, chk_totp512;
98 static LUTIL_PASSWD_HASH_FUNC hash_totp1, hash_totp256, hash_totp512;
99 static const struct berval scheme_totp1 = BER_BVC("{TOTP1}");
100 static const struct berval scheme_totp256 = BER_BVC("{TOTP256}");
101 static const struct berval scheme_totp512 = BER_BVC("{TOTP512}");
103 static AttributeDescription *ad_authTimestamp;
105 /* This is the definition used by ISODE, as supplied to us in
106 * ITS#6238 Followup #9
108 static struct schema_info {
110 AttributeDescription **ad;
111 } totp_OpSchema[] = {
112 { "( 1.3.6.1.4.1.453.16.2.188 "
113 "NAME 'authTimestamp' "
114 "DESC 'last successful authentication using any method/mech' "
115 "EQUALITY generalizedTimeMatch "
116 "ORDERING generalizedTimeOrderingMatch "
117 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
118 "SINGLE-VALUE NO-USER-MODIFICATION USAGE dsaOperation )",
123 /* RFC3548 base32 encoding/decoding */
125 static const char Base32[] =
126 "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
127 static const char Pad32 = '=';
136 size_t datalength = 0;
138 u_int input1; /* assumed to be at least 32 bits */
142 while (4 < srclength) {
143 if (datalength + 8 > targsize)
155 for (i=7; i>1; i--) {
156 output[i] = input1 & 0x1f;
159 output[0] = input0 >> 3;
160 output[1] = (input0 & 0x07) << 2 | input1;
163 target[datalength++] = Base32[output[i]];
166 /* Now we worry about padding. */
167 if (0 != srclength) {
168 static const int outlen[] = { 2,4,5,7 };
170 if (datalength + 8 > targsize)
173 /* Get what's left. */
175 for (i = 1; i < srclength; i++) {
179 input1 <<= 8 * (4-srclength);
180 n = outlen[srclength-1];
181 for (i=0; i<n; i++) {
182 target[datalength++] = Base32[(input1 & 0xf8000000) >> 27];
186 target[datalength++] = Pad32;
188 if (datalength >= targsize)
190 target[datalength] = '\0'; /* Returned value doesn't count \0. */
194 /* converts characters, eight at a time, starting at src
195 from base - 32 numbers into five 8 bit bytes in the target area.
196 it returns the number of data bytes stored at the target, or -1 on error.
205 int tarindex, state, ch;
211 while ((ch = *src++) != '\0') {
215 pos = strchr(Base32, ch);
216 if (pos == 0) /* A non-base32 character. */
222 if ((size_t)tarindex >= targsize)
224 target[tarindex] = (pos - Base32) << 3;
230 if ((size_t)tarindex + 1 >= targsize)
232 target[tarindex] |= (pos - Base32) >> 2;
233 target[tarindex+1] = ((pos - Base32) & 0x3)
241 target[tarindex] |= (pos - Base32) << 1;
247 if ((size_t)tarindex + 1 >= targsize)
249 target[tarindex] |= (pos - Base32) >> 4;
250 target[tarindex+1] = ((pos - Base32) & 0xf)
258 if ((size_t)tarindex + 1 >= targsize)
260 target[tarindex] |= (pos - Base32) >> 1;
261 target[tarindex+1] = ((pos - Base32) & 0x1)
269 target[tarindex] |= (pos - Base32) << 2;
275 if ((size_t)tarindex + 1 >= targsize)
277 target[tarindex] |= (pos - Base32) >> 3;
278 target[tarindex+1] = ((pos - Base32) & 0x7)
286 target[tarindex] |= (pos - Base32);
298 * We are done decoding Base-32 chars. Let's see if we ended
299 * on a byte boundary, and/or with erroneous trailing characters.
302 if (ch == Pad32) { /* We got a pad char. */
305 /* count pad chars */
306 for (; ch; ch = *src++) {
311 /* there are only 4 valid ending states with a
312 * pad character, make sure the number of pads is valid.
315 case 2: if (i != 6) return -1;
317 case 4: if (i != 4) return -1;
319 case 5: if (i != 3) return -1;
321 case 7: if (i != 1) return -1;
327 * Now make sure that the "extra" bits that slopped past
328 * the last full byte were zeros. If we don't check them,
329 * they become a subliminal channel.
331 if (target && target[tarindex] != 0)
335 * We ended by seeing the end of the string. Make sure we
336 * have no partial bytes lying around.
348 typedef struct myval {
360 unsigned int digestLen;
362 HMAC_setup(ctx, key->mv_val, key->mv_len, hash);
363 HMAC_crunch(ctx, data->mv_val, data->mv_len);
364 HMAC_finish(ctx, out->mv_val, digestLen);
365 out->mv_len = digestLen;
368 static const int DIGITS_POWER[] = {
369 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
371 static void generate(
378 unsigned char digest[TOTP_SHA512_DIGEST_LENGTH];
381 unsigned char msg[8];
382 int i, offset, res, otp;
385 *(uint64_t *)msg = tval;
387 for (i=7; i>=0; i--) {
388 msg[i] = tval & 0xff;
394 data.mv_len = sizeof(msg);
396 digval.mv_val = digest;
397 digval.mv_len = sizeof(digest);
398 do_hmac(mech, key, &data, &digval);
400 offset = digest[digval.mv_len-1] & 0xf;
401 res = ((digest[offset] & 0x7f) << 24) |
402 ((digest[offset+1] & 0xff) << 16) |
403 ((digest[offset+2] & 0xff) << 8) |
404 (digest[offset+3] & 0xff);
406 otp = res % DIGITS_POWER[digits];
407 out->mv_len = snprintf(out->mv_val, out->mv_len, "%0*d", digits, otp);
410 static int totp_op_cleanup( Operation *op, SlapReply *rs );
411 static int totp_bind_response( Operation *op, SlapReply *rs );
417 const struct berval *passwd,
418 const struct berval *cred,
426 long t = time(0L) / TIME_STEP;
431 /* Find our thread context, find our Operation */
432 ctx = ldap_pvt_thread_pool_context();
433 if (ldap_pvt_thread_pool_getkey(ctx, totp_op_cleanup, &op_tmp, NULL) ||
435 return LUTIL_PASSWD_ERR;
438 rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &e);
439 if (rc != LDAP_SUCCESS) return LUTIL_PASSWD_ERR;
441 /* Make sure previous login is older than current time */
442 a = attr_find(e->e_attrs, ad_authTimestamp);
445 struct lutil_timet tt;
446 if (lutil_parsetime(a->a_vals[0].bv_val, &tm) == 0 &&
447 lutil_tm2time(&tm, &tt) == 0) {
448 long told = tt.tt_sec / TIME_STEP;
450 rc = LUTIL_PASSWD_ERR;
452 if (!rc) { /* seems OK, remember old stamp */
454 for (sc = op->o_callback; sc; sc = sc->sc_next) {
455 if (sc->sc_response == totp_bind_response) {
456 sc->sc_private = ber_dupbv_x(NULL, &a->a_vals[0], op->o_tmpmemctx);
461 } /* else no previous login, 1st use is OK */
463 be_entry_release_r(op, e);
466 /* Key is stored in base32 */
467 key.mv_len = passwd->bv_len * 5 / 8;
468 key.mv_val = ber_memalloc(key.mv_len+1);
471 return LUTIL_PASSWD_ERR;
473 rc = totp_b32_pton(passwd->bv_val, key.mv_val, key.mv_len);
475 rc = LUTIL_PASSWD_ERR;
480 out.mv_len = sizeof(outbuf);
481 generate(&key, t, DIGITS, &out, mech);
482 memset(key.mv_val, 0, key.mv_len);
485 if (out.mv_len != cred->bv_len) {
486 rc = LUTIL_PASSWD_ERR;
490 rc = memcmp(out.mv_val, cred->bv_val, out.mv_len) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
493 ber_memfree(key.mv_val);
497 static int chk_totp1(
498 const struct berval *scheme,
499 const struct berval *passwd,
500 const struct berval *cred,
503 return chk_totp(passwd, cred, TOTP_SHA1, text);
506 static int chk_totp256(
507 const struct berval *scheme,
508 const struct berval *passwd,
509 const struct berval *cred,
512 return chk_totp(passwd, cred, TOTP_SHA256, text);
515 static int chk_totp512(
516 const struct berval *scheme,
517 const struct berval *passwd,
518 const struct berval *cred,
521 return chk_totp(passwd, cred, TOTP_SHA512, text);
524 static int passwd_string32(
525 const struct berval *scheme,
526 const struct berval *passwd,
529 int b32len = (passwd->bv_len + 4)/5 * 8;
531 hash->bv_len = scheme->bv_len + b32len;
532 hash->bv_val = ber_memalloc(hash->bv_len + 1);
533 AC_MEMCPY(hash->bv_val, scheme->bv_val, scheme->bv_len);
534 rc = totp_b32_ntop((unsigned char *)passwd->bv_val, passwd->bv_len,
535 hash->bv_val + scheme->bv_len, b32len+1);
537 ber_memfree(hash->bv_val);
539 return LUTIL_PASSWD_ERR;
541 return LUTIL_PASSWD_OK;
544 static int hash_totp1(
545 const struct berval *scheme,
546 const struct berval *passwd,
551 if (passwd->bv_len != SHA_DIGEST_LENGTH) {
552 *text = "invalid key length";
553 return LUTIL_PASSWD_ERR;
556 return passwd_string32(scheme, passwd, hash);
559 static int hash_totp256(
560 const struct berval *scheme,
561 const struct berval *passwd,
566 if (passwd->bv_len != SHA256_DIGEST_LENGTH) {
567 *text = "invalid key length";
568 return LUTIL_PASSWD_ERR;
571 return passwd_string32(scheme, passwd, hash);
574 static int hash_totp512(
575 const struct berval *scheme,
576 const struct berval *passwd,
581 if (passwd->bv_len != SHA512_DIGEST_LENGTH) {
582 *text = "invalid key length";
583 return LUTIL_PASSWD_ERR;
586 return passwd_string32(scheme, passwd, hash);
589 static int totp_op_cleanup(
595 /* clear out the current key */
596 ldap_pvt_thread_pool_setkey( op->o_threadctx, totp_op_cleanup,
597 NULL, 0, NULL, NULL );
599 /* free the callback */
601 op->o_callback = cb->sc_next;
603 ber_bvfree_x(cb->sc_private, op->o_tmpmemctx);
604 op->o_tmpfree( cb, op->o_tmpmemctx );
609 totp_bind_response( Operation *op, SlapReply *rs )
611 Modifications *mod = NULL;
612 BackendInfo *bi = op->o_bd->bd_info;
616 /* we're only interested if the bind was successful */
617 if ( rs->sr_err != LDAP_SUCCESS )
618 return SLAP_CB_CONTINUE;
620 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
621 op->o_bd->bd_info = bi;
623 if ( rc != LDAP_SUCCESS ) {
624 return SLAP_CB_CONTINUE;
631 char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ];
632 struct berval timestamp;
634 /* get the current time */
637 /* update the authTimestamp in the user's entry with the current time */
638 timestamp.bv_val = nowstr;
639 timestamp.bv_len = sizeof(nowstr);
640 slap_timestamp( &now, ×tamp );
642 m = ch_calloc( sizeof(Modifications), 1 );
643 m->sml_op = LDAP_MOD_REPLACE;
645 m->sml_type = ad_authTimestamp->ad_cname;
646 m->sml_desc = ad_authTimestamp;
648 m->sml_values = ch_calloc( sizeof(struct berval), 2 );
649 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
651 ber_dupbv( &m->sml_values[0], ×tamp );
652 ber_dupbv( &m->sml_nvalues[0], ×tamp );
656 /* get authTimestamp attribute, if it exists */
657 if ((a = attr_find( e->e_attrs, ad_authTimestamp)) != NULL && op->o_callback->sc_private) {
658 struct berval *bv = op->o_callback->sc_private;
659 m = ch_calloc( sizeof(Modifications), 1 );
660 m->sml_op = LDAP_MOD_DELETE;
662 m->sml_type = ad_authTimestamp->ad_cname;
663 m->sml_desc = ad_authTimestamp;
665 m->sml_values = ch_calloc( sizeof(struct berval), 2 );
666 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
668 ber_dupbv( &m->sml_values[0], bv );
669 ber_dupbv( &m->sml_nvalues[0], bv );
675 be_entry_release_r( op, e );
677 /* perform the update */
680 SlapReply r2 = { REP_RESULT };
681 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
683 /* This is a DSA-specific opattr, it never gets replicated. */
684 op2.o_tag = LDAP_REQ_MODIFY;
685 op2.o_callback = &cb;
686 op2.orm_modlist = mod;
687 op2.o_dn = op->o_bd->be_rootdn;
688 op2.o_ndn = op->o_bd->be_rootndn;
689 op2.o_dont_replicate = 1;
690 rc = op->o_bd->be_modify( &op2, &r2 );
691 slap_mods_free( mod, 1 );
692 if (rc != LDAP_SUCCESS) {
693 /* slapd has logged this as a success already, but we
694 * need to fail it because the authTimestamp changed
697 rs->sr_err = LDAP_INVALID_CREDENTIALS;
698 connection2anonymous(op->o_conn);
700 op2.o_callback = NULL;
701 send_ldap_result(&op2, rs);
702 op->o_bd->bd_info = bi;
707 op->o_bd->bd_info = bi;
708 return SLAP_CB_CONTINUE;
711 static int totp_op_bind(
715 /* If this is a simple Bind, stash the Op pointer so our chk
716 * function can find it. Set a cleanup callback to clear it
717 * out when the Bind completes.
719 if ( op->oq_bind.rb_method == LDAP_AUTH_SIMPLE ) {
721 ldap_pvt_thread_pool_setkey( op->o_threadctx,
722 totp_op_cleanup, op, 0, NULL, NULL );
723 cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
724 cb->sc_response = totp_bind_response;
725 cb->sc_cleanup = totp_op_cleanup;
726 cb->sc_next = op->o_callback;
729 return SLAP_CB_CONTINUE;
732 static int totp_db_open(
739 if (!ad_authTimestamp) {
740 const char *text = NULL;
741 rc = slap_str2ad("authTimestamp", &ad_authTimestamp, &text);
743 rc = register_at(totp_OpSchema[0].def, totp_OpSchema[0].ad, 0 );
745 snprintf(cr->msg, sizeof(cr->msg), "unable to find or register authTimestamp attribute: %s (%d)",
747 Debug(LDAP_DEBUG_ANY, "totp: %s.\n", cr->msg, 0, 0);
749 ad_authTimestamp->ad_type->sat_flags |= SLAP_AT_MANAGEABLE;
755 static slap_overinst totp;
758 totp_initialize(void)
762 totp.on_bi.bi_type = "totp";
764 totp.on_bi.bi_db_open = totp_db_open;
765 totp.on_bi.bi_op_bind = totp_op_bind;
767 rc = lutil_passwd_add((struct berval *) &scheme_totp1, chk_totp1, hash_totp1);
769 rc = lutil_passwd_add((struct berval *) &scheme_totp256, chk_totp256, hash_totp256);
771 rc = lutil_passwd_add((struct berval *) &scheme_totp512, chk_totp512, hash_totp512);
775 return overlay_register(&totp);
778 int init_module(int argc, char *argv[]) {
779 return totp_initialize();