Implement HOTP resynchronization: the user provides two consecutive codes

from their token.  If the first code is found within the synchronization
window (currently hardcoded to 99) and the second is the next code in the
sequence, the counter is reset to one past the second code.


git-svn-id: svn+ssh://svn.openpam.org/svn/openpam/trunk@842 185d5e19-27fe-0310-9dcf-9bff6b9f3609
This commit is contained in:
Dag-Erling Smørgrav 2014-11-12 17:30:38 +00:00
parent d130c0ec09
commit 753721df82
2 changed files with 65 additions and 4 deletions

View File

@ -82,6 +82,11 @@ printed to standard output.
Print the user's key.
.It Cm geturi
Print the user's key in otpauth URI form.
.It Cm resync Ar code1 Ar code2
Resynchronize an event-mode token that has moved too far ahead of the
validation server.
The codes provided must be two consecutive codes within the
resynchronization window.
.It Cm setkey Ar uri
Set the user's key to the given otpauth URI.
.It Cm uri

View File

@ -236,7 +236,7 @@ static int
oathkey_verify(int argc, char *argv[])
{
struct oath_key *key;
unsigned long response;
unsigned long counter, response;
char *end;
int match, ret;
@ -247,12 +247,19 @@ oathkey_verify(int argc, char *argv[])
response = strtoul(*argv, &end, 10);
if (end == *argv || *end != '\0')
response = ULONG_MAX; /* never valid */
if (key->mode == om_totp)
switch (key->mode) {
case om_totp:
match = oath_totp_match(key, response, 3 /* XXX window */);
else if (key->mode == om_hotp)
break;
case om_hotp:
counter = key->counter;
match = oath_hotp_match(key, response, 17 /* XXX window */);
else
if (verbose && match > 0 && key->counter > counter + 1)
warnx("skipped %lu codes", key->counter - counter - 1);
break;
default:
match = -1;
}
/* oath_*_match() return -1 on error, 0 on failure, 1 on success */
if (match < 0) {
warnx("OATH error");
@ -298,6 +305,52 @@ oathkey_calc(int argc, char *argv[])
return (ret);
}
/*
* Resynchronize
*/
static int
oathkey_resync(int argc, char *argv[])
{
struct oath_key *key;
unsigned long counter, response[2];
char *end;
int i, match, ret;
if (argc != 2)
return (RET_USAGE);
for (i = 0; i < argc; ++i) {
response[i] = strtoul(argv[i], &end, 10);
if (end == argv[i] || *end != '\0')
response[i] = ULONG_MAX; /* never valid */
}
if ((ret = oathkey_load(&key)) != RET_SUCCESS)
return (ret);
switch (key->mode) {
case om_hotp:
counter = key->counter;
match = oath_hotp_match(key, response[0], 99 /* XXX window */);
if (match > 0)
match = oath_hotp_match(key, response[1], 1);
if (verbose && match > 0)
warnx("skipped %lu codes", key->counter - counter - 1);
break;
case om_totp:
match = 1;
break;
default:
match = -1;
}
if (match < 0) {
warnx("OATH error");
match = 0;
}
if (verbose)
warnx("resynchronization %s", match ? "succeeded" : "failed");
ret = match ? readonly ? RET_SUCCESS : oathkey_save(key) : RET_FAILURE;
oath_key_free(key);
return (ret);
}
/*
* Print usage string and exit.
*/
@ -312,6 +365,7 @@ usage(void)
" genkey Generate a new key\n"
" getkey Print the key in hexadecimal form\n"
" geturi Print the key in otpauth URI form\n"
" resync Resynchronize an HOTP token\n"
" setkey Generate a new key\n"
" verify <response>\n"
" Verify a response\n");
@ -408,6 +462,8 @@ main(int argc, char *argv[])
ret = oathkey_getkey(argc, argv);
else if (strcmp(cmd, "geturi") == 0 || strcmp(cmd, "uri") == 0)
ret = oathkey_geturi(argc, argv);
else if (strcmp(cmd, "resync") == 0)
ret = oathkey_resync(argc, argv);
else if (strcmp(cmd, "setkey") == 0)
ret = oathkey_setkey(argc, argv);
else if (strcmp(cmd, "verify") == 0)