int main (int argc, char *argv[]) { struct gengetopt_args_info args_info; char *secret; size_t secretlen = 0; int rc; size_t window; uint64_t moving_factor; unsigned digits; char otp[10]; time_t now, when, t0, time_step_size; int totpflags = 0; set_program_name (argv[0]); if (cmdline_parser (argc, argv, &args_info) != 0) return EXIT_FAILURE; if (args_info.version_given) { char *p; int l = -1; if (strcmp (oath_check_version (NULL), OATH_VERSION) != 0) l = asprintf (&p, "OATH Toolkit liboath.so %s oath.h %s", oath_check_version (NULL), OATH_VERSION); else if (strcmp (OATH_VERSION, PACKAGE_VERSION) != 0) l = asprintf (&p, "OATH Toolkit %s", oath_check_version (NULL), OATH_VERSION); version_etc (stdout, "oathtool", l == -1 ? "OATH Toolkit" : p, PACKAGE_VERSION, "Simon Josefsson", (char *) NULL); if (l != -1) free (p); return EXIT_SUCCESS; } if (args_info.help_given) usage (EXIT_SUCCESS); if (args_info.inputs_num == 0) { cmdline_parser_print_help (); emit_bug_reporting_address (); return EXIT_SUCCESS; } rc = oath_init (); if (rc != OATH_OK) error (EXIT_FAILURE, 0, "liboath initialization failed: %s", oath_strerror (rc)); if (args_info.base32_flag) { rc = oath_base32_decode (args_info.inputs[0], strlen (args_info.inputs[0]), &secret, &secretlen); if (rc != OATH_OK) error (EXIT_FAILURE, 0, "base32 decoding failed: %s", oath_strerror (rc)); } else { secretlen = 1 + strlen (args_info.inputs[0]) / 2; secret = malloc (secretlen); if (!secret) error (EXIT_FAILURE, errno, "malloc"); rc = oath_hex2bin (args_info.inputs[0], secret, &secretlen); if (rc != OATH_OK) error (EXIT_FAILURE, 0, "hex decoding of secret key failed"); } if (args_info.counter_orig) moving_factor = args_info.counter_arg; else moving_factor = 0; if (args_info.digits_orig) digits = args_info.digits_arg; else digits = 6; if (args_info.window_orig) window = args_info.window_arg; else window = 0; if (digits != 6 && digits != 7 && digits != 8) error (EXIT_FAILURE, 0, "only digits 6, 7 and 8 are supported"); if (validate_otp_p (args_info.inputs_num) && !args_info.digits_orig) digits = strlen (args_info.inputs[1]); else if (validate_otp_p (args_info.inputs_num) && args_info.digits_orig && args_info.digits_arg != strlen (args_info.inputs[1])) error (EXIT_FAILURE, 0, "given one-time password has bad length %d != %ld", args_info.digits_arg, strlen (args_info.inputs[1])); if (args_info.inputs_num > 2) error (EXIT_FAILURE, 0, "too many parameters"); if (args_info.verbose_flag) { char *tmp; tmp = malloc (2 * secretlen + 1); if (!tmp) error (EXIT_FAILURE, errno, "malloc"); oath_bin2hex (secret, secretlen, tmp); printf ("Hex secret: %s\n", tmp); free (tmp); rc = oath_base32_encode (secret, secretlen, &tmp, NULL); if (rc != OATH_OK) error (EXIT_FAILURE, 0, "base32 encoding failed: %s", oath_strerror (rc)); printf ("Base32 secret: %s\n", tmp); free (tmp); if (args_info.inputs_num == 2) printf ("OTP: %s\n", args_info.inputs[1]); printf ("Digits: %d\n", digits); printf ("Window size: %ld\n", window); } if (args_info.totp_given) { now = time (NULL); when = parse_time (args_info.now_arg, now); t0 = parse_time (args_info.start_time_arg, now); time_step_size = parse_duration (args_info.time_step_size_arg); if (when == BAD_TIME) error (EXIT_FAILURE, 0, "cannot parse time `%s'", args_info.now_arg); if (t0 == BAD_TIME) error (EXIT_FAILURE, 0, "cannot parse time `%s'", args_info.start_time_arg); if (time_step_size == BAD_TIME) error (EXIT_FAILURE, 0, "cannot parse time `%s'", args_info.time_step_size_arg); if (strcmp (args_info.totp_arg, "sha256") == 0) totpflags = OATH_TOTP_HMAC_SHA256; else if (strcmp (args_info.totp_arg, "sha512") == 0) totpflags = OATH_TOTP_HMAC_SHA512; if (args_info.verbose_flag) verbose_totp (t0, time_step_size, when); } else { if (args_info.verbose_flag) verbose_hotp (moving_factor); } if (generate_otp_p (args_info.inputs_num) && !args_info.totp_given) { size_t iter = 0; do { rc = oath_hotp_generate (secret, secretlen, moving_factor + iter, digits, false, OATH_HOTP_DYNAMIC_TRUNCATION, otp); if (rc != OATH_OK) error (EXIT_FAILURE, 0, "generating one-time password failed (%d)", rc); printf ("%s\n", otp); } while (window - iter++ > 0); } else if (generate_otp_p (args_info.inputs_num) && args_info.totp_given) { size_t iter = 0; do { rc = oath_totp_generate2 (secret, secretlen, when + iter * time_step_size, time_step_size, t0, digits, totpflags, otp); if (rc != OATH_OK) error (EXIT_FAILURE, 0, "generating one-time password failed (%d)", rc); printf ("%s\n", otp); } while (window - iter++ > 0); } else if (validate_otp_p (args_info.inputs_num) && !args_info.totp_given) { rc = oath_hotp_validate (secret, secretlen, moving_factor, window, args_info.inputs[1]); if (rc == OATH_INVALID_OTP) error (EXIT_OTP_INVALID, 0, "password \"%s\" not found in range %ld .. %ld", args_info.inputs[1], (long) moving_factor, (long) moving_factor + window); else if (rc < 0) error (EXIT_FAILURE, 0, "validating one-time password failed (%d)", rc); printf ("%d\n", rc); } else if (validate_otp_p (args_info.inputs_num) && args_info.totp_given) { rc = oath_totp_validate4 (secret, secretlen, when, time_step_size, t0, window, NULL, NULL, totpflags, args_info.inputs[1]); if (rc == OATH_INVALID_OTP) error (EXIT_OTP_INVALID, 0, "password \"%s\" not found in range %ld .. %ld", args_info.inputs[1], (long) ((when - t0) / time_step_size - window / 2), (long) ((when - t0) / time_step_size + window / 2)); else if (rc < 0) error (EXIT_FAILURE, 0, "validating one-time password failed (%d)", rc); printf ("%d\n", rc); } free (secret); oath_done (); return EXIT_SUCCESS; }
int main (void) { oath_rc rc; char *hexsecret = "ABCDEF3435363738393031323334353637abcdef"; char secret[20]; size_t secretlen; if (!oath_check_version (OATH_VERSION)) { printf ("oath_check_version (%s) failed [%s]\n", OATH_VERSION, oath_check_version (NULL)); return 1; } if (oath_check_version (NULL) == NULL) { printf ("oath_check_version (NULL) == NULL\n"); return 1; } if (oath_check_version ("999.999")) { printf ("oath_check_version (999.999) succeeded?!\n"); return 1; } rc = oath_init (); if (rc != OATH_OK) { printf ("oath_init: %d\n", rc); return 1; } secretlen = 0; rc = oath_hex2bin (hexsecret, secret, &secretlen); if (rc != OATH_TOO_SMALL_BUFFER) { printf ("oath_hex2bin too small: %d\n", rc); return 1; } if (secretlen != 20) { printf ("oath_hex2bin too small: 20 != %d\n", secretlen); return 1; } rc = oath_hex2bin ("abcd", secret, &secretlen); if (rc != OATH_OK) { printf ("oath_hex2bin lower case failed: %d\n", rc); return 1; } rc = oath_hex2bin ("ABCD", secret, &secretlen); if (rc != OATH_OK) { printf ("oath_hex2bin upper case failed: %d\n", rc); return 1; } rc = oath_hex2bin ("ABC", secret, &secretlen); if (rc != OATH_INVALID_HEX) { printf ("oath_hex2bin too small failed: %d\n", rc); return 1; } rc = oath_hex2bin ("JUNK", secret, &secretlen); if (rc != OATH_INVALID_HEX) { printf ("oath_hex2bin junk failed: %d\n", rc); return 1; } secretlen = sizeof (secret); rc = oath_hex2bin (hexsecret, secret, &secretlen); if (rc != OATH_OK) { printf ("oath_hex2bin: %d\n", rc); return 1; } if (secretlen != 20) { printf ("oath_hex2bin: 20 != %d\n", secretlen); return 1; } if (memcmp (secret, "\xAB\xCD\xEF\x34\x35\x36\x37\x38\x39\x30" "\x31\x32\x33\x34\x35\x36\x37\xab\xcd\xef", 20) != 0) { printf ("oath_hex2bin: decode mismatch\n"); return 1; } rc = oath_done (); if (rc != OATH_OK) { printf ("oath_done: %d\n", rc); return 1; } return 0; }
static int parse_usersfile (const char *username, const char *otp, size_t window, const char *passwd, time_t * last_otp, FILE * infh, char **lineptr, size_t * n, uint64_t * new_moving_factor) { while (getline (lineptr, n, infh) != -1) { char *saveptr; char *p = strtok_r (*lineptr, whitespace, &saveptr); unsigned digits, totpstepsize; char secret[32]; size_t secret_length = sizeof (secret); uint64_t start_moving_factor = 0; int rc; char *prev_otp = NULL; if (p == NULL) continue; /* Read token type */ if (parse_type (p, &digits, &totpstepsize) != 0) continue; /* Read username */ p = strtok_r (NULL, whitespace, &saveptr); if (p == NULL || strcmp (p, username) != 0) continue; /* Read password. */ p = strtok_r (NULL, whitespace, &saveptr); if (passwd) { if (p == NULL) continue; if (strcmp (p, "-") == 0) { if (*passwd != '\0') return OATH_BAD_PASSWORD; } else if (strcmp (p, passwd) != 0) return OATH_BAD_PASSWORD; } /* Read key. */ p = strtok_r (NULL, whitespace, &saveptr); if (p == NULL) continue; rc = oath_hex2bin (p, secret, &secret_length); if (rc != OATH_OK) return rc; /* Read (optional) moving factor. */ p = strtok_r (NULL, whitespace, &saveptr); if (p && *p) { char *endptr; unsigned long long int ull = strtoull (p, &endptr, 10); if (endptr && *endptr != '\0') return OATH_INVALID_COUNTER; start_moving_factor = ull; } /* Read (optional) last OTP */ prev_otp = strtok_r (NULL, whitespace, &saveptr); /* Read (optional) last_otp */ p = strtok_r (NULL, whitespace, &saveptr); if (p) { struct tm tm; char *ts; ts = strptime (p, TIME_FORMAT_STRING, &tm); if (ts == NULL || *ts != '\0') return OATH_INVALID_TIMESTAMP; tm.tm_isdst = -1; if (last_otp) { *last_otp = mktime (&tm); if (*last_otp == (time_t) - 1) return OATH_INVALID_TIMESTAMP; } } if (prev_otp && strcmp (prev_otp, otp) == 0) return OATH_REPLAYED_OTP; if (totpstepsize == 0) rc = oath_hotp_validate (secret, secret_length, start_moving_factor, window, otp); else if (prev_otp) { int prev_otp_pos, this_otp_pos, tmprc; rc = oath_totp_validate2 (secret, secret_length, time (NULL), totpstepsize, 0, window, &this_otp_pos, otp); if (rc < 0) return rc; tmprc = oath_totp_validate2 (secret, secret_length, time (NULL), totpstepsize, 0, window, &prev_otp_pos, prev_otp); if (tmprc >= 0 && prev_otp_pos >= this_otp_pos) return OATH_REPLAYED_OTP; } else rc = oath_totp_validate (secret, secret_length, time (NULL), totpstepsize, 0, window, otp); if (rc < 0) return rc; *new_moving_factor = start_moving_factor + rc; return OATH_OK; } return OATH_UNKNOWN_USER; }