5 * Passcode verification functions for otp.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Copyright 2002-2005 Google, Inc.
23 * Copyright 2005 TRI-D Systems, Inc.
26 static const char rcsid[] = "$Id$";
28 #if defined(__linux__) && !defined(_GNU_SOURCE)
29 #define _GNU_SOURCE /* RTLD_DEFAULT */
39 #include "otp_cardops.h"
42 cardops_t otp_cardops[OTP_MAX_VENDORS]; /* cardops objects */
43 int otp_num_cardops = 0; /* number of cardops modules loaded */
47 * Test for passcode validity.
49 * If challenge is supplied, it is used to generate the card response
50 * against which the passcode will be compared. If challenge is not
51 * supplied, or if the comparison fails, synchronous responses are
52 * generated and tested. NOTE: for async authentications, sync mode
53 * responses are still considered valid! (Assuming module configuration
56 * If passcode is supplied, a simple string comparison is done, else if
57 * cmp is supplied, it is called to test for validity. The cmp function
58 * is required for RADIUS, where we might have a CHAP response instead
59 * of the plaintext of the passcode from the user.
61 * If challenge is supplied, then resync is used to determine if the card
62 * should be resynced or if this is a one-off response. (If challenge is
63 * not supplied, this is sync mode response and the card is always resynced.)
65 * Returns one of the OTP_RC_* return codes. challenge is overwritten.
68 otp_pw_valid(const char *username, char *challenge, const char *passcode,
69 int resync, const otp_option_t *opt,
70 cmpfunc_t cmpfunc, void *data,
71 const char *log_prefix)
74 int e = 0, t = 0; /* must initialize for async auth path */
75 int fc; /* failcondition */
77 /* expected response */
78 char e_response[OTP_MAX_RESPONSE_LEN + OTP_MAX_PIN_LEN + 1];
79 int pin_offset = 0; /* pin offset in e_response (prepend or append) */
81 otp_card_info_t card_info = { .cardops = NULL };
82 otp_user_state_t user_state = { .locked = 0 };
84 time_t now = time(NULL);
87 * In the Cyclades ACS environment (2.3.0 tested), the runtime linker
88 * apparently does not run static constructors in ELF .ctors sections.
89 * Since that is how we initialize cardops modules, we have an ugly
90 * workaround here. Our other choice is to implement cardops modules
91 * as full-fledged shared libraries, which is just too much work.
93 if (otp_num_cardops == 0) {
94 void (*cardops_init)(void);
96 /* ctors did not run; execute all known constructors */
97 if ((cardops_init = dlsym(RTLD_DEFAULT, "cryptocard_init")))
99 if ((cardops_init = dlsym(RTLD_DEFAULT, "trid_init")))
105 rc = OTP_RC_SERVICE_ERR;
106 goto auth_done_service_err;
108 if (!passcode && !cmpfunc) {
109 otp_log(OTP_LOG_CRIT, "%s: %s: Can't test passcode validity!",
110 log_prefix, __func__);
111 rc = OTP_RC_SERVICE_ERR;
112 goto auth_done_service_err;
115 /* Look up user info. (errors are logged by the function) */
116 rc = otp_get_card_info(opt->pwdfile, username, &card_info, log_prefix);
118 rc = OTP_RC_USER_UNKNOWN;
119 goto auth_done_service_err;
120 } else if (rc == -2) {
121 rc = OTP_RC_AUTHINFO_UNAVAIL;
122 goto auth_done_service_err;
124 card_info.username = username;
126 /* Find the correct cardops module. */
127 for (i = 0; otp_cardops[i].prefix; i++) {
128 if (!strncasecmp(otp_cardops[i].prefix, card_info.card,
129 otp_cardops[i].prefix_len)) {
130 card_info.cardops = &otp_cardops[i];
134 if (!card_info.cardops) {
135 otp_log(OTP_LOG_ERR, "%s: %s: invalid card type '%s' for [%s]",
136 log_prefix, __func__, card_info.card, username);
137 rc = OTP_RC_SERVICE_ERR;
138 goto auth_done_service_err;
141 /* Convert name to a feature mask once, for fast operations later. */
142 if (card_info.cardops->name2fm(card_info.card, &card_info.featuremask)) {
143 otp_log(OTP_LOG_ERR, "%s: %s: invalid card type '%s' for [%s]",
144 log_prefix, __func__, card_info.card, username);
145 rc = OTP_RC_SERVICE_ERR;
146 goto auth_done_service_err;
149 /* Convert keystring to a keyblock. */
150 if (card_info.cardops->keystring2keyblock(card_info.keystring,
151 card_info.keyblock) < 0) {
152 otp_log(OTP_LOG_ERR, "%s: %s: invalid key '%s' for [%s]",
153 log_prefix, __func__, card_info.keystring, username);
154 rc = OTP_RC_SERVICE_ERR;
155 goto auth_done_service_err;
158 /* Adjust e_response for PIN prepend. */
159 if (opt->prepend_pin) {
160 (void) strcpy(e_response, card_info.pin);
161 pin_offset = strlen(e_response);
164 /* Get user state. */
165 if (otp_state_get(opt, username, &user_state, log_prefix) != 0) {
166 otp_log(OTP_LOG_ERR, "%s: %s: unable to get state for [%s]",
167 log_prefix, __func__, username);
168 rc = OTP_RC_SERVICE_ERR;
169 goto auth_done_service_err;
171 if (user_state.nullstate) {
172 if (card_info.cardops->nullstate(opt, &card_info, &user_state,
174 otp_log(OTP_LOG_ERR, "%s: %s: unable to set null state for [%s]",
175 log_prefix, __func__, username);
176 rc = OTP_RC_SERVICE_ERR;
177 goto auth_done_service_err;
181 /* Set fc (failcondition). */
182 if (opt->hardfail && user_state.failcount >= (unsigned) opt->hardfail) {
183 /* NOTE: persistent softfail stops working */
184 fc = OTP_FC_FAIL_HARD;
185 } else if (opt->softfail && user_state.authtime == INT32_MAX) {
186 fc = OTP_FC_FAIL_SOFT;
187 } else if (opt->softfail &&
188 user_state.failcount >= (unsigned) opt->softfail) {
193 * Determine the next time this user can authenticate.
195 * Once we hit softfail, we introduce a 1m delay before the user
196 * can authenticate. For each successive failed authentication,
197 * we double the delay time, up to a max of 32 minutes. While in
198 * the "delay mode" of operation, all authentication ATTEMPTS are
199 * considered failures. Also, each attempt during the delay period
200 * restarts the clock.
202 * The advantage of a delay instead of a simple lockout is that an
203 * attacker can't lock out a user as easily; the user need only wait
204 * a bit before he can authenticate.
206 * Note that if the user waits for the delay period to expire, he
207 * is no longer in softfail and can only use ewindow, not rwindow.
209 fcount = user_state.failcount - opt->softfail;
211 * when and authtime are uint32, but time is saved as int32,
212 * so this can't overflow
214 when = user_state.authtime +
215 (fcount > 5 ? 32 * 60 : (1 << fcount) * 60);
216 if ((uint32_t) now < when)
217 fc = OTP_FC_FAIL_SOFT;
219 fc = OTP_FC_FAIL_NONE;
221 fc = OTP_FC_FAIL_NONE;
226 * Test async response.
228 if (*challenge && (card_info.featuremask & OTP_CF_AM) && opt->allow_async) {
231 /* Perform any site-specific transforms of the challenge. */
232 if (opt->site_transform) {
233 if ((chal_len = otp_challenge_transform(username,
234 challenge, opt->chal_len)) < 0) {
235 otp_log(OTP_LOG_ERR, "%s: %s: challenge transform failed for [%s]",
236 log_prefix, __func__, username);
237 rc = OTP_RC_SERVICE_ERR;
238 goto auth_done_service_err;
239 /* NB: state not updated. */
242 chal_len = opt->chal_len;
245 /* Calculate the async response. */
246 if (card_info.cardops->response(&card_info, challenge, chal_len,
247 &e_response[pin_offset],
250 "%s: %s: unable to calculate async response for [%s], "
251 "to challenge %s", log_prefix, __func__, username, challenge);
252 rc = OTP_RC_SERVICE_ERR;
253 goto auth_done_service_err;
254 /* NB: state not updated. */
257 /* NOTE: We do not display the PIN. */
259 char s[OTP_MAX_CHALLENGE_LEN * 2 + 1];
261 otp_log(OTP_LOG_DEBUG,
262 "%s: %s: [%s], async challenge %s, expecting response %s",
263 log_prefix, __func__, username,
264 card_info.cardops->printchallenge(s, challenge, chal_len),
265 &e_response[pin_offset]);
268 /* Add PIN if needed. */
269 if (!opt->prepend_pin)
270 (void) strcat(e_response, card_info.pin);
272 /* Test user-supplied passcode. */
274 nmatch = strcmp(passcode, e_response);
276 nmatch = cmpfunc(data, e_response, log_prefix);
278 if (!opt->allow_async) {
279 otp_log(OTP_LOG_AUTH, "%s: %s: bad async auth for [%s]: "
280 "valid but disallowed by config",
281 log_prefix, __func__, username);
282 rc = OTP_RC_AUTH_ERR;
285 if (fc == OTP_FC_FAIL_HARD) {
286 otp_log(OTP_LOG_AUTH,
287 "%s: %s: bad async auth for [%s]: valid but in hardfail "
288 " (%d/%d failed/max)", log_prefix, __func__, username,
289 user_state.failcount, opt->hardfail);
290 rc = OTP_RC_MAXTRIES;
293 if (fc == OTP_FC_FAIL_SOFT) {
294 otp_log(OTP_LOG_AUTH,
295 "%s: %s: bad async auth for [%s]: valid but in softfail "
296 " (%d/%d failed/max)", log_prefix, __func__, username,
297 user_state.failcount, opt->softfail);
298 rc = OTP_RC_MAXTRIES;
302 if ((uint32_t) now - user_state.authtime < (unsigned) opt->chal_delay) {
303 otp_log(OTP_LOG_AUTH,
304 "%s: %s: bad async auth for [%s]: valid but too soon",
305 log_prefix, __func__, username);
306 rc = OTP_RC_MAXTRIES;
311 /* Authenticated in async mode. */
313 /* special log message for sync users */
314 if (card_info.featuremask & OTP_CF_SM)
315 otp_log(OTP_LOG_INFO, "%s: %s: [%s] authenticated in async mode",
316 log_prefix, __func__, username);
318 } /* if (user authenticated async) */
319 } /* if (async mode possible) */
323 * Calculate and test sync responses in the window. Note that we
324 * always accept a sync response, even if a challenge or resync was
325 * explicitly requested.
327 * Note that we always start at the t=0 e=0 window position, even
328 * though we may already know a previous authentication is further
329 * ahead in the window (when in softfail). This has the effect that
330 * an rwindow softfail override can occur in a sequence like 6,3,4.
331 * That is, the user can always move backwards in the window to
332 * restart the rwindow sequence, as long as they don't go beyond
333 * (prior to) the last successful authentication.
335 if ((card_info.featuremask & OTP_CF_SM) && opt->allow_sync) {
336 int tend, end, ewindow, rwindow;
338 /* set ending ewin counter */
339 if (card_info.featuremask & OTP_CF_FRW) {
340 /* force rwindow for e+t cards */
341 rwindow = (card_info.featuremask & OTP_CF_FRW) >> OTP_CF_FRW_SHIFT;
342 ewindow = 0; /* quiet compiler */
344 ewindow = opt->ewindow_size;
345 /* Increase window for softfail+rwindow. */
346 if (opt->rwindow_size && fc == OTP_FC_FAIL_SOFT)
347 rwindow = opt->rwindow_size;
351 end = rwindow ? rwindow : ewindow;
353 /* Setup initial challenge. */
354 (void) memcpy(challenge, user_state.challenge, user_state.clen);
356 /* Test each sync response in the window. */
357 tend = card_info.cardops->maxtwin(&card_info, user_state.csd);
358 for (t = 0; t <= tend; ++t) {
359 for (e = 0; e <= end; ++e) {
360 /* Get next challenge. */
361 rc = card_info.cardops->challenge(&card_info, &user_state, challenge,
362 now, t, e, log_prefix);
365 "%s: %s: unable to get sync challenge t:%d e:%d for [%s]",
366 log_prefix, __func__, t, e, username);
367 rc = OTP_RC_SERVICE_ERR;
368 goto auth_done_service_err;
369 /* NB: state not updated. */
370 } else if (rc == -2) {
372 * For event synchronous modes, we can never go backwards (the
373 * challenge() method can only walk forward on the event counter),
374 * so there is an implicit guarantee that we'll never get a
375 * response matching an event in the past.
377 * But for time synchronous modes, challenge() can walk backwards,
378 * in order to accomodate clock drift. We must never allow a
379 * successful auth for a correct passcode earlier in time than
380 * one already used successfully, so we skip out early here.
383 otp_log(OTP_LOG_DEBUG,
384 "%s: %s: [%s], sync challenge t:%d e:%d is early",
385 log_prefix, __func__, username, t, e);
389 /* Calculate sync response. */
390 if (card_info.cardops->response(&card_info, challenge, user_state.clen,
391 &e_response[pin_offset],
394 "%s: %s: unable to calculate sync response "
395 "t:%d e:%d for [%s], to challenge %s",
396 log_prefix, __func__, t, e, username, challenge);
397 rc = OTP_RC_SERVICE_ERR;
398 goto auth_done_service_err;
399 /* NB: state not updated. */
402 /* NOTE: We do not display the PIN. */
404 char s[OTP_MAX_CHALLENGE_LEN * 2 + 1];
406 otp_log(OTP_LOG_DEBUG, "%s: %s: [%s], sync challenge t:%d e:%d %s, "
407 "expecting response %s",
408 log_prefix, __func__, username, t, e,
409 card_info.cardops->printchallenge(s, challenge,
411 &e_response[pin_offset]);
414 /* Add PIN if needed. */
415 if (!opt->prepend_pin)
416 (void) strcat(e_response, card_info.pin);
418 /* Test user-supplied passcode. */
420 nmatch = strcmp(passcode, e_response);
422 nmatch = cmpfunc(data, e_response, log_prefix);
424 if (fc == OTP_FC_FAIL_HARD) {
425 otp_log(OTP_LOG_AUTH,
426 "%s: %s: bad sync auth for [%s]: valid but in hardfail "
427 " (%d/%d failed/max)", log_prefix, __func__, username,
428 user_state.failcount, opt->hardfail);
429 rc = OTP_RC_MAXTRIES;
430 } else if (fc == OTP_FC_FAIL_SOFT) {
435 /* rwindow mode not configured */
436 otp_log(OTP_LOG_AUTH,
437 "%s: %s: bad sync auth for [%s]: valid but in softfail "
438 " (%d/%d failed/max)", log_prefix, __func__, username,
439 user_state.failcount, opt->softfail);
440 rc = OTP_RC_MAXTRIES;
445 * User must enter two consecutive correct sync passcodes
446 * for rwindow softfail override.
448 if (card_info.cardops->isconsecutive(&card_info, &user_state,
451 * This is the 2nd of two consecutive responses, is it
452 * soon enough? Note that for persistent softfail we can't
453 * enforce rwindow_delay b/c the previous authtime is also
454 * the persistent softfail sentinel.
456 if (user_state.authtime == INT32_MAX ||
457 now - user_state.authtime < (unsigned) opt->rwindow_delay) {
458 otp_log(OTP_LOG_AUTH,
459 "%s: %s: rwindow softfail override for [%s] at "
460 "window position t:%d e:%d", log_prefix, __func__,
465 /* consecutive but not soon enough */
466 otp_log(OTP_LOG_AUTH,
467 "%s: %s: late override for [%s] at "
468 "window position t:%d e:%d", log_prefix, __func__,
470 rc = OTP_RC_AUTH_ERR;
472 } /* if (passcode is consecutive */
474 /* passcode correct, but not consecutive or not soon enough */
476 otp_log(OTP_LOG_DEBUG,
477 "%s: %s: [%s] rwindow candidate "
478 "at window position t:%d e:%d", log_prefix, __func__,
480 rc = OTP_RC_AUTH_ERR;
483 /* normal sync mode auth */
485 } /* else (!hardfail && !softfail) */
488 /* force resync; this only has an effect if (rc == OTP_RC_OK) */
490 /* update csd (et al.) on successful auth or rwindow candidate */
491 if (card_info.cardops->updatecsd(&user_state, now, t, e, rc) != 0) {
492 otp_log(OTP_LOG_ERR, "%s: %s: unable to update csd for [%s]",
493 log_prefix, __func__, username);
494 rc = OTP_RC_SERVICE_ERR;
495 goto auth_done_service_err;
496 /* NB: state not updated. */
500 } /* if (passcode is valid) */
501 } /* for (each slot in the ewindow) */
502 } /* for (each slot in the twindow) */
503 } /* if (sync mode possible) */
505 /* Both async and sync mode failed. */
506 rc = OTP_RC_AUTH_ERR;
509 if (rc == OTP_RC_OK) {
511 (void) memcpy(user_state.challenge, challenge, user_state.clen);
512 user_state.failcount = 0;
513 user_state.authtime = now;
515 if (++user_state.failcount == UINT_MAX)
516 user_state.failcount--;
517 /* authtime set to INT32_MAX by nullstate(); leave it to force softfail */
518 if (user_state.authtime != INT32_MAX)
519 user_state.authtime = (int32_t) now; /* cast prevents overflow */
521 * Note that we don't update the challenge. Even for softfail (where
522 * we might have actually had a good auth), we want the challenge
523 * unchanged because we always start our sync loop at e=0 t=0 (and so
524 * challenge must stay as the 0'th challenge regardless of next valid
525 * window position, because the challenge() method can't return
526 * arbitrary event window positions--since we start at e=0 the challenge
527 * must be the 0th challenge, i.e. unchanged).
529 } /* else (rc != OTP_RC_OK) */
530 user_state.updated = 1;
532 auth_done_service_err: /* exit here for system errors */
534 * Release and update state.
536 * We "fail-out" if we can't do this, because for sync mode the
537 * response can be reused until state data is updated, an obvious
540 * For async mode with RADIUS, if we can't update the last auth
541 * time, we will be open to a less obvious replay attack over the
542 * lifetime of the State attribute (opt->chal_delay): if someone
543 * that can see RADIUS traffic captures an Access-Request containing
544 * a State attribute, and can cause the NAS to cycle the request id
545 * within opt->chal_delay secs, then they can login to the NAS and
546 * insert the captured State attribute into the new Access-Request,
547 * and we'll give an Access-Accept.
549 if (user_state.locked) {
550 if (otp_state_put(username, &user_state, log_prefix) != 0) {
551 otp_log(OTP_LOG_ERR, "%s: %s: unable to put state for [%s]",
552 log_prefix, __func__, username);
553 rc = OTP_RC_SERVICE_ERR; /* no matter what it might have been */