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$
.\"
.Dd December 11, 2014
.Dd December 15, 2014
.Dt OATHKEY 1
.Os
.Sh NAME
@ -70,8 +70,11 @@ This is the default.
.Pp
The commands are:
.Bl -tag -width 6n
.It Cm calc
.It Cm calc Op Ar count
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
reuse.
.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
keyfile is updated to prevent reuse.
.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
.Xr oath_hotp 3 ,
.Xr oath_key 3 ,

View File

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