- 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:
parent
2fe7fdd088
commit
e39d0abb85
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue