Track liboath:

- Use UINT_MAX to indicate an invalid response.
  - The meaning of the window parameter has changed slightly.
The calc command now accepts a count of codes to generate.
The resync command now fails if the key is not resynchronizable.
Clean up the usage message.
Document exit codes.


git-svn-id: svn+ssh://svn.openpam.org/svn/openpam/trunk@850 185d5e19-27fe-0310-9dcf-9bff6b9f3609
This commit is contained in:
Dag-Erling Smørgrav 2014-12-15 17:00:59 +00:00
parent cec8549503
commit 1cffa76b4f
2 changed files with 79 additions and 36 deletions

View File

@ -28,7 +28,7 @@
.\" .\"
.\" $Id$ .\" $Id$
.\" .\"
.Dd December 11, 2014 .Dd December 15, 2014
.Dt OATHKEY 1 .Dt OATHKEY 1
.Os .Os
.Sh NAME .Sh NAME
@ -70,8 +70,11 @@ This is the default.
.Pp .Pp
The commands are: The commands are:
.Bl -tag -width 6n .Bl -tag -width 6n
.It Cm calc .It Cm calc Op Ar count
Compute and display the current code for the given key. Compute and display the current code for the given key.
If a count is specified, compute and display
.Ar count
additional codes.
If writeback mode is enabled, the user's keyfile is updated to prevent If writeback mode is enabled, the user's keyfile is updated to prevent
reuse. reuse.
.It Cm genkey Ar hotp | totp .It Cm genkey Ar hotp | totp
@ -100,6 +103,19 @@ user's key.
If writeback mode is enabled and the response matched, the user's If writeback mode is enabled and the response matched, the user's
keyfile is updated to prevent reuse. keyfile is updated to prevent reuse.
.El .El
.Sh EXIT STATUS
The
.Cm verify
command exits 0 if the code is valid, 1 if it is invalid and >1 if an
error occurred.
.Pp
The
.Cm resync
command exits 0 if resynchronization was successful, 1 if it failed or
the specified key does not support resynchronization, and >1 if an
error occurred.
.Pp
All other commands exit 0 if successful and >1 if an error occurred.
.Sh SEE ALSO .Sh SEE ALSO
.Xr oath_hotp 3 , .Xr oath_hotp 3 ,
.Xr oath_key 3 , .Xr oath_key 3 ,

View File

@ -50,6 +50,10 @@
#include <security/oath.h> #include <security/oath.h>
/* XXX hardcoded windows */
#define HOTP_WINDOW 9
#define TOTP_WINDOW 1
enum { RET_SUCCESS, RET_FAILURE, RET_ERROR, RET_USAGE, RET_UNAUTH }; enum { RET_SUCCESS, RET_FAILURE, RET_ERROR, RET_USAGE, RET_UNAUTH };
static char *user; static char *user;
@ -237,7 +241,8 @@ static int
oathkey_verify(int argc, char *argv[]) oathkey_verify(int argc, char *argv[])
{ {
struct oath_key *key; struct oath_key *key;
unsigned long counter, response; unsigned long counter;
unsigned int response;
char *end; char *end;
int match, ret; int match, ret;
@ -247,17 +252,17 @@ oathkey_verify(int argc, char *argv[])
return (ret); return (ret);
response = strtoul(*argv, &end, 10); response = strtoul(*argv, &end, 10);
if (end == *argv || *end != '\0') if (end == *argv || *end != '\0')
response = ULONG_MAX; /* never valid */ response = UINT_MAX; /* never valid */
switch (key->mode) { switch (key->mode) {
case om_totp:
match = oath_totp_match(key, response, 3 /* XXX window */);
break;
case om_hotp: case om_hotp:
counter = key->counter; counter = key->counter;
match = oath_hotp_match(key, response, 17 /* XXX window */); match = oath_hotp_match(key, response, HOTP_WINDOW);
if (verbose && match > 0 && key->counter > counter + 1) if (verbose && match > 0 && key->counter > counter + 1)
warnx("skipped %lu codes", key->counter - counter - 1); warnx("skipped %lu codes", key->counter - counter - 1);
break; break;
case om_totp:
match = oath_totp_match(key, response, TOTP_WINDOW);
break;
default: default:
match = -1; match = -1;
} }
@ -267,7 +272,7 @@ oathkey_verify(int argc, char *argv[])
match = 0; match = 0;
} }
if (verbose) if (verbose)
warnx("response: %lu %s", response, warnx("response: %u %s", response,
match ? "matched" : "did not match"); match ? "matched" : "did not match");
ret = match ? readonly ? RET_SUCCESS : oathkey_save(key) : RET_FAILURE; ret = match ? readonly ? RET_SUCCESS : oathkey_save(key) : RET_FAILURE;
oath_key_free(key); oath_key_free(key);
@ -282,26 +287,41 @@ oathkey_calc(int argc, char *argv[])
{ {
struct oath_key *key; struct oath_key *key;
unsigned int current; unsigned int current;
unsigned long i, n;
char *end;
int ret; int ret;
if (argc != 0) if (argc > 1)
return (RET_USAGE); return (RET_USAGE);
(void)argv; if (argc > 0) {
n = strtoul(argv[0], &end, 10);
if (end == argv[0] || *end != '\0')
return (RET_USAGE);
} else {
n = 0;
}
if ((ret = oathkey_load(&key)) != RET_SUCCESS) if ((ret = oathkey_load(&key)) != RET_SUCCESS)
return (ret); return (ret);
if (key->mode == om_totp) for (i = 0; i <= n; ++i) {
current = oath_totp_current(key); switch (key->mode) {
else if (key->mode == om_hotp) case om_hotp:
current = oath_hotp_current(key); current = oath_hotp_current(key);
else break;
current = -1; case om_totp:
if (current == (unsigned int)-1) { current = oath_totp_current(key);
warnx("OATH error"); break;
ret = RET_ERROR; default:
} else { current = UINT_MAX;
}
if (current == UINT_MAX) {
warnx("OATH error");
ret = RET_ERROR;
break;
}
printf("%.*d\n", (int)key->digits, current); printf("%.*d\n", (int)key->digits, current);
ret = readonly ? RET_SUCCESS : oathkey_save(key);
} }
if (ret == RET_SUCCESS && !readonly)
ret = oathkey_save(key);
oath_key_free(key); oath_key_free(key);
return (ret); return (ret);
} }
@ -313,7 +333,8 @@ static int
oathkey_resync(int argc, char *argv[]) oathkey_resync(int argc, char *argv[])
{ {
struct oath_key *key; struct oath_key *key;
unsigned long counter, response[3]; unsigned long counter;
unsigned int response[3];
char *end; char *end;
int i, match, n, ret, w; int i, match, n, ret, w;
@ -323,23 +344,28 @@ oathkey_resync(int argc, char *argv[])
for (i = 0, w = 1; i < n; ++i) { for (i = 0, w = 1; i < n; ++i) {
response[i] = strtoul(argv[i], &end, 10); response[i] = strtoul(argv[i], &end, 10);
if (end == argv[i] || *end != '\0') if (end == argv[i] || *end != '\0')
response[i] = ULONG_MAX; /* never valid */ response[i] = UINT_MAX; /* never valid */
w = w * 10; w = w * (HOTP_WINDOW + 1);
} }
w -= n;
if ((ret = oathkey_load(&key)) != RET_SUCCESS) if ((ret = oathkey_load(&key)) != RET_SUCCESS)
return (ret); return (ret);
switch (key->mode) { switch (key->mode) {
case om_hotp: case om_hotp:
/* this should be a library function */
counter = key->counter; counter = key->counter;
match = oath_hotp_match(key, response[0], w); while (key->counter < counter + w) {
for (i = 1; i < n && match > 0; ++i) match = oath_hotp_match(key, response[0],
match = oath_hotp_match(key, response[i], 1); counter + w - key->counter - 1);
warnx("%d", match);
if (match <= 0)
break;
for (i = 1; i < n && match > 0; ++i)
match = oath_hotp_match(key, response[i], 0);
}
if (verbose && match > 0) if (verbose && match > 0)
warnx("skipped %lu codes", key->counter - counter - 1); warnx("skipped %lu codes", key->counter - counter - 1);
break; break;
case om_totp:
match = 1;
break;
default: default:
match = -1; match = -1;
} }
@ -361,18 +387,19 @@ static void
usage(void) usage(void)
{ {
fprintf(stderr, fprintf(stderr,
"usage: oathkey [-hrvw] [-u user] [-k keyfile] <command>\n" "usage: oathkey [-hrvw] [-u user] [-k keyfile] command\n"
"\n" "\n"
"Commands:\n" "Commands:\n"
" calc Print the current code\n" " calc [count]\n"
" genkey <mode>\n" " Print the next code(s)\n"
" genkey hotp | totp\n"
" Generate a new key\n" " Generate a new key\n"
" getkey Print the key in hexadecimal form\n" " getkey Print the key in hexadecimal form\n"
" geturi Print the key in otpauth URI form\n" " geturi Print the key in otpauth URI form\n"
" resync <code1> <code2> [<code3>]\n" " resync code1 code2 [code3]\n"
" Resynchronize an HOTP token\n" " Resynchronize an HOTP token\n"
" setkey Generate a new key\n" " setkey Generate a new key\n"
" verify <code>\n" " verify code\n"
" Verify an HOTP or TOTP code\n"); " Verify an HOTP or TOTP code\n");
exit(1); exit(1);
} }