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 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 #define HMAC_setup(ctx, key, len, hash) HMAC_CTX_init(&ctx); HMAC_Init_ex(&ctx, key, len, hash, 0)
47 #define HMAC_crunch(ctx, buf, len) HMAC_Update(&ctx, buf, len)
48 #define HMAC_finish(ctx, dig, dlen) HMAC_Final(&ctx, dig, &dlen); HMAC_CTX_cleanup(&ctx)
51 #include <nettle/hmac.h>
53 #define TOTP_SHA512_DIGEST_LENGTH SHA512_DIGEST_SIZE
54 #define TOTP_SHA1 &nettle_sha1
55 #define TOTP_SHA256 &nettle_sha256
56 #define TOTP_SHA512 &nettle_sha512
57 #define TOTP_HMAC_CTX struct hmac_sha512_ctx
59 #define HMAC_setup(ctx, key, len, hash) \
60 const struct nettle_hash *h=hash;\
61 hmac_set_key(&ctx.outer, &ctx.inner, &ctx.state, h, len, key)
62 #define HMAC_crunch(ctx, buf, len) hmac_update(&ctx.state, h, len, buf)
63 #define HMAC_finish(ctx, dig, dlen) \
64 hmac_digest(&ctx.outer, &ctx.inner, &ctx.state, h, h->digest_size, dig);\
68 # error Unsupported crypto backend.
74 static LUTIL_PASSWD_CHK_FUNC chk_totp1, chk_totp256, chk_totp512;
75 static LUTIL_PASSWD_HASH_FUNC hash_totp1, hash_totp256, hash_totp512;
76 static const struct berval scheme_totp1 = BER_BVC("{TOTP1}");
77 static const struct berval scheme_totp256 = BER_BVC("{TOTP256}");
78 static const struct berval scheme_totp512 = BER_BVC("{TOTP512}");
80 static AttributeDescription *ad_authTimestamp;
82 /* This is the definition used by ISODE, as supplied to us in
83 * ITS#6238 Followup #9
85 static struct schema_info {
87 AttributeDescription **ad;
89 { "( 1.3.6.1.4.1.453.16.2.188 "
90 "NAME 'authTimestamp' "
91 "DESC 'last successful authentication using any method/mech' "
92 "EQUALITY generalizedTimeMatch "
93 "ORDERING generalizedTimeOrderingMatch "
94 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
95 "SINGLE-VALUE NO-USER-MODIFICATION USAGE dsaOperation )",
100 /* RFC3548 base32 encoding/decoding */
102 static const char Base32[] =
103 "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
104 static const char Pad32 = '=';
113 size_t datalength = 0;
115 u_int input1; /* assumed to be at least 32 bits */
119 while (4 < srclength) {
120 if (datalength + 8 > targsize)
132 for (i=7; i>1; i--) {
133 output[i] = input1 & 0x1f;
136 output[0] = input0 >> 3;
137 output[1] = (input0 & 0x07) << 2 | input1;
140 target[datalength++] = Base32[output[i]];
143 /* Now we worry about padding. */
144 if (0 != srclength) {
145 static const int outlen[] = { 2,4,5,7 };
147 if (datalength + 8 > targsize)
150 /* Get what's left. */
152 for (i = 1; i < srclength; i++) {
156 input1 <<= 8 * (4-srclength);
157 n = outlen[srclength-1];
158 for (i=0; i<n; i++) {
159 target[datalength++] = Base32[(input1 & 0xf8000000) >> 27];
163 target[datalength++] = Pad32;
165 if (datalength >= targsize)
167 target[datalength] = '\0'; /* Returned value doesn't count \0. */
171 /* converts characters, eight at a time, starting at src
172 from base - 32 numbers into five 8 bit bytes in the target area.
173 it returns the number of data bytes stored at the target, or -1 on error.
182 int tarindex, state, ch;
188 while ((ch = *src++) != '\0') {
192 pos = strchr(Base32, ch);
193 if (pos == 0) /* A non-base32 character. */
199 if ((size_t)tarindex >= targsize)
201 target[tarindex] = (pos - Base32) << 3;
207 if ((size_t)tarindex + 1 >= targsize)
209 target[tarindex] |= (pos - Base32) >> 2;
210 target[tarindex+1] = ((pos - Base32) & 0x3)
218 target[tarindex] |= (pos - Base32) << 1;
224 if ((size_t)tarindex + 1 >= targsize)
226 target[tarindex] |= (pos - Base32) >> 4;
227 target[tarindex+1] = ((pos - Base32) & 0xf)
235 if ((size_t)tarindex + 1 >= targsize)
237 target[tarindex] |= (pos - Base32) >> 1;
238 target[tarindex+1] = ((pos - Base32) & 0x1)
246 target[tarindex] |= (pos - Base32) << 2;
252 if ((size_t)tarindex + 1 >= targsize)
254 target[tarindex] |= (pos - Base32) >> 3;
255 target[tarindex+1] = ((pos - Base32) & 0x7)
263 target[tarindex] |= (pos - Base32);
275 * We are done decoding Base-32 chars. Let's see if we ended
276 * on a byte boundary, and/or with erroneous trailing characters.
279 if (ch == Pad32) { /* We got a pad char. */
282 /* count pad chars */
283 for (; ch; ch = *src++) {
288 /* there are only 4 valid ending states with a
289 * pad character, make sure the number of pads is valid.
292 case 2: if (i != 6) return -1;
294 case 4: if (i != 4) return -1;
296 case 5: if (i != 3) return -1;
298 case 7: if (i != 1) return -1;
304 * Now make sure that the "extra" bits that slopped past
305 * the last full byte were zeros. If we don't check them,
306 * they become a subliminal channel.
308 if (target && target[tarindex] != 0)
312 * We ended by seeing the end of the string. Make sure we
313 * have no partial bytes lying around.
325 typedef struct myval {
337 unsigned int digestLen;
339 HMAC_setup(ctx, key->mv_val, key->mv_len, hash);
340 HMAC_crunch(ctx, data->mv_val, data->mv_len);
341 HMAC_finish(ctx, out->mv_val, digestLen);
342 out->mv_len = digestLen;
345 static const int DIGITS_POWER[] = {
346 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
348 static void generate(
355 unsigned char digest[TOTP_SHA512_DIGEST_LENGTH];
358 unsigned char msg[8];
359 int i, offset, res, otp;
362 *(uint64_t *)msg = tval;
364 for (i=7; i>=0; i--) {
365 msg[i] = tval & 0xff;
371 data.mv_len = sizeof(msg);
373 digval.mv_val = digest;
374 digval.mv_len = sizeof(digest);
375 do_hmac(mech, key, &data, &digval);
377 offset = digest[digval.mv_len-1] & 0xf;
378 res = ((digest[offset] & 0x7f) << 24) |
379 ((digest[offset+1] & 0xff) << 16) |
380 ((digest[offset+2] & 0xff) << 8) |
381 (digest[offset+3] & 0xff);
383 otp = res % DIGITS_POWER[digits];
384 out->mv_len = snprintf(out->mv_val, out->mv_len, "%0*d", digits, otp);
387 static int totp_op_cleanup( Operation *op, SlapReply *rs );
388 static int totp_bind_response( Operation *op, SlapReply *rs );
394 const struct berval *passwd,
395 const struct berval *cred,
403 long t = time(0L) / TIME_STEP;
408 /* Find our thread context, find our Operation */
409 ctx = ldap_pvt_thread_pool_context();
410 if (ldap_pvt_thread_pool_getkey(ctx, totp_op_cleanup, &op_tmp, NULL) ||
412 return LUTIL_PASSWD_ERR;
415 rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &e);
416 if (rc != LDAP_SUCCESS) return LUTIL_PASSWD_ERR;
418 /* Make sure previous login is older than current time */
419 a = attr_find(e->e_attrs, ad_authTimestamp);
422 struct lutil_timet tt;
423 if (lutil_parsetime(a->a_vals[0].bv_val, &tm) == 0 &&
424 lutil_tm2time(&tm, &tt) == 0) {
425 long told = tt.tt_sec / TIME_STEP;
427 rc = LUTIL_PASSWD_ERR;
429 if (!rc) { /* seems OK, remember old stamp */
431 for (sc = op->o_callback; sc; sc = sc->sc_next) {
432 if (sc->sc_response == totp_bind_response) {
433 sc->sc_private = ber_dupbv_x(NULL, &a->a_vals[0], op->o_tmpmemctx);
438 } /* else no previous login, 1st use is OK */
440 be_entry_release_r(op, e);
443 /* Key is stored in base32 */
444 key.mv_len = passwd->bv_len * 5 / 8;
445 key.mv_val = ber_memalloc(key.mv_len+1);
448 return LUTIL_PASSWD_ERR;
450 rc = totp_b32_pton(passwd->bv_val, key.mv_val, key.mv_len);
452 rc = LUTIL_PASSWD_ERR;
457 out.mv_len = sizeof(outbuf);
458 generate(&key, t, DIGITS, &out, mech);
459 memset(key.mv_val, 0, key.mv_len);
462 if (out.mv_len != cred->bv_len) {
463 rc = LUTIL_PASSWD_ERR;
467 rc = memcmp(out.mv_val, cred->bv_val, out.mv_len) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
470 ber_memfree(key.mv_val);
474 static int chk_totp1(
475 const struct berval *scheme,
476 const struct berval *passwd,
477 const struct berval *cred,
480 return chk_totp(passwd, cred, TOTP_SHA1, text);
483 static int chk_totp256(
484 const struct berval *scheme,
485 const struct berval *passwd,
486 const struct berval *cred,
489 return chk_totp(passwd, cred, TOTP_SHA256, text);
492 static int chk_totp512(
493 const struct berval *scheme,
494 const struct berval *passwd,
495 const struct berval *cred,
498 return chk_totp(passwd, cred, TOTP_SHA512, text);
501 static int passwd_string32(
502 const struct berval *scheme,
503 const struct berval *passwd,
506 int b32len = (passwd->bv_len + 4)/5 * 8;
508 hash->bv_len = scheme->bv_len + b32len;
509 hash->bv_val = ber_memalloc(hash->bv_len + 1);
510 AC_MEMCPY(hash->bv_val, scheme->bv_val, scheme->bv_len);
511 rc = totp_b32_ntop((unsigned char *)passwd->bv_val, passwd->bv_len,
512 hash->bv_val + scheme->bv_len, b32len+1);
514 ber_memfree(hash->bv_val);
516 return LUTIL_PASSWD_ERR;
518 return LUTIL_PASSWD_OK;
521 static int hash_totp1(
522 const struct berval *scheme,
523 const struct berval *passwd,
528 if (passwd->bv_len != SHA_DIGEST_LENGTH) {
529 *text = "invalid key length";
530 return LUTIL_PASSWD_ERR;
533 return passwd_string32(scheme, passwd, hash);
536 static int hash_totp256(
537 const struct berval *scheme,
538 const struct berval *passwd,
543 if (passwd->bv_len != SHA256_DIGEST_LENGTH) {
544 *text = "invalid key length";
545 return LUTIL_PASSWD_ERR;
548 return passwd_string32(scheme, passwd, hash);
551 static int hash_totp512(
552 const struct berval *scheme,
553 const struct berval *passwd,
558 if (passwd->bv_len != SHA512_DIGEST_LENGTH) {
559 *text = "invalid key length";
560 return LUTIL_PASSWD_ERR;
563 return passwd_string32(scheme, passwd, hash);
566 static int totp_op_cleanup(
572 /* clear out the current key */
573 ldap_pvt_thread_pool_setkey( op->o_threadctx, totp_op_cleanup,
574 NULL, 0, NULL, NULL );
576 /* free the callback */
578 op->o_callback = cb->sc_next;
580 ber_bvfree_x(cb->sc_private, op->o_tmpmemctx);
581 op->o_tmpfree( cb, op->o_tmpmemctx );
586 totp_bind_response( Operation *op, SlapReply *rs )
588 Modifications *mod = NULL;
589 BackendInfo *bi = op->o_bd->bd_info;
593 /* we're only interested if the bind was successful */
594 if ( rs->sr_err != LDAP_SUCCESS )
595 return SLAP_CB_CONTINUE;
597 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
598 op->o_bd->bd_info = bi;
600 if ( rc != LDAP_SUCCESS ) {
601 return SLAP_CB_CONTINUE;
608 char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ];
609 struct berval timestamp;
611 /* get the current time */
614 /* update the authTimestamp in the user's entry with the current time */
615 timestamp.bv_val = nowstr;
616 timestamp.bv_len = sizeof(nowstr);
617 slap_timestamp( &now, ×tamp );
619 m = ch_calloc( sizeof(Modifications), 1 );
620 m->sml_op = LDAP_MOD_REPLACE;
622 m->sml_type = ad_authTimestamp->ad_cname;
623 m->sml_desc = ad_authTimestamp;
625 m->sml_values = ch_calloc( sizeof(struct berval), 2 );
626 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
628 ber_dupbv( &m->sml_values[0], ×tamp );
629 ber_dupbv( &m->sml_nvalues[0], ×tamp );
633 /* get authTimestamp attribute, if it exists */
634 if ((a = attr_find( e->e_attrs, ad_authTimestamp)) != NULL && op->o_callback->sc_private) {
635 struct berval *bv = op->o_callback->sc_private;
636 m = ch_calloc( sizeof(Modifications), 1 );
637 m->sml_op = LDAP_MOD_DELETE;
639 m->sml_type = ad_authTimestamp->ad_cname;
640 m->sml_desc = ad_authTimestamp;
642 m->sml_values = ch_calloc( sizeof(struct berval), 2 );
643 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
645 ber_dupbv( &m->sml_values[0], bv );
646 ber_dupbv( &m->sml_nvalues[0], bv );
652 be_entry_release_r( op, e );
654 /* perform the update */
657 SlapReply r2 = { REP_RESULT };
658 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
660 /* This is a DSA-specific opattr, it never gets replicated. */
661 op2.o_tag = LDAP_REQ_MODIFY;
662 op2.o_callback = &cb;
663 op2.orm_modlist = mod;
664 op2.o_dn = op->o_bd->be_rootdn;
665 op2.o_ndn = op->o_bd->be_rootndn;
666 op2.o_dont_replicate = 1;
667 rc = op->o_bd->be_modify( &op2, &r2 );
668 slap_mods_free( mod, 1 );
669 if (rc != LDAP_SUCCESS) {
670 /* slapd has logged this as a success already, but we
671 * need to fail it because the authTimestamp changed
674 rs->sr_err = LDAP_INVALID_CREDENTIALS;
675 connection2anonymous(op->o_conn);
677 op2.o_callback = NULL;
678 send_ldap_result(&op2, rs);
679 op->o_bd->bd_info = bi;
684 op->o_bd->bd_info = bi;
685 return SLAP_CB_CONTINUE;
688 static int totp_op_bind(
692 /* If this is a simple Bind, stash the Op pointer so our chk
693 * function can find it. Set a cleanup callback to clear it
694 * out when the Bind completes.
696 if ( op->oq_bind.rb_method == LDAP_AUTH_SIMPLE ) {
698 ldap_pvt_thread_pool_setkey( op->o_threadctx,
699 totp_op_cleanup, op, 0, NULL, NULL );
700 cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
701 cb->sc_response = totp_bind_response;
702 cb->sc_cleanup = totp_op_cleanup;
703 cb->sc_next = op->o_callback;
706 return SLAP_CB_CONTINUE;
709 static int totp_db_open(
716 if (!ad_authTimestamp) {
717 const char *text = NULL;
718 rc = slap_str2ad("authTimestamp", &ad_authTimestamp, &text);
720 rc = register_at(totp_OpSchema[0].def, totp_OpSchema[0].ad, 0 );
722 snprintf(cr->msg, sizeof(cr->msg), "unable to find or register authTimestamp attribute: %s (%d)",
724 Debug(LDAP_DEBUG_ANY, "totp: %s.\n", cr->msg, 0, 0);
726 ad_authTimestamp->ad_type->sat_flags |= SLAP_AT_MANAGEABLE;
732 static slap_overinst totp;
735 totp_initialize(void)
739 totp.on_bi.bi_type = "totp";
741 totp.on_bi.bi_db_open = totp_db_open;
742 totp.on_bi.bi_op_bind = totp_op_bind;
744 rc = lutil_passwd_add((struct berval *) &scheme_totp1, chk_totp1, hash_totp1);
746 rc = lutil_passwd_add((struct berval *) &scheme_totp256, chk_totp256, hash_totp256);
748 rc = lutil_passwd_add((struct berval *) &scheme_totp512, chk_totp512, hash_totp512);
752 return overlay_register(&totp);
755 int init_module(int argc, char *argv[]) {
756 return totp_initialize();