3
* $Id: otp_cardops.c,v 1.62.2.1 2005/12/08 01:30:50 fcusack Exp $
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: otp_cardops.c,v 1.62.2.1 2005/12/08 01:30:50 fcusack Exp $";
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 ((chal_len = otp_challenge_transform(username,
233
challenge, opt->chal_len)) < 0) {
234
otp_log(OTP_LOG_ERR, "%s: %s: challenge transform failed for [%s]",
235
log_prefix, __func__, username);
236
rc = OTP_RC_SERVICE_ERR;
237
goto auth_done_service_err;
238
/* NB: state not updated. */
241
/* Calculate the async response. */
242
if (card_info.cardops->response(&card_info, challenge, chal_len,
243
&e_response[pin_offset],
246
"%s: %s: unable to calculate async response for [%s], "
247
"to challenge %s", log_prefix, __func__, username, challenge);
248
rc = OTP_RC_SERVICE_ERR;
249
goto auth_done_service_err;
250
/* NB: state not updated. */
253
/* NOTE: We do not display the PIN. */
255
char s[OTP_MAX_CHALLENGE_LEN * 2 + 1];
257
otp_log(OTP_LOG_DEBUG,
258
"%s: %s: [%s], async challenge %s, expecting response %s",
259
log_prefix, __func__, username,
260
card_info.cardops->printchallenge(s, challenge, chal_len),
261
&e_response[pin_offset]);
264
/* Add PIN if needed. */
265
if (!opt->prepend_pin)
266
(void) strcat(e_response, card_info.pin);
268
/* Test user-supplied passcode. */
270
nmatch = strcmp(passcode, e_response);
272
nmatch = cmpfunc(data, e_response, log_prefix);
274
if (!opt->allow_async) {
275
otp_log(OTP_LOG_AUTH, "%s: %s: bad async auth for [%s]: "
276
"valid but disallowed by config",
277
log_prefix, __func__, username);
278
rc = OTP_RC_AUTH_ERR;
281
if (fc == OTP_FC_FAIL_HARD) {
282
otp_log(OTP_LOG_AUTH,
283
"%s: %s: bad async auth for [%s]: valid but in hardfail "
284
" (%d/%d failed/max)", log_prefix, __func__, username,
285
user_state.failcount, opt->hardfail);
286
rc = OTP_RC_MAXTRIES;
289
if (fc == OTP_FC_FAIL_SOFT) {
290
otp_log(OTP_LOG_AUTH,
291
"%s: %s: bad async auth for [%s]: valid but in softfail "
292
" (%d/%d failed/max)", log_prefix, __func__, username,
293
user_state.failcount, opt->softfail);
294
rc = OTP_RC_MAXTRIES;
298
if ((uint32_t) now - user_state.authtime < (unsigned) opt->chal_delay) {
299
otp_log(OTP_LOG_AUTH,
300
"%s: %s: bad async auth for [%s]: valid but too soon",
301
log_prefix, __func__, username);
302
rc = OTP_RC_MAXTRIES;
307
/* Authenticated in async mode. */
309
/* special log message for sync users */
310
if (card_info.featuremask & OTP_CF_SM)
311
otp_log(OTP_LOG_INFO, "%s: %s: [%s] authenticated in async mode",
312
log_prefix, __func__, username);
314
} /* if (user authenticated async) */
315
} /* if (async mode possible) */
319
* Calculate and test sync responses in the window. Note that we
320
* always accept a sync response, even if a challenge or resync was
321
* explicitly requested.
323
* Note that we always start at the t=0 e=0 window position, even
324
* though we may already know a previous authentication is further
325
* ahead in the window (when in softfail). This has the effect that
326
* an rwindow softfail override can occur in a sequence like 6,3,4.
327
* That is, the user can always move backwards in the window to
328
* restart the rwindow sequence, as long as they don't go beyond
329
* (prior to) the last successful authentication.
331
if ((card_info.featuremask & OTP_CF_SM) && opt->allow_sync) {
332
int tend, end, ewindow, rwindow;
334
/* set ending ewin counter */
335
if (card_info.featuremask & OTP_CF_FRW) {
336
/* force rwindow for e+t cards */
337
rwindow = (card_info.featuremask & OTP_CF_FRW) >> OTP_CF_FRW_SHIFT;
338
ewindow = 0; /* quiet compiler */
340
ewindow = opt->ewindow_size;
341
/* Increase window for softfail+rwindow. */
342
if (opt->rwindow_size && fc == OTP_FC_FAIL_SOFT)
343
rwindow = opt->rwindow_size;
347
end = rwindow ? rwindow : ewindow;
349
/* Setup initial challenge. */
350
(void) memcpy(challenge, user_state.challenge, user_state.clen);
352
/* Test each sync response in the window. */
353
tend = card_info.cardops->maxtwin(&card_info, user_state.csd);
354
for (t = 0; t <= tend; ++t) {
355
for (e = 0; e <= end; ++e) {
356
/* Get next challenge. */
357
rc = card_info.cardops->challenge(&card_info, &user_state, challenge,
358
now, t, e, log_prefix);
361
"%s: %s: unable to get sync challenge t:%d e:%d for [%s]",
362
log_prefix, __func__, t, e, username);
363
rc = OTP_RC_SERVICE_ERR;
364
goto auth_done_service_err;
365
/* NB: state not updated. */
366
} else if (rc == -2) {
368
* For event synchronous modes, we can never go backwards (the
369
* challenge() method can only walk forward on the event counter),
370
* so there is an implicit guarantee that we'll never get a
371
* response matching an event in the past.
373
* But for time synchronous modes, challenge() can walk backwards,
374
* in order to accomodate clock drift. We must never allow a
375
* successful auth for a correct passcode earlier in time than
376
* one already used successfully, so we skip out early here.
379
otp_log(OTP_LOG_DEBUG,
380
"%s: %s: [%s], sync challenge t:%d e:%d is early",
381
log_prefix, __func__, username, t, e);
385
/* Calculate sync response. */
386
if (card_info.cardops->response(&card_info, challenge, user_state.clen,
387
&e_response[pin_offset],
390
"%s: %s: unable to calculate sync response "
391
"t:%d e:%d for [%s], to challenge %s",
392
log_prefix, __func__, t, e, username, challenge);
393
rc = OTP_RC_SERVICE_ERR;
394
goto auth_done_service_err;
395
/* NB: state not updated. */
398
/* NOTE: We do not display the PIN. */
400
char s[OTP_MAX_CHALLENGE_LEN * 2 + 1];
402
otp_log(OTP_LOG_DEBUG, "%s: %s: [%s], sync challenge t:%d e:%d %s, "
403
"expecting response %s",
404
log_prefix, __func__, username, t, e,
405
card_info.cardops->printchallenge(s, challenge,
407
&e_response[pin_offset]);
410
/* Add PIN if needed. */
411
if (!opt->prepend_pin)
412
(void) strcat(e_response, card_info.pin);
414
/* Test user-supplied passcode. */
416
nmatch = strcmp(passcode, e_response);
418
nmatch = cmpfunc(data, e_response, log_prefix);
420
if (fc == OTP_FC_FAIL_HARD) {
421
otp_log(OTP_LOG_AUTH,
422
"%s: %s: bad sync auth for [%s]: valid but in hardfail "
423
" (%d/%d failed/max)", log_prefix, __func__, username,
424
user_state.failcount, opt->hardfail);
425
rc = OTP_RC_MAXTRIES;
426
} else if (fc == OTP_FC_FAIL_SOFT) {
431
/* rwindow mode not configured */
432
otp_log(OTP_LOG_AUTH,
433
"%s: %s: bad sync auth for [%s]: valid but in softfail "
434
" (%d/%d failed/max)", log_prefix, __func__, username,
435
user_state.failcount, opt->softfail);
436
rc = OTP_RC_MAXTRIES;
441
* User must enter two consecutive correct sync passcodes
442
* for rwindow softfail override.
444
if (card_info.cardops->isconsecutive(&card_info, &user_state,
447
* This is the 2nd of two consecutive responses, is it
448
* soon enough? Note that for persistent softfail we can't
449
* enforce rwindow_delay b/c the previous authtime is also
450
* the persistent softfail sentinel.
452
if (user_state.authtime == INT32_MAX ||
453
now - user_state.authtime < (unsigned) opt->rwindow_delay) {
454
otp_log(OTP_LOG_AUTH,
455
"%s: %s: rwindow softfail override for [%s] at "
456
"window position t:%d e:%d", log_prefix, __func__,
461
/* consecutive but not soon enough */
462
otp_log(OTP_LOG_AUTH,
463
"%s: %s: late override for [%s] at "
464
"window position t:%d e:%d", log_prefix, __func__,
466
rc = OTP_RC_AUTH_ERR;
468
} /* if (passcode is consecutive */
470
/* passcode correct, but not consecutive or not soon enough */
472
otp_log(OTP_LOG_DEBUG,
473
"%s: %s: [%s] rwindow candidate "
474
"at window position t:%d e:%d", log_prefix, __func__,
476
rc = OTP_RC_AUTH_ERR;
479
/* normal sync mode auth */
481
} /* else (!hardfail && !softfail) */
484
/* force resync; this only has an effect if (rc == OTP_RC_OK) */
486
/* update csd (et al.) on successful auth or rwindow candidate */
487
if (card_info.cardops->updatecsd(&user_state, now, t, e, rc) != 0) {
488
otp_log(OTP_LOG_ERR, "%s: %s: unable to update csd for [%s]",
489
log_prefix, __func__, username);
490
rc = OTP_RC_SERVICE_ERR;
491
goto auth_done_service_err;
492
/* NB: state not updated. */
496
} /* if (passcode is valid) */
497
} /* for (each slot in the ewindow) */
498
} /* for (each slot in the twindow) */
499
} /* if (sync mode possible) */
501
/* Both async and sync mode failed. */
502
rc = OTP_RC_AUTH_ERR;
505
if (rc == OTP_RC_OK) {
507
(void) memcpy(user_state.challenge, challenge, user_state.clen);
508
user_state.failcount = 0;
509
user_state.authtime = now;
511
if (++user_state.failcount == UINT_MAX)
512
user_state.failcount--;
513
/* authtime set to INT32_MAX by nullstate(); leave it to force softfail */
514
if (user_state.authtime != INT32_MAX)
515
user_state.authtime = (int32_t) now; /* cast prevents overflow */
517
* Note that we don't update the challenge. Even for softfail (where
518
* we might have actually had a good auth), we want the challenge
519
* unchanged because we always start our sync loop at e=0 t=0 (and so
520
* challenge must stay as the 0'th challenge regardless of next valid
521
* window position, because the challenge() method can't return
522
* arbitrary event window positions--since we start at e=0 the challenge
523
* must be the 0th challenge, i.e. unchanged).
525
} /* else (rc != OTP_RC_OK) */
526
user_state.updated = 1;
528
auth_done_service_err: /* exit here for system errors */
530
* Release and update state.
532
* We "fail-out" if we can't do this, because for sync mode the
533
* response can be reused until state data is updated, an obvious
536
* For async mode with RADIUS, if we can't update the last auth
537
* time, we will be open to a less obvious replay attack over the
538
* lifetime of the State attribute (opt->chal_delay): if someone
539
* that can see RADIUS traffic captures an Access-Request containing
540
* a State attribute, and can cause the NAS to cycle the request id
541
* within opt->chal_delay secs, then they can login to the NAS and
542
* insert the captured State attribute into the new Access-Request,
543
* and we'll give an Access-Accept.
545
if (user_state.locked) {
546
if (otp_state_put(username, &user_state, log_prefix) != 0) {
547
otp_log(OTP_LOG_ERR, "%s: %s: unable to put state for [%s]",
548
log_prefix, __func__, username);
549
rc = OTP_RC_SERVICE_ERR; /* no matter what it might have been */