All property names and values may be percent-encoded.

If the key length is not a multiple of 40 bits, its base32 representation may be padded, and that padding will be encoded.   We already decoded the label (which may contain spaces and other unsafe characters), but not the key.  For the sake of simplicity and robustness, we now decode the name and value of every property.

This corresponds to OpenPAM r886.
This commit is contained in:
Dag-Erling Smørgrav 2017-03-05 16:53:32 +01:00
parent d419d7388a
commit d017611d76
2 changed files with 32 additions and 22 deletions

View file

@ -1,5 +1,6 @@
/*-
* Copyright (c) 2013-2014 The University of Oslo
* Copyright (c) 2013-2016 The University of Oslo
* Copyright (c) 2016-2017 Dag-Erling Smørgrav
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -48,6 +49,8 @@
struct oath_key *
oath_key_from_uri(const char *uri)
{
char name[64], value[256];
size_t namelen, valuelen;
struct oath_key *key;
const char *p, *q, *r;
uintmax_t n;
@ -86,69 +89,76 @@ oath_key_from_uri(const char *uri)
key->counter = UINT64_MAX;
key->lastused = UINT64_MAX;
while (*p != '\0') {
/* locate name-value separator */
if ((q = strchr(p, '=')) == NULL)
goto invalid;
q = q + 1;
/* locate end of value */
if ((r = strchr(p, '&')) == NULL)
r = strchr(p, '\0');
if (r < q)
/* & before = */
goto invalid;
/* p points to key, q points to value, r points to & or NUL */
if (strlcmp("secret=", p, q - p) == 0) {
/* decode name and value*/
namelen = sizeof name;
valuelen = sizeof value;
if (percent_decode(p, q - p - 1, name, &namelen) != 0 ||
percent_decode(q, r - q, value, &valuelen) != 0)
goto invalid;
if (strcmp("secret", name) == 0) {
if (key->keylen != 0)
/* dupe */
goto invalid;
key->keylen = sizeof key->key;
if (base32_decode(q, r - q, key->key, &key->keylen) != 0)
if (base32_decode(value, valuelen, key->key, &key->keylen) != 0)
goto invalid;
} else if (strlcmp("algorithm=", p, q - p) == 0) {
} else if (strcmp("algorithm", name) == 0) {
if (key->hash != oh_undef)
/* dupe */
goto invalid;
if (strlcmp("SHA1", q, r - q) == 0)
if (strcmp("SHA1", value) == 0)
key->hash = oh_sha1;
else if (strlcmp("SHA256", q, r - q) == 0)
else if (strcmp("SHA256", value) == 0)
key->hash = oh_sha256;
else if (strlcmp("SHA512", q, r - q) == 0)
else if (strcmp("SHA512", value) == 0)
key->hash = oh_sha512;
else if (strlcmp("MD5", q, r - q) == 0)
else if (strcmp("MD5", value) == 0)
key->hash = oh_md5;
else
goto invalid;
} else if (strlcmp("digits=", p, q - p) == 0) {
} else if (strcmp("digits", name) == 0) {
if (key->digits != 0)
/* dupe */
goto invalid;
/* only 6 or 8 */
if (r - q != 1 || (*q != '6' && *q != '8'))
if (valuelen != 1 || (*value != '6' && *value != '8'))
goto invalid;
key->digits = *q - '0';
} else if (strlcmp("counter=", p, q - p) == 0) {
} else if (strcmp("counter", name) == 0) {
if (key->counter != UINT64_MAX)
/* dupe */
goto invalid;
n = strtoumax(q, &e, 10);
if (e != r || n >= UINT64_MAX)
n = strtoumax(value, &e, 10);
if (e == value || *e != '\0' || n >= UINT64_MAX)
goto invalid;
key->counter = (uint64_t)n;
} else if (strlcmp("lastused=", p, q - p) == 0) {
} else if (strcmp("lastused", name) == 0) {
if (key->lastused != UINT64_MAX)
/* dupe */
goto invalid;
n = strtoumax(q, &e, 10);
if (e != r || n >= UINT64_MAX)
n = strtoumax(value, &e, 10);
if (e == value || *e != '\0' || n >= UINT64_MAX)
goto invalid;
key->lastused = (uint64_t)n;
} else if (strlcmp("period=", p, q - p) == 0) {
} else if (strcmp("period", name) == 0) {
if (key->timestep != 0)
/* dupe */
goto invalid;
n = strtoumax(q, &e, 10);
if (e != r || n > OATH_MAX_TIMESTEP)
n = strtoumax(value, &e, 10);
if (e == value || *e != '\0' || n > OATH_MAX_TIMESTEP)
goto invalid;
key->timestep = n;
} else if (strlcmp("issuer=", p, q - p) == 0) {
} else if (strcmp("issuer", name) == 0) {
// noop for now
} else {
goto invalid;

View file

@ -63,7 +63,7 @@ oath_key_to_uri(const struct oath_key *key)
return (NULL);
}
/* XXX the label should be URI-encoded */
/* XXX the label and secret should be URI-encoded */
if (key->mode == om_hotp) {
urilen = asprintf(&uri, "otpauth://%s/%s?"
"algorithm=%s&digits=%d&counter=%ju&secret=",