From: Margaret Cullen Date: Fri, 11 Aug 2023 22:47:58 +0000 (-0400) Subject: Add lookback capability to address transit delay X-Git-Tag: release_3_2_4~163 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3c06f274dd8bc70d7b32736ef6c8064b61cae177;p=thirdparty%2Ffreeradius-server.git Add lookback capability to address transit delay Signed-off-by: Margaret Cullen --- diff --git a/src/modules/rlm_totp/rlm_totp.c b/src/modules/rlm_totp/rlm_totp.c index c9c4709c90d..32328b0fcc8 100644 --- a/src/modules/rlm_totp/rlm_totp.c +++ b/src/modules/rlm_totp/rlm_totp.c @@ -29,6 +29,8 @@ RCSID("$Id$") #include #define TIME_STEP (30) +#define BACK_STEPS (1) +#define BACK_STEP_SECS (30) /* * RFC 4648 base32 decoding. @@ -174,45 +176,57 @@ static int totp_cmp(TESTING_UNUSED REQUEST *request, time_t now, uint8_t const * char buffer[9]; uint8_t data[8]; uint8_t digest[SHA1_DIGEST_LENGTH]; - - padded = ((uint64_t) now) / TIME_STEP; - data[0] = padded >> 56; - data[1] = padded >> 48; - data[2] = padded >> 40; - data[3] = padded >> 32; - data[4] = padded >> 24; - data[5] = padded >> 16; - data[6] = padded >> 8; - data[7] = padded & 0xff; - - /* - * Encrypt the network order time with the key. - */ - fr_hmac_sha1(digest, data, 8, key, keylen); - - /* - * Take the least significant 4 bits. - */ - offset = digest[SHA1_DIGEST_LENGTH - 1] & 0x0f; - - /* - * Grab the 32bits at "offset", and drop the high bit. - */ - challenge = (digest[offset] & 0x7f) << 24; - challenge |= digest[offset + 1] << 16; - challenge |= digest[offset + 2] << 8; - challenge |= digest[offset + 3]; + time_t then; + int i; /* - * The token is the last 6 digits in the number. + * First try to authenticate against the current OTP, then step + * back in increments of BACK_STEP_SECS, up to BACK_STEPS times, + * to authenticate properly in cases of long transit delay, as + * described in RFC 6238, secion 5.2. */ - snprintf(buffer, sizeof(buffer), PRINT, challenge % DIV); - - RDEBUG3("Time %zu", (size_t) now); - RDEBUG3("Expected %s", buffer); - RDEBUG3("Received %s", totp); - - return rad_digest_cmp((uint8_t const *) buffer, (uint8_t const *) totp, LEN); + for (i = 0, then = now; i <= BACK_STEPS; i++, then -= BACK_STEP_SECS) { + padded = (uint64_t) then / TIME_STEP; + data[0] = padded >> 56; + data[1] = padded >> 48; + data[2] = padded >> 40; + data[3] = padded >> 32; + data[4] = padded >> 24; + data[5] = padded >> 16; + data[6] = padded >> 8; + data[7] = padded & 0xff; + + /* + * Encrypt the network order time with the key. + */ + fr_hmac_sha1(digest, data, 8, key, keylen); + + /* + * Take the least significant 4 bits. + */ + offset = digest[SHA1_DIGEST_LENGTH - 1] & 0x0f; + + /* + * Grab the 32bits at "offset", and drop the high bit. + */ + challenge = (digest[offset] & 0x7f) << 24; + challenge |= digest[offset + 1] << 16; + challenge |= digest[offset + 2] << 8; + challenge |= digest[offset + 3]; + + /* + * The token is the last 6 digits in the number (or 8 for testing).. + */ + snprintf(buffer, sizeof(buffer), PRINT, challenge % DIV); + + RDEBUG3("Now: %zu, Then: %zu", (size_t) now, (size_t) then); + RDEBUG3("Expected %s", buffer); + RDEBUG3("Received %s", totp); + + if (rad_digest_cmp((uint8_t const *) buffer, (uint8_t const *) totp, LEN) == 0) + return 0; + } + return 1; } #ifndef TESTING @@ -226,7 +240,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, REQU uint8_t const *key; size_t keylen; uint8_t buffer[80]; /* multiple of 5*8 characters */ - + uint64_t now = time(NULL); password = fr_pair_find_by_num(request->packet->vps, PW_TOTP_PASSWORD, 0, TAG_ANY); if (!password) return RLM_MODULE_NOOP; @@ -260,9 +274,10 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, REQU keylen = len; } - if (totp_cmp(request, time(NULL), key, keylen, password->vp_strvalue) != 0) return RLM_MODULE_FAIL; - - return RLM_MODULE_OK; + if (totp_cmp(request, now, key, keylen, password->vp_strvalue) == 0) + return RLM_MODULE_OK; + } + return RLM_MODULE_FAIL; } @@ -327,8 +342,12 @@ int main(int argc, char **argv) (void) sscanf(argv[2], "%llu", &now); } - if (totp_cmp(NULL, (time_t) now, (uint8_t const *) argv[3], strlen(argv[3]), argv[4]) == 0) { - return 0; + printf ("=== Time = %llu, TIME_STEP = %d, BACK_STEPS = %d, BACK_STEP_SECS = %d ===\n", + now, TIME_STEP, BACK_STEPS, BACK_STEP_SECS); + + if (totp_cmp(NULL, (time_t) now, (uint8_t const *) argv[3], + strlen(argv[3]), argv[4]) == 0) { + return 0; } printf("Fail\n"); return 1;