xref: /netbsd-src/external/bsd/openldap/dist/contrib/slapd-modules/passwd/totp/slapd-totp.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: slapd-totp.c,v 1.2 2021/08/14 16:14:53 christos Exp $	*/
2 
3 /* slapd-totp.c - Password module and overlay for TOTP */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 2015-2021 The OpenLDAP Foundation.
8  * Portions Copyright 2015 by Howard Chu, Symas Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted only as authorized by the OpenLDAP
13  * Public License.
14  *
15  * A copy of this license is available in the file LICENSE in the
16  * top-level directory of the distribution or, alternatively, at
17  * <http://www.OpenLDAP.org/license.html>.
18  */
19 /* ACKNOWLEDGEMENTS:
20  * This work includes code from the lastbind overlay.
21  */
22 
23 #include <portable.h>
24 
25 #if HAVE_STDINT_H
26 #include <stdint.h>
27 #endif
28 
29 #include <lber.h>
30 #include <lber_pvt.h>
31 #include "lutil.h"
32 #include <ac/stdlib.h>
33 #include <ac/ctype.h>
34 #include <ac/string.h>
35 /* include socket.h to get sys/types.h and/or winsock2.h */
36 #include <ac/socket.h>
37 
38 #if HAVE_OPENSSL
39 #include <openssl/sha.h>
40 #include <openssl/hmac.h>
41 
42 #define TOTP_SHA512_DIGEST_LENGTH	SHA512_DIGEST_LENGTH
43 #define TOTP_SHA1	EVP_sha1()
44 #define TOTP_SHA256	EVP_sha256()
45 #define TOTP_SHA512	EVP_sha512()
46 #define TOTP_HMAC_CTX	HMAC_CTX *
47 
48 #if OPENSSL_VERSION_NUMBER < 0x10100000L
HMAC_CTX_new(void)49 static HMAC_CTX *HMAC_CTX_new(void)
50 {
51 	HMAC_CTX *ctx = OPENSSL_malloc(sizeof(*ctx));
52 	if (ctx != NULL) {
53 		HMAC_CTX_init(ctx);
54 	}
55 	return ctx;
56 }
57 
HMAC_CTX_free(HMAC_CTX * ctx)58 static void HMAC_CTX_free(HMAC_CTX *ctx)
59 {
60 	if (ctx != NULL) {
61 		HMAC_CTX_cleanup(ctx);
62 		OPENSSL_free(ctx);
63 	}
64 }
65 #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
66 
67 #define HMAC_setup(ctx, key, len, hash) \
68 	ctx = HMAC_CTX_new(); \
69 	HMAC_Init_ex(ctx, key, len, hash, 0)
70 #define HMAC_crunch(ctx, buf, len)	HMAC_Update(ctx, buf, len)
71 #define HMAC_finish(ctx, dig, dlen) \
72 	HMAC_Final(ctx, dig, &dlen); \
73 	HMAC_CTX_free(ctx)
74 
75 #elif HAVE_GNUTLS
76 #include <nettle/hmac.h>
77 
78 #define TOTP_SHA512_DIGEST_LENGTH	SHA512_DIGEST_SIZE
79 #define TOTP_SHA1	&nettle_sha1
80 #define TOTP_SHA256	&nettle_sha256
81 #define TOTP_SHA512	&nettle_sha512
82 #define TOTP_HMAC_CTX	struct hmac_sha512_ctx
83 
84 #define HMAC_setup(ctx, key, len, hash)	\
85 	const struct nettle_hash *h=hash;\
86 	hmac_set_key(&ctx.outer, &ctx.inner, &ctx.state, h, len, key)
87 #define HMAC_crunch(ctx, buf, len)	hmac_update(&ctx.state, h, len, buf)
88 #define HMAC_finish(ctx, dig, dlen) \
89 	hmac_digest(&ctx.outer, &ctx.inner, &ctx.state, h, h->digest_size, dig);\
90 	dlen = h->digest_size
91 
92 #else
93 # error Unsupported crypto backend.
94 #endif
95 
96 #include "slap.h"
97 #include "slap-config.h"
98 
99 static LUTIL_PASSWD_CHK_FUNC chk_totp1, chk_totp256, chk_totp512,
100 	chk_totp1andpw, chk_totp256andpw, chk_totp512andpw;
101 static LUTIL_PASSWD_HASH_FUNC hash_totp1, hash_totp256, hash_totp512,
102 	hash_totp1andpw, hash_totp256andpw, hash_totp512andpw;
103 static const struct berval scheme_totp1 = BER_BVC("{TOTP1}");
104 static const struct berval scheme_totp256 = BER_BVC("{TOTP256}");
105 static const struct berval scheme_totp512 = BER_BVC("{TOTP512}");
106 static const struct berval scheme_totp1andpw = BER_BVC("{TOTP1ANDPW}");
107 static const struct berval scheme_totp256andpw = BER_BVC("{TOTP256ANDPW}");
108 static const struct berval scheme_totp512andpw = BER_BVC("{TOTP512ANDPW}");
109 
110 static AttributeDescription *ad_authTimestamp;
111 
112 /* This is the definition used by ISODE, as supplied to us in
113  * ITS#6238 Followup #9
114  */
115 static struct schema_info {
116 	char *def;
117 	AttributeDescription **ad;
118 } totp_OpSchema[] = {
119 	{	"( 1.3.6.1.4.1.453.16.2.188 "
120 		"NAME 'authTimestamp' "
121 		"DESC 'last successful authentication using any method/mech' "
122 		"EQUALITY generalizedTimeMatch "
123 		"ORDERING generalizedTimeOrderingMatch "
124 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
125 		"SINGLE-VALUE NO-USER-MODIFICATION USAGE dsaOperation )",
126 		&ad_authTimestamp},
127 	{ NULL, NULL }
128 };
129 
130 /* RFC3548 base32 encoding/decoding */
131 
132 static const char Base32[] =
133 	"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
134 static const char Pad32 = '=';
135 
136 static int
totp_b32_ntop(u_char const * src,size_t srclength,char * target,size_t targsize)137 totp_b32_ntop(
138 	u_char const *src,
139 	size_t srclength,
140 	char *target,
141 	size_t targsize)
142 {
143 	size_t datalength = 0;
144 	u_char input0;
145 	u_int input1;	/* assumed to be at least 32 bits */
146 	u_char output[8];
147 	int i;
148 
149 	while (4 < srclength) {
150 		if (datalength + 8 > targsize)
151 			return (-1);
152 		input0 = *src++;
153 		input1 = *src++;
154 		input1 <<= 8;
155 		input1 |= *src++;
156 		input1 <<= 8;
157 		input1 |= *src++;
158 		input1 <<= 8;
159 		input1 |= *src++;
160 		srclength -= 5;
161 
162 		for (i=7; i>1; i--) {
163 			output[i] = input1 & 0x1f;
164 			input1 >>= 5;
165 		}
166 		output[0] = input0 >> 3;
167 		output[1] = (input0 & 0x07) << 2 | input1;
168 
169 		for (i=0; i<8; i++)
170 			target[datalength++] = Base32[output[i]];
171 	}
172 
173 	/* Now we worry about padding. */
174 	if (0 != srclength) {
175 		static const int outlen[] = { 2,4,5,7 };
176 		int n;
177 		if (datalength + 8 > targsize)
178 			return (-1);
179 
180 		/* Get what's left. */
181 		input1 = *src++;
182 		for (i = 1; i < srclength; i++) {
183 			input1 <<= 8;
184 			input1 |= *src++;
185 		}
186 		input1 <<= 8 * (4-srclength);
187 		n = outlen[srclength-1];
188 		for (i=0; i<n; i++) {
189 			target[datalength++] = Base32[(input1 & 0xf8000000) >> 27];
190 			input1 <<= 5;
191 		}
192 		for (; i<8; i++)
193 			target[datalength++] = Pad32;
194 	}
195 	if (datalength >= targsize)
196 		return (-1);
197 	target[datalength] = '\0';	/* Returned value doesn't count \0. */
198 	return (datalength);
199 }
200 
201 /* converts characters, eight at a time, starting at src
202    from base - 32 numbers into five 8 bit bytes in the target area.
203    it returns the number of data bytes stored at the target, or -1 on error.
204  */
205 
206 static int
totp_b32_pton(char const * src,u_char * target,size_t targsize)207 totp_b32_pton(
208 	char const *src,
209 	u_char *target,
210 	size_t targsize)
211 {
212 	int tarindex, state, ch;
213 	char *pos;
214 
215 	state = 0;
216 	tarindex = 0;
217 
218 	while ((ch = *src++) != '\0') {
219 		if (ch == Pad32)
220 			break;
221 
222 		pos = strchr(Base32, ch);
223 		if (pos == 0) 		/* A non-base32 character. */
224 			return (-1);
225 
226 		switch (state) {
227 		case 0:
228 			if (target) {
229 				if ((size_t)tarindex >= targsize)
230 					return (-1);
231 				target[tarindex] = (pos - Base32) << 3;
232 			}
233 			state = 1;
234 			break;
235 		case 1:
236 			if (target) {
237 				if ((size_t)tarindex + 1 >= targsize)
238 					return (-1);
239 				target[tarindex]   |=  (pos - Base32) >> 2;
240 				target[tarindex+1]  = ((pos - Base32) & 0x3)
241 							<< 6 ;
242 			}
243 			tarindex++;
244 			state = 2;
245 			break;
246 		case 2:
247 			if (target) {
248 				target[tarindex]   |=  (pos - Base32) << 1;
249 			}
250 			state = 3;
251 			break;
252 		case 3:
253 			if (target) {
254 				if ((size_t)tarindex + 1 >= targsize)
255 					return (-1);
256 				target[tarindex] |= (pos - Base32) >> 4;
257 				target[tarindex+1]  = ((pos - Base32) & 0xf)
258 							<< 4 ;
259 			}
260 			tarindex++;
261 			state = 4;
262 			break;
263 		case 4:
264 			if (target) {
265 				if ((size_t)tarindex + 1 >= targsize)
266 					return (-1);
267 				target[tarindex] |= (pos - Base32) >> 1;
268 				target[tarindex+1]  = ((pos - Base32) & 0x1)
269 							<< 7 ;
270 			}
271 			tarindex++;
272 			state = 5;
273 			break;
274 		case 5:
275 			if (target) {
276 				target[tarindex]   |=  (pos - Base32) << 2;
277 			}
278 			state = 6;
279 			break;
280 		case 6:
281 			if (target) {
282 				if ((size_t)tarindex + 1 >= targsize)
283 					return (-1);
284 				target[tarindex] |= (pos - Base32) >> 3;
285 				target[tarindex+1]  = ((pos - Base32) & 0x7)
286 							<< 5 ;
287 			}
288 			tarindex++;
289 			state = 7;
290 			break;
291 		case 7:
292 			if (target) {
293 				target[tarindex]   |=  (pos - Base32);
294 			}
295 			state = 0;
296 			tarindex++;
297 			break;
298 
299 		default:
300 			abort();
301 		}
302 	}
303 
304 	/*
305 	 * We are done decoding Base-32 chars.  Let's see if we ended
306 	 * on a byte boundary, and/or with erroneous trailing characters.
307 	 */
308 
309 	if (ch == Pad32) {		/* We got a pad char. */
310 		int i = 0;
311 
312 		/* count pad chars */
313 		for (; ch; ch = *src++) {
314 			if (ch != Pad32)
315 				return (-1);
316 			i++;
317 		}
318 		/* there are only 4 valid ending states with a
319 		 * pad character, make sure the number of pads is valid.
320 		 */
321 		switch(state) {
322 		case 2:	if (i != 6) return -1;
323 			break;
324 		case 4: if (i != 4) return -1;
325 			break;
326 		case 5: if (i != 3) return -1;
327 			break;
328 		case 7: if (i != 1) return -1;
329 			break;
330 		default:
331 			return -1;
332 		}
333 		/*
334 		 * Now make sure that the "extra" bits that slopped past
335 		 * the last full byte were zeros.  If we don't check them,
336 		 * they become a subliminal channel.
337 		 */
338 		if (target && target[tarindex] != 0)
339 			return (-1);
340 	} else {
341 		/*
342 		 * We ended by seeing the end of the string.  Make sure we
343 		 * have no partial bytes lying around.
344 		 */
345 		if (state != 0)
346 			return (-1);
347 	}
348 
349 	return (tarindex);
350 }
351 
352 /* RFC6238 TOTP */
353 
354 
355 typedef struct myval {
356 	ber_len_t mv_len;
357 	void *mv_val;
358 } myval;
359 
do_hmac(const void * hash,myval * key,myval * data,myval * out)360 static void do_hmac(
361 	const void *hash,
362 	myval *key,
363 	myval *data,
364 	myval *out)
365 {
366 	TOTP_HMAC_CTX ctx;
367 	unsigned int digestLen;
368 
369 	HMAC_setup(ctx, key->mv_val, key->mv_len, hash);
370 	HMAC_crunch(ctx, data->mv_val, data->mv_len);
371 	HMAC_finish(ctx, out->mv_val, digestLen);
372 	out->mv_len = digestLen;
373 }
374 
375 static const int DIGITS_POWER[] = {
376 	1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
377 
generate(myval * key,uint64_t tval,int digits,myval * out,const void * mech)378 static void generate(
379 	myval *key,
380 	uint64_t tval,
381 	int digits,
382 	myval *out,
383 	const void *mech)
384 {
385 	unsigned char digest[TOTP_SHA512_DIGEST_LENGTH];
386 	myval digval;
387 	myval data;
388 	unsigned char msg[8];
389 	int i, offset, res, otp;
390 
391 #if WORDS_BIGENDIAN
392 	*(uint64_t *)msg = tval;
393 #else
394 	for (i=7; i>=0; i--) {
395 		msg[i] = tval & 0xff;
396 		tval >>= 8;
397 	}
398 #endif
399 
400 	data.mv_val = msg;
401 	data.mv_len = sizeof(msg);
402 
403 	digval.mv_val = digest;
404 	digval.mv_len = sizeof(digest);
405 	do_hmac(mech, key, &data, &digval);
406 
407 	offset = digest[digval.mv_len-1] & 0xf;
408 	res = ((digest[offset] & 0x7f) << 24) |
409 			((digest[offset+1] & 0xff) << 16) |
410 			((digest[offset+2] & 0xff) << 8) |
411 			(digest[offset+3] & 0xff);
412 
413 	otp = res % DIGITS_POWER[digits];
414 	out->mv_len = snprintf(out->mv_val, out->mv_len, "%0*d", digits, otp);
415 }
416 
417 static int totp_op_cleanup( Operation *op, SlapReply *rs );
418 static int totp_bind_response( Operation *op, SlapReply *rs );
419 
420 #define TIME_STEP	30
421 #define DIGITS	6
422 #define DELIM	'|'	/* a single character */
423 #define TOTP_AND_PW_HASH_SCHEME	"{SSHA}"
424 
chk_totp(const struct berval * passwd,const struct berval * cred,const void * mech,const char ** text)425 static int chk_totp(
426 	const struct berval *passwd,
427 	const struct berval *cred,
428 	const void *mech,
429 	const char **text)
430 {
431 	void *ctx, *op_tmp;
432 	Operation *op;
433 	Entry *e;
434 	Attribute *a;
435 	long t, told = 0;
436 	int rc;
437 	myval out, key;
438 	char outbuf[32];
439 
440 	/* Find our thread context, find our Operation */
441 	ctx = ldap_pvt_thread_pool_context();
442 	if (ldap_pvt_thread_pool_getkey(ctx, totp_op_cleanup, &op_tmp, NULL) ||
443 		!op_tmp)
444 		return LUTIL_PASSWD_ERR;
445 	op = op_tmp;
446 
447 	rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &e);
448 	if (rc != LDAP_SUCCESS) return LUTIL_PASSWD_ERR;
449 
450 	/* Make sure previous login is older than current time */
451 	t = op->o_time / TIME_STEP;
452 	a = attr_find(e->e_attrs, ad_authTimestamp);
453 	if (a) {
454 		struct lutil_tm tm;
455 		struct lutil_timet tt;
456 		if (lutil_parsetime(a->a_vals[0].bv_val, &tm) == 0 &&
457 			lutil_tm2time(&tm, &tt) == 0) {
458 			told = tt.tt_sec / TIME_STEP;
459 			if (told >= t)
460 				rc = LUTIL_PASSWD_ERR;
461 		}
462 		if (!rc) {	/* seems OK, remember old stamp */
463 			slap_callback *sc;
464 			for (sc = op->o_callback; sc; sc = sc->sc_next) {
465 				if (sc->sc_response == totp_bind_response) {
466 					sc->sc_private = ber_dupbv_x(NULL, &a->a_vals[0], op->o_tmpmemctx);
467 					break;
468 				}
469 			}
470 		}
471 	}	/* else no previous login, 1st use is OK */
472 
473 	be_entry_release_r(op, e);
474 	if (rc) return rc;
475 
476 	/* Key is stored in base32 */
477 	key.mv_len = passwd->bv_len * 5 / 8;
478 	key.mv_val = ber_memalloc(key.mv_len+1);
479 
480 	if (!key.mv_val)
481 		return LUTIL_PASSWD_ERR;
482 
483 	rc = totp_b32_pton(passwd->bv_val, key.mv_val, key.mv_len);
484 	if (rc < 1) {
485 		rc = LUTIL_PASSWD_ERR;
486 		goto out;
487 	}
488 
489 	out.mv_val = outbuf;
490 	out.mv_len = sizeof(outbuf);
491 	generate(&key, t, DIGITS, &out, mech);
492 
493 	/* compare */
494 	if (out.mv_len != cred->bv_len) {
495 		rc = LUTIL_PASSWD_ERR;
496 		goto out;
497 	}
498 
499 	rc = memcmp(out.mv_val, cred->bv_val, out.mv_len) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
500 
501 	/* If current value doesn't match, try again with previous value
502 	 * but only if the most recent login is older than the previous
503 	 * time step but still set */
504 	if (rc == LUTIL_PASSWD_ERR && told < t - 1 && told > 0) {
505 		out.mv_val = outbuf;
506 		out.mv_len = sizeof(outbuf);
507 		generate(&key, t - 1, DIGITS, &out, mech);
508 		/* compare */
509 		if (out.mv_len != cred->bv_len)
510 			goto out;
511 		rc = memcmp(out.mv_val, cred->bv_val, out.mv_len) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
512 	}
513 
514 out:
515 	memset(key.mv_val, 0, key.mv_len);
516 	ber_memfree(key.mv_val);
517 	return rc;
518 }
519 
chk_totp_and_pw(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text,const void * mech)520 static int chk_totp_and_pw(
521 	const struct berval *scheme,
522 	const struct berval *passwd,
523 	const struct berval *cred,
524 	const char **text,
525 	const void *mech)
526 {
527 	char *s;
528 	int rc = LUTIL_PASSWD_ERR, rc_pass, rc_otp;
529 	ber_len_t len;
530 	struct berval cred_pass, cred_otp, passwd_pass, passwd_otp;
531 
532 	/* Check credential length, no point to continue if too short */
533 	if (cred->bv_len <= DIGITS)
534 		return rc;
535 
536 	/* The OTP seed of the stored password */
537 	s = strchr(passwd->bv_val, DELIM);
538 	if (s) {
539 		len = s - passwd->bv_val;
540 	} else {
541 		return rc;
542 	}
543 	if (!ber_str2bv(passwd->bv_val, len, 1, &passwd_otp))
544 		return rc;
545 
546 	/* The password part of the stored password */
547 	s++;
548 	ber_str2bv(s, 0, 0, &passwd_pass);
549 
550 	/* The OTP part of the entered credential */
551 	ber_str2bv(&cred->bv_val[cred->bv_len - DIGITS], DIGITS, 0, &cred_otp);
552 
553 	/* The password part of the entered credential */
554 	if (!ber_str2bv(cred->bv_val, cred->bv_len - DIGITS, 0, &cred_pass)) {
555 		/* Cleanup */
556 		memset(passwd_otp.bv_val, 0, passwd_otp.bv_len);
557 		ber_memfree(passwd_otp.bv_val);
558 		return rc;
559 	}
560 
561 	rc_otp = chk_totp(&passwd_otp, &cred_otp, mech, text);
562 	rc_pass = lutil_passwd(&passwd_pass, &cred_pass, NULL, text);
563 	if (rc_otp == LUTIL_PASSWD_OK && rc_pass == LUTIL_PASSWD_OK)
564 		rc = LUTIL_PASSWD_OK;
565 
566 	/* Cleanup and return */
567 	memset(passwd_otp.bv_val, 0, passwd_otp.bv_len);
568 	ber_memfree(passwd_otp.bv_val);
569 
570 	return rc;
571 }
572 
chk_totp1(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text)573 static int chk_totp1(
574 	const struct berval *scheme,
575 	const struct berval *passwd,
576 	const struct berval *cred,
577 	const char **text)
578 {
579 	return chk_totp(passwd, cred, TOTP_SHA1, text);
580 }
581 
chk_totp256(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text)582 static int chk_totp256(
583 	const struct berval *scheme,
584 	const struct berval *passwd,
585 	const struct berval *cred,
586 	const char **text)
587 {
588 	return chk_totp(passwd, cred, TOTP_SHA256, text);
589 }
590 
chk_totp512(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text)591 static int chk_totp512(
592 	const struct berval *scheme,
593 	const struct berval *passwd,
594 	const struct berval *cred,
595 	const char **text)
596 {
597 	return chk_totp(passwd, cred, TOTP_SHA512, text);
598 }
599 
chk_totp1andpw(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text)600 static int chk_totp1andpw(
601 	const struct berval *scheme,
602 	const struct berval *passwd,
603 	const struct berval *cred,
604 	const char **text)
605 {
606 	return chk_totp_and_pw(scheme, passwd, cred, text, TOTP_SHA1);
607 }
608 
chk_totp256andpw(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text)609 static int chk_totp256andpw(
610 	const struct berval *scheme,
611 	const struct berval *passwd,
612 	const struct berval *cred,
613 	const char **text)
614 {
615 	return chk_totp_and_pw(scheme, passwd, cred, text, TOTP_SHA256);
616 }
617 
chk_totp512andpw(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text)618 static int chk_totp512andpw(
619 	const struct berval *scheme,
620 	const struct berval *passwd,
621 	const struct berval *cred,
622 	const char **text)
623 {
624 	return chk_totp_and_pw(scheme, passwd, cred, text, TOTP_SHA512);
625 }
626 
passwd_string32(const struct berval * scheme,const struct berval * passwd,struct berval * hash)627 static int passwd_string32(
628 	const struct berval *scheme,
629 	const struct berval *passwd,
630 	struct berval *hash)
631 {
632 	int b32len = (passwd->bv_len + 4)/5 * 8;
633 	int rc;
634 	hash->bv_len = scheme->bv_len + b32len;
635 	hash->bv_val = ber_memalloc(hash->bv_len + 1);
636 	AC_MEMCPY(hash->bv_val, scheme->bv_val, scheme->bv_len);
637 	rc = totp_b32_ntop((unsigned char *)passwd->bv_val, passwd->bv_len,
638 		hash->bv_val + scheme->bv_len, b32len+1);
639 	if (rc < 0) {
640 		ber_memfree(hash->bv_val);
641 		hash->bv_val = NULL;
642 		return LUTIL_PASSWD_ERR;
643 	}
644 	return LUTIL_PASSWD_OK;
645 }
646 
hash_totp_and_pw(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)647 static int hash_totp_and_pw(
648 	const struct berval *scheme,
649 	const struct berval *passwd,
650 	struct berval *hash,
651 	const char **text)
652 {
653 	struct berval otp, pass, hash_otp, hash_pass;
654 	ber_len_t len;
655 	char *s;
656 	int rc = LUTIL_PASSWD_ERR;
657 
658 	/* The OTP seed part */
659 	s = strchr(passwd->bv_val, DELIM);
660 	if (s) {
661 		len = s - passwd->bv_val;
662 	} else {
663 		return rc;
664 	}
665 	if (!ber_str2bv(passwd->bv_val, len, 0, &otp))
666 		return rc;
667 
668 	/* The static password part */
669 	s++;
670 	ber_str2bv(s, 0, 0, &pass);
671 
672 	/* Hash the OTP seed */
673 	rc = passwd_string32(scheme, &otp, &hash_otp);
674 
675 	/* If successful, hash the static password, else cleanup and return */
676 	if (rc == LUTIL_PASSWD_OK) {
677 		rc = lutil_passwd_hash(&pass, TOTP_AND_PW_HASH_SCHEME,
678 			&hash_pass, text);
679 	} else {
680 		return LUTIL_PASSWD_ERR;
681 	}
682 
683 	/* If successful, allocate memory to combine them, else cleanup
684 	 *  and return */
685 	if (rc == LUTIL_PASSWD_OK) {
686 		/* Add 1 character to bv_len to hold DELIM */
687 		hash->bv_len = hash_pass.bv_len + hash_otp.bv_len + 1;
688 		hash->bv_val = ber_memalloc(hash->bv_len + 1);
689 		if (!hash->bv_val)
690 			rc = LUTIL_PASSWD_ERR;
691 	} else {
692 		memset(hash_otp.bv_val, 0, hash_otp.bv_len);
693 		ber_memfree(hash_otp.bv_val);
694 		return LUTIL_PASSWD_ERR;
695 	}
696 
697 	/* If successful, combine the two hashes with the delimiter */
698 	if (rc == LUTIL_PASSWD_OK) {
699 		AC_MEMCPY(hash->bv_val, hash_otp.bv_val, hash_otp.bv_len);
700 		hash->bv_val[hash_otp.bv_len] = DELIM;
701 		AC_MEMCPY(hash->bv_val + hash_otp.bv_len + 1,
702 			hash_pass.bv_val, hash_pass.bv_len);
703 		hash->bv_val[hash->bv_len] = '\0';
704 	}
705 
706 	/* Cleanup and return */
707 	memset(hash_otp.bv_val, 0, hash_otp.bv_len);
708 	memset(hash_pass.bv_val, 0, hash_pass.bv_len);
709 	ber_memfree(hash_otp.bv_val);
710 	ber_memfree(hash_pass.bv_val);
711 
712 	return rc;
713 }
714 
hash_totp1(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)715 static int hash_totp1(
716 	const struct berval *scheme,
717 	const struct berval *passwd,
718 	struct berval *hash,
719 	const char **text)
720 {
721 #if 0
722 	if (passwd->bv_len != SHA_DIGEST_LENGTH) {
723 		*text = "invalid key length";
724 		return LUTIL_PASSWD_ERR;
725 	}
726 #endif
727 	return passwd_string32(scheme, passwd, hash);
728 }
729 
hash_totp256(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)730 static int hash_totp256(
731 	const struct berval *scheme,
732 	const struct berval *passwd,
733 	struct berval *hash,
734 	const char **text)
735 {
736 #if 0
737 	if (passwd->bv_len != SHA256_DIGEST_LENGTH) {
738 		*text = "invalid key length";
739 		return LUTIL_PASSWD_ERR;
740 	}
741 #endif
742 	return passwd_string32(scheme, passwd, hash);
743 }
744 
hash_totp512(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)745 static int hash_totp512(
746 	const struct berval *scheme,
747 	const struct berval *passwd,
748 	struct berval *hash,
749 	const char **text)
750 {
751 #if 0
752 	if (passwd->bv_len != SHA512_DIGEST_LENGTH) {
753 		*text = "invalid key length";
754 		return LUTIL_PASSWD_ERR;
755 	}
756 #endif
757 	return passwd_string32(scheme, passwd, hash);
758 }
759 
hash_totp1andpw(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)760 static int hash_totp1andpw(
761 	const struct berval *scheme,
762 	const struct berval *passwd,
763 	struct berval *hash,
764 	const char **text)
765 {
766 #if 0
767 	if (passwd->bv_len != SHA_DIGEST_LENGTH) {
768 		*text = "invalid key length";
769 		return LUTIL_PASSWD_ERR;
770 	}
771 #endif
772 	return hash_totp_and_pw(scheme, passwd, hash, text);
773 }
774 
hash_totp256andpw(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)775 static int hash_totp256andpw(
776 	const struct berval *scheme,
777 	const struct berval *passwd,
778 	struct berval *hash,
779 	const char **text)
780 {
781 #if 0
782 	if (passwd->bv_len != SHA256_DIGEST_LENGTH) {
783 		*text = "invalid key length";
784 		return LUTIL_PASSWD_ERR;
785 	}
786 #endif
787 	return hash_totp_and_pw(scheme, passwd, hash, text);
788 }
789 
hash_totp512andpw(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)790 static int hash_totp512andpw(
791 	const struct berval *scheme,
792 	const struct berval *passwd,
793 	struct berval *hash,
794 	const char **text)
795 {
796 #if 0
797 	if (passwd->bv_len != SHA512_DIGEST_LENGTH) {
798 		*text = "invalid key length";
799 		return LUTIL_PASSWD_ERR;
800 	}
801 #endif
802 	return hash_totp_and_pw(scheme, passwd, hash, text);
803 }
804 
totp_op_cleanup(Operation * op,SlapReply * rs)805 static int totp_op_cleanup(
806 	Operation *op,
807 	SlapReply *rs )
808 {
809 	slap_callback *cb;
810 
811 	/* clear out the current key */
812 	ldap_pvt_thread_pool_setkey( op->o_threadctx, totp_op_cleanup,
813 		NULL, 0, NULL, NULL );
814 
815 	/* free the callback */
816 	cb = op->o_callback;
817 	op->o_callback = cb->sc_next;
818 	if (cb->sc_private)
819 		ber_bvfree_x(cb->sc_private, op->o_tmpmemctx);
820 	op->o_tmpfree( cb, op->o_tmpmemctx );
821 	return 0;
822 }
823 
824 static int
totp_bind_response(Operation * op,SlapReply * rs)825 totp_bind_response( Operation *op, SlapReply *rs )
826 {
827 	Modifications *mod = NULL;
828 	BackendInfo *bi = op->o_bd->bd_info;
829 	Entry *e;
830 	int rc;
831 
832 	/* we're only interested if the bind was successful */
833 	if ( rs->sr_err != LDAP_SUCCESS )
834 		return SLAP_CB_CONTINUE;
835 
836 	rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
837 	op->o_bd->bd_info = bi;
838 
839 	if ( rc != LDAP_SUCCESS ) {
840 		return SLAP_CB_CONTINUE;
841 	}
842 
843 	{
844 		time_t now;
845 		Attribute *a;
846 		Modifications *m;
847 		char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ];
848 		struct berval timestamp;
849 
850 		/* get the current time */
851 		now = op->o_time;
852 
853 		/* update the authTimestamp in the user's entry with the current time */
854 		timestamp.bv_val = nowstr;
855 		timestamp.bv_len = sizeof(nowstr);
856 		slap_timestamp( &now, &timestamp );
857 
858 		m = ch_calloc( sizeof(Modifications), 1 );
859 		m->sml_op = LDAP_MOD_REPLACE;
860 		m->sml_flags = 0;
861 		m->sml_type = ad_authTimestamp->ad_cname;
862 		m->sml_desc = ad_authTimestamp;
863 		m->sml_numvals = 1;
864 		m->sml_values = ch_calloc( sizeof(struct berval), 2 );
865 		m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
866 
867 		ber_dupbv( &m->sml_values[0], &timestamp );
868 		ber_dupbv( &m->sml_nvalues[0], &timestamp );
869 		m->sml_next = mod;
870 		mod = m;
871 
872 		/* get authTimestamp attribute, if it exists */
873 		if ((a = attr_find( e->e_attrs, ad_authTimestamp)) != NULL && op->o_callback->sc_private) {
874 			struct berval *bv = op->o_callback->sc_private;
875 			m = ch_calloc( sizeof(Modifications), 1 );
876 			m->sml_op = LDAP_MOD_DELETE;
877 			m->sml_flags = 0;
878 			m->sml_type = ad_authTimestamp->ad_cname;
879 			m->sml_desc = ad_authTimestamp;
880 			m->sml_numvals = 1;
881 			m->sml_values = ch_calloc( sizeof(struct berval), 2 );
882 			m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
883 
884 			ber_dupbv( &m->sml_values[0], bv );
885 			ber_dupbv( &m->sml_nvalues[0], bv );
886 			m->sml_next = mod;
887 			mod = m;
888 		}
889 	}
890 
891 	be_entry_release_r( op, e );
892 
893 	/* perform the update */
894 	if ( mod ) {
895 		Operation op2 = *op;
896 		SlapReply r2 = { REP_RESULT };
897 		slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
898 
899 		/* This is a DSA-specific opattr, it never gets replicated. */
900 		op2.o_tag = LDAP_REQ_MODIFY;
901 		op2.o_callback = &cb;
902 		op2.orm_modlist = mod;
903 		op2.o_dn = op->o_bd->be_rootdn;
904 		op2.o_ndn = op->o_bd->be_rootndn;
905 		op2.o_dont_replicate = 1;
906 		rc = op->o_bd->be_modify( &op2, &r2 );
907 		slap_mods_free( mod, 1 );
908 		if (rc != LDAP_SUCCESS) {
909 			/* slapd has logged this as a success already, but we
910 			 * need to fail it because the authTimestamp changed
911 			 * out from under us.
912 			 */
913 			rs->sr_err = LDAP_INVALID_CREDENTIALS;
914 			connection2anonymous(op->o_conn);
915 			op2 = *op;
916 			op2.o_callback = NULL;
917 			send_ldap_result(&op2, rs);
918 			op->o_bd->bd_info = bi;
919 			return rs->sr_err;
920 		}
921 	}
922 
923 	op->o_bd->bd_info = bi;
924 	return SLAP_CB_CONTINUE;
925 }
926 
totp_op_bind(Operation * op,SlapReply * rs)927 static int totp_op_bind(
928 	Operation *op,
929 	SlapReply *rs )
930 {
931 	/* If this is a simple Bind, stash the Op pointer so our chk
932 	 * function can find it. Set a cleanup callback to clear it
933 	 * out when the Bind completes.
934 	 */
935 	if ( op->oq_bind.rb_method == LDAP_AUTH_SIMPLE ) {
936 		slap_callback *cb;
937 		ldap_pvt_thread_pool_setkey( op->o_threadctx,
938 			totp_op_cleanup, op, 0, NULL, NULL );
939 		cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
940 		cb->sc_response = totp_bind_response;
941 		cb->sc_cleanup = totp_op_cleanup;
942 		cb->sc_next = op->o_callback;
943 		op->o_callback = cb;
944 	}
945 	return SLAP_CB_CONTINUE;
946 }
947 
totp_db_open(BackendDB * be,ConfigReply * cr)948 static int totp_db_open(
949 	BackendDB *be,
950 	ConfigReply *cr
951 )
952 {
953 	int rc = 0;
954 
955 	if (!ad_authTimestamp) {
956 		const char *text = NULL;
957 		rc = slap_str2ad("authTimestamp", &ad_authTimestamp, &text);
958 		if (rc) {
959 			rc = register_at(totp_OpSchema[0].def, totp_OpSchema[0].ad, 0 );
960 			if (rc) {
961 				snprintf(cr->msg, sizeof(cr->msg), "unable to find or register authTimestamp attribute: %s (%d)",
962 					text, rc);
963 				Debug(LDAP_DEBUG_ANY, "totp: %s.\n", cr->msg );
964 			}
965 			ad_authTimestamp->ad_type->sat_flags |= SLAP_AT_MANAGEABLE;
966 		}
967 	}
968 	return rc;
969 }
970 
971 static slap_overinst totp;
972 
973 int
totp_initialize(void)974 totp_initialize(void)
975 {
976 	int rc;
977 
978 	totp.on_bi.bi_type = "totp";
979 
980 	totp.on_bi.bi_db_open = totp_db_open;
981 	totp.on_bi.bi_op_bind = totp_op_bind;
982 
983 	rc = lutil_passwd_add((struct berval *) &scheme_totp1, chk_totp1, hash_totp1);
984 	if (!rc)
985 		rc = lutil_passwd_add((struct berval *) &scheme_totp256, chk_totp256, hash_totp256);
986 	if (!rc)
987 		rc = lutil_passwd_add((struct berval *) &scheme_totp512, chk_totp512, hash_totp512);
988 	if (!rc)
989 		rc = lutil_passwd_add((struct berval *) &scheme_totp1andpw, chk_totp1andpw, hash_totp1andpw);
990 	if (!rc)
991 		rc = lutil_passwd_add((struct berval *) &scheme_totp256andpw, chk_totp256andpw, hash_totp256andpw);
992 	if (!rc)
993 		rc = lutil_passwd_add((struct berval *) &scheme_totp512andpw, chk_totp512andpw, hash_totp512andpw);
994 	if (rc)
995 		return rc;
996 
997 	return overlay_register(&totp);
998 }
999 
init_module(int argc,char * argv[])1000 int init_module(int argc, char *argv[]) {
1001 	return totp_initialize();
1002 }
1003