Download raw body.
ensure gotwebd login token uniqueness
gotwebd login links requested within the same second are not unique.
Which means users (including anonymous) can deduce the occurance of
server-side clock ticks once per second by requesting login links
repeatedly and watch the login token changing.
I don't know if this is a problem in practice but this side-channel
can be closed with little effort by prepending random data to the
login token which gets mixed into the hash before the useful data is
mixed in.
ok?
M gotwebd/login.c | 10+ 5-
1 file changed, 10 insertions(+), 5 deletions(-)
commit - f8c15ec8a9ddce2f08959da8a558e2f50b8738b8
commit + 012f34f998f2f6bad8853afdd0f6a3a63e582be9
blob - 9504381f3d7a57fcce332e523404ead0eb3ebe74
blob + d9f42f6aec8a16bc3ef3a406f2fc3e7d2b6ac426
--- gotwebd/login.c
+++ gotwebd/login.c
@@ -62,7 +62,7 @@ static char login_token_secret[32];
/*
* The token format is:
*
- * "v1\0"[issued at/64bit][expire/64bit][uid/64bit][host]"\0"
+ * "v2\0"[random/64bit][issued at/64bit][expire/64bit][uid/64bit][host]"\0"
*
* Padded with additional \0 to a length divisible by 4, and then
* followed by the HMAC-SHA256 of it, all encoded in base64.
@@ -75,7 +75,7 @@ login_check_token(uid_t *euid, char **hostname,
const char *purpose)
{
time_t now;
- uint64_t issued, expire, uid;
+ uint64_t random, issued, expire, uid;
uint8_t *data;
int len;
char hmac[32], exp[32];
@@ -112,7 +112,7 @@ login_check_token(uid_t *euid, char **hostname,
return -1;
}
- if (memcmp(data, "v1", 3) != 0) {
+ if (memcmp(data, "v2", 3) != 0) {
log_warnx("unknown %s token format version", purpose);
free(data);
return -1;
@@ -140,6 +140,9 @@ login_check_token(uid_t *euid, char **hostname,
return -1;
}
+ memcpy(&random, data + used, sizeof(random));
+ used += sizeof(random);
+
memcpy(&issued, data + used, sizeof(issued));
used += sizeof(issued);
@@ -193,7 +196,7 @@ login_gen_token(uint64_t uid, const char *hostname, ti
FILE *fp;
char *tok;
time_t now;
- uint64_t issued, expire;
+ uint64_t random, issued, expire;
size_t siz, hlen, pad;
unsigned int hmaclen; /* openssl... */
@@ -205,6 +208,7 @@ login_gen_token(uint64_t uid, const char *hostname, ti
fatalx("%s token secret length mismatch", purpose);
now = time(NULL);
+ arc4random_buf(&random, sizeof(random));
issued = (uint64_t)now;
expire = issued + validity;
@@ -215,7 +219,8 @@ login_gen_token(uint64_t uid, const char *hostname, ti
/* include NUL */
hlen = strlen(hostname) + 1;
- if (fwrite("v1", 1, 3, fp) != 3 ||
+ if (fwrite("v2", 1, 3, fp) != 3 ||
+ fwrite(&random, 1, 8, fp) != 8 ||
fwrite(&issued, 1, 8, fp) != 8 ||
fwrite(&expire, 1, 8, fp) != 8 ||
fwrite(&uid, 1, 8, fp) != 8 ||
ensure gotwebd login token uniqueness