- Add a provisional API for computing the current HOTP or TOTP code.

- Add a provisional API for matching a user response.
- Add a provisional API for generating a dummy key.  When one of the
  matching functions recognizes a dummy key, it will go through the
  motions but never report a match.


git-svn-id: svn+ssh://svn.openpam.org/svn/openpam/trunk@643 185d5e19-27fe-0310-9dcf-9bff6b9f3609
This commit is contained in:
Dag-Erling Smørgrav 2013-03-05 15:24:00 +00:00
parent 2fe7fdd088
commit e39d0abb85
4 changed files with 130 additions and 7 deletions

View File

@ -101,7 +101,18 @@ struct oath_key *oath_key_from_uri(const char *);
struct oath_key *oath_key_from_file(const char *);
char *oath_key_to_uri(const struct oath_key *);
#define DUMMY_LABEL ("oath-dummy-key")
#define DUMMY_LABELLEN (sizeof DUMMY_LABEL)
#define DUMMY_KEYLEN 80
struct oath_key *oath_dummy_key(enum oath_mode, enum oath_hash, unsigned int);
unsigned int oath_hotp(const uint8_t *, size_t, uint64_t, unsigned int);
int oath_hotp_current(struct oath_key *);
int oath_hotp_match(struct oath_key *, unsigned int, int);
unsigned int oath_totp(const uint8_t *, size_t, unsigned int);
int oath_totp_match(const struct oath_key *, unsigned int, int);
unsigned int oath_totp_current(const struct oath_key *);
#endif

View File

@ -37,6 +37,7 @@
#include <openssl/hmac.h>
#include <stdint.h>
#include <string.h>
#include "oath.h"
@ -87,3 +88,52 @@ oath_hotp(const uint8_t *K, size_t Klen, uint64_t seq, unsigned int Digit)
D = Snum % mod;
return (D);
}
/*
* Computes the current code for the given key and advances the counter.
*/
int
oath_hotp_current(struct oath_key *k)
{
unsigned int code;
if (k == NULL)
return (-1);
if (k->mode != om_hotp)
return (-1);
if (k->counter == UINT64_MAX)
return (-1);
code = oath_hotp(k->key, k->keylen, k->counter, k->digits);
k->counter += 1;
return (code);
}
/*
* Compares the code provided by the user with expected values within a
* given window. Returns 1 if there was a match, 0 if not, and -1 if an
* error occurred.
*/
int
oath_hotp_match(struct oath_key *k, unsigned int response, int window)
{
unsigned int code;
int dummy;
if (k == NULL)
return (-1);
if (window < 1)
return (-1);
if (k->mode != om_hotp)
return (-1);
if (k->counter >= UINT64_MAX - window)
return (-1);
dummy = (memcmp(k->label, DUMMY_LABEL, DUMMY_LABELLEN) == 0);
for (int i = 0; i < window; ++i) {
code = oath_hotp(k->key, k->keylen, k->counter + i, k->digits);
if (code == response && !dummy) {
k->counter = k->counter + i;
return (1);
}
}
return (0);
}

View File

@ -112,10 +112,8 @@ oath_key_from_uri(const char *uri)
if ((q = strchr(p, '/')) == NULL)
goto invalid;
if (strlcmp("hotp", p, q - p) == 0) {
openpam_log(PAM_LOG_DEBUG, "OATH mode: HOTP");
key->mode = om_hotp;
} else if (strlcmp("totp", p, q - p) == 0) {
openpam_log(PAM_LOG_DEBUG, "OATH mode: TOTP");
key->mode = om_totp;
} else {
goto invalid;
@ -132,7 +130,7 @@ oath_key_from_uri(const char *uri)
p = q + 1;
/* extract parameters */
key->counter = UINTMAX_MAX;
key->counter = UINT64_MAX;
while (*p != '\0') {
if ((q = strchr(p, '=')) == NULL)
goto invalid;
@ -152,6 +150,7 @@ oath_key_from_uri(const char *uri)
base32_declen(r - q) > OATH_MAX_KEYLEN)
goto invalid;
key->key = key->data + key->labellen;
key->keylen = key->datalen - key->labellen;
if (base32_dec(q, r - q, key->key, &key->keylen) != 0)
goto invalid;
if (base32_enclen(key->keylen) != (size_t)(r - q))
@ -179,11 +178,11 @@ oath_key_from_uri(const char *uri)
goto invalid;
key->digits = *q - '0';
} else if (strlcmp("counter=", p, q - p) == 0) {
if (key->counter != UINTMAX_MAX)
if (key->counter != UINT64_MAX)
/* dupe */
goto invalid;
n = strtoumax(q, &e, 10);
if (e != r || n >= UINTMAX_MAX)
if (e != r || n >= UINT64_MAX)
goto invalid;
key->counter = (uint64_t)n;
} else if (strlcmp("period=", p, q - p) == 0) {
@ -226,6 +225,7 @@ oath_key_from_uri(const char *uri)
key->digits = 6;
if (key->keylen == 0)
goto invalid;
return (key);
invalid:
openpam_log(PAM_LOG_NOTICE, "invalid OATH URI: %s", uri);
@ -295,8 +295,8 @@ oath_key_to_uri(const struct oath_key *key)
}
/* compute length of base32-encoded key and append it */
kslen = base32_enclen(key->keylen);
if ((tmp = realloc(uri, urilen + kslen + 1)) == NULL) {
kslen = base32_enclen(key->keylen) + 1;
if ((tmp = realloc(uri, urilen + kslen)) == NULL) {
free(uri);
return (NULL);
}
@ -308,3 +308,22 @@ oath_key_to_uri(const struct oath_key *key)
return (uri);
}
struct oath_key *
oath_dummy_key(enum oath_mode mode, enum oath_hash hash, unsigned int digits)
{
struct oath_key *key;
if ((key = oath_key_alloc(DUMMY_LABELLEN + DUMMY_KEYLEN)) == NULL)
return (NULL);
key->mode = mode;
key->digits = digits;
key->counter = 0;
key->timestep = 30;
key->hash = hash;
key->label = (char *)key->data;
memcpy(key->label, DUMMY_LABEL, DUMMY_LABELLEN);
key->key = key->data + DUMMY_LABELLEN;
key->keylen = DUMMY_KEYLEN;
return (key);
}

View File

@ -34,6 +34,7 @@
#endif
#include <stdint.h>
#include <string.h>
#include <time.h>
#include "oath.h"
@ -48,3 +49,45 @@ oath_totp(const uint8_t *K, size_t Klen, unsigned int Digit)
time(&now);
return (oath_hotp(K, Klen, now / TOTP_TIME_STEP, Digit));
}
unsigned int
oath_totp_current(const struct oath_key *k)
{
unsigned int code;
uint64_t seq;
if (k == NULL)
return (-1);
if (k->mode != om_totp)
return (-1);
if (k->timestep == 0)
return (-1);
seq = time(NULL) / k->timestep;
code = oath_hotp(k->key, k->keylen, seq, k->digits);
return (code);
}
int
oath_totp_match(const struct oath_key *k, unsigned int response, int window)
{
unsigned int code;
uint64_t seq;
int dummy;
if (k == NULL)
return (-1);
if (window < 1)
return (-1);
if (k->mode != om_totp)
return (-1);
if (k->timestep == 0)
return (-1);
seq = time(NULL) / k->timestep;
dummy = (memcmp(k->label, DUMMY_LABEL, DUMMY_LABELLEN) == 0);
for (int i = -window; i <= window; ++i) {
code = oath_hotp(k->key, k->keylen, seq + i, k->digits);
if (code == response && !dummy)
return (1);
}
return (0);
}