From 753721df82388d0c1dc7f97dc97d35f5595fc83e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Wed, 12 Nov 2014 17:30:38 +0000 Subject: [PATCH] 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 --- bin/oathkey/oathkey.1 | 5 ++++ bin/oathkey/oathkey.c | 64 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/bin/oathkey/oathkey.1 b/bin/oathkey/oathkey.1 index 55a594b..d05d302 100644 --- a/bin/oathkey/oathkey.1 +++ b/bin/oathkey/oathkey.1 @@ -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 diff --git a/bin/oathkey/oathkey.c b/bin/oathkey/oathkey.c index a413fc7..5506896 100644 --- a/bin/oathkey/oathkey.c +++ b/bin/oathkey/oathkey.c @@ -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 \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)