From 03a61fd766fb43082a3beaddf1e5a69c881bd475 Mon Sep 17 00:00:00 2001 From: "David M. Syzdek" Date: Mon, 16 Jan 2023 22:52:50 -0900 Subject: otputil: adding 'otp' and 'skey' widgets --- Makefile.am | 2 + src/otputil.c | 140 +++++++++++++++++++----- src/otputil.h | 38 +++++++ src/widget-hotp.c | 2 +- src/widget-otp.c | 322 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/widget-skey.c | 252 ++++++++++++++++++++++++++++++++++++++++++ src/widget-totp.c | 2 +- 7 files changed, 730 insertions(+), 28 deletions(-) create mode 100644 src/widget-otp.c create mode 100644 src/widget-skey.c diff --git a/Makefile.am b/Makefile.am index 32bcbfc..cc1aeb6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -220,6 +220,8 @@ src_otputil_LDADD = $(AM_LIBS) $(noinst_LIBRARIES) $(lib_LTLIBRARIES) src_otputil_SOURCES = src/otputil.c \ src/otputil.h \ src/widget-hotp.c \ + src/widget-otp.c \ + src/widget-skey.c \ src/widget-totp.c diff --git a/src/otputil.c b/src/otputil.c index 6c32b50..9524b63 100644 --- a/src/otputil.c +++ b/src/otputil.c @@ -116,7 +116,7 @@ otputil_widget_lookup( //--------------------------// #pragma mark widgets prototypes -static int +extern int otputil_widget_debug( otputil_config_t * cnf ); @@ -146,7 +146,7 @@ static otputil_widget_t otputil_widget_map[] = { .name = "debug", .desc = NULL, .usage = NULL, - .short_opt = "0123456789abc:d:efghijk:lm:nopqrst:uvwx:yzABCDEFGHIJKLMNOPQRST:UVWXYZ", + .short_opt = "0123456789abc:d:efghijk:lm:nopqrs:t:uvwx:yzABCDEFGHIJKLMNOP:QRST:UVWXYZ", .arg_min = 0, .arg_max = 4096, .aliases = NULL, @@ -165,17 +165,67 @@ static otputil_widget_t otputil_widget_map[] = { .name = "hotp", .desc = "hotp tools (RFC 4226)", .usage = " [ code ]", - .short_opt = (TOTP_SHORT_OPT "c:d:k:m:p"), + .short_opt = (TOTP_SHORT_OPT "c:d:k:m:o"), .arg_min = 0, .arg_max = 1, .aliases = NULL, .func_exec = &otputil_widget_hotp, .func_usage = NULL, }, + { .name = "otp", + .desc = "otp tools (RFC 2289)", + .usage = " [ sequence ] seed ]", + .short_opt = (TOTP_SHORT_OPT "c:m:oP:ps:"), + .arg_min = 0, + .arg_max = 2, + .aliases = NULL, + .func_exec = &otputil_widget_otp, + .func_usage = &otputil_widget_otp_usage, + }, + { .name = "otp-md4", + .desc = "otp alias for MD4", + .usage = " [ sequence ] seed ]", + .short_opt = (TOTP_SHORT_OPT "c:oP:ps:"), + .arg_min = 0, + .arg_max = 2, + .aliases = NULL, + .func_exec = &otputil_widget_otp_md4, + .func_usage = NULL, + }, + { .name = "otp-md5", + .desc = "otp alias for MD5", + .usage = " [ sequence ] seed ]", + .short_opt = (TOTP_SHORT_OPT "c:oP:ps:"), + .arg_min = 0, + .arg_max = 2, + .aliases = NULL, + .func_exec = &otputil_widget_otp_md5, + .func_usage = NULL, + }, + { .name = "otp-sha1", + .desc = "otp alias for SHA1", + .usage = " [ sequence ] seed ]", + .short_opt = (TOTP_SHORT_OPT "c:oP:ps:"), + .arg_min = 0, + .arg_max = 2, + .aliases = NULL, + .func_exec = &otputil_widget_otp_sha1, + .func_usage = NULL, + }, + { .name = "skey", + .desc = "s/key tools (RFC 1760)", + .usage = " [ sequence ]", + .short_opt = (TOTP_SHORT_OPT "c:m:oP:p"), + .arg_min = 0, + .arg_max = 1, + .aliases = NULL, + .func_exec = &otputil_widget_skey, + .func_usage = &otputil_widget_skey_usage, + }, { .name = "totp", .desc = "totp tools (RFC 6238)", .usage = " [ code ]", - .short_opt = (TOTP_SHORT_OPT "d:k:m:pT:t:x:"), + .short_opt = (TOTP_SHORT_OPT "d:k:m:oT:t:x:"), .arg_min = 0, .arg_max = 1, .aliases = NULL, @@ -234,6 +284,7 @@ main( cnf->prog_name = &cnf->prog_name[1]; if (!(cnf->prog_name)) cnf->prog_name = argv[0]; + otputil_set_param(NULL, OTPUTIL_OPT_DESC, cnf->prog_name); // skip argument processing if called via alias @@ -288,6 +339,7 @@ otputil_arguments( char * endptr; int rc; int i; + const char * str; // getopt options static const char * short_opt = "+" TOTP_SHORT_OPT; @@ -317,17 +369,16 @@ otputil_arguments( case 'c': uval = strtoull(optarg, &endptr, 0); + i = (int)uval; if ((optarg == endptr) || (endptr[0] != '\0')) { fprintf(stderr, "%s: invalid value for `-c'\n", PROGRAM_NAME); fprintf(stderr, "Try `%s --help' for more information.\n", PROGRAM_NAME); return(1); }; - if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_HOTP_C, &uval)) != OTPUTIL_SUCCESS) - { - fprintf(stderr, "%s: otputil_set_param(OTPUTIL_OPT_HOTP_C): %s\n", PROGRAM_NAME, otputil_err2string(rc)); - return(1); - }; + otputil_set_param(NULL, OTPUTIL_OPT_HOTP_C, &uval); + otputil_set_param(NULL, OTPUTIL_OPT_OTP_SEQ, &i); + otputil_set_param(NULL, OTPUTIL_OPT_SKEY_SEQ, &i); break; case 'd': @@ -370,31 +421,29 @@ otputil_arguments( break; case 'm': - if ((i = otputil_str2md(optarg)) == -1) + str = (!(strncasecmp("otp-", optarg, 4))) ? &optarg[4] : optarg; + if ((i = otputil_str2md(str)) == -1) { - fprintf(stderr, "%s: message digest for `-m'\n", PROGRAM_NAME); + fprintf(stderr, "%s: %s: unknown message digest for `-m'\n", PROGRAM_NAME, str); fprintf(stderr, "Try `%s --help' for more information.\n", PROGRAM_NAME); return(1); }; - if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_HMAC, &i)) != OTPUTIL_SUCCESS) - { - fprintf(stderr, "%s: otputil_set_param(OTPUTIL_OPT_HMAC): %s\n", PROGRAM_NAME, otputil_err2string(rc)); - return(1); - }; + otputil_set_param(NULL, OTPUTIL_OPT_HOTP_HMAC, &i); + otputil_set_param(NULL, OTPUTIL_OPT_OTP_HASH, &i); + otputil_set_param(NULL, OTPUTIL_OPT_SKEY_HASH, &i); + otputil_set_param(NULL, OTPUTIL_OPT_TOTP_HMAC, &i); break; - case 's': - cnf->quiet = 1; - if ((cnf->verbose)) - { - fprintf(stderr, "%s: incompatible options\n", PROGRAM_NAME); - fprintf(stderr, "Try `%s --help' for more information.\n", PROGRAM_NAME); - return(1); - }; + case 'o': + cnf->prompt_otp_pass = 1; + break; + + case 'P': + cnf->user_pass = optarg; break; case 'p': - cnf->otp_pass = otputil_getpass("Enter OTP password or code: ", NULL, 0); + cnf->prompt_user_pass = 1; break; case 'q': @@ -407,6 +456,14 @@ otputil_arguments( }; break; + case 's': + if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_OTP_SEED, optarg)) != OTPUTIL_SUCCESS) + { + fprintf(stderr, "%s: otputil_set_param(OTPUTIL_OPT_OTP_SEED): %s\n", PROGRAM_NAME, otputil_err2string(rc)); + return(1); + }; + break; + case 'T': uval = strtoull(optarg, &endptr, 0); if ((optarg == endptr) || (endptr[0] != '\0')) @@ -493,6 +550,33 @@ otputil_arguments( return(1); }; + // process user password + if ( ((cnf->user_pass)) && ((cnf->prompt_user_pass)) ) + { + fprintf(stderr, "%s: incompatible options `-P' and `-p'\n", PROGRAM_NAME); + fprintf(stderr, "Try `%s --help' for more information.\n", PROGRAM_NAME); + return(1); + }; + if ((cnf->prompt_user_pass)) + cnf->user_pass = otputil_getpass("Enter user's password: ", NULL, 0); + if ((cnf->user_pass)) + { + if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_SKEY_PASS, cnf->user_pass)) != OTPUTIL_SUCCESS) + { + fprintf(stderr, "%s: otputil_set_param(OTPUTIL_OPT_SKEY_PASS): %s\n", PROGRAM_NAME, otputil_err2string(rc)); + return(1); + }; + if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_OTP_PASS, cnf->user_pass)) != OTPUTIL_SUCCESS) + { + fprintf(stderr, "%s: otputil_set_param(OTPUTIL_OPT_OTP_PASS): %s\n", PROGRAM_NAME, otputil_err2string(rc)); + return(1); + }; + }; + + // process OTP password + if ((cnf->prompt_otp_pass)) + cnf->otp_pass = otputil_getpass("Enter OTP password or code: ", NULL, 0); + return(0); } @@ -615,12 +699,16 @@ otputil_widget_usage( printf(" %s-%s [OPTIONS]%s\n", PROGRAM_NAME, widget_name, widget_help); printf(" %s%s [OPTIONS]%s\n", PROGRAM_NAME, widget_name, widget_help); printf("OPTIONS:\n"); - if ((strchr(short_opt, 'c'))) printf(" -c num counter value\n"); + if ((strchr(short_opt, 'c'))) printf(" -c num counter/sequence value\n"); if ((strchr(short_opt, 'd'))) printf(" -d num number of digits in code\n"); if ((strchr(short_opt, 'k'))) printf(" -k string shared user key\n"); if ((strchr(short_opt, 'h'))) printf(" -h, --help print this help and exit\n"); if ((strchr(short_opt, 'm'))) printf(" -m hash use message digest hash\n"); + if ((strchr(short_opt, 'o'))) printf(" -o prompt for OTP password/code to verify\n"); + if ((strchr(short_opt, 'P'))) printf(" -P str user password\n"); + if ((strchr(short_opt, 'p'))) printf(" -p prompt for user password\n"); if ((strchr(short_opt, 'q'))) printf(" -q, --quiet, --silent do not print messages\n"); + if ((strchr(short_opt, 's'))) printf(" -s seed OTP seed\n"); if ((strchr(short_opt, 'T'))) printf(" -T seconds current Unix time\n"); if ((strchr(short_opt, 't'))) printf(" -t seconds Unix time start of time steps\n"); if ((strchr(short_opt, 'V'))) printf(" -V, --version print version number and exit\n"); diff --git a/src/otputil.h b/src/otputil.h index 5471cd8..cd6bd18 100644 --- a/src/otputil.h +++ b/src/otputil.h @@ -87,10 +87,13 @@ struct _otputil_cli_config int quiet; int verbose; int opt_index; + int prompt_user_pass; + int prompt_otp_pass; int argc; char ** argv; const char * prog_name; const char * otp_pass; + const char * user_pass; const otputil_widget_t * widget; }; @@ -124,6 +127,41 @@ otputil_widget_hotp( otputil_config_t * cnf ); +extern int +otputil_widget_otp( + otputil_config_t * cnf ); + + +extern int +otputil_widget_otp_md4( + otputil_config_t * cnf ); + + +extern int +otputil_widget_otp_md5( + otputil_config_t * cnf ); + + +extern int +otputil_widget_otp_sha1( + otputil_config_t * cnf ); + + +extern int +otputil_widget_otp_usage( + otputil_config_t * cnf ); + + +extern int +otputil_widget_skey( + otputil_config_t * cnf ); + + +extern int +otputil_widget_skey_usage( + otputil_config_t * cnf ); + + extern int otputil_widget_totp( otputil_config_t * cnf ); diff --git a/src/widget-hotp.c b/src/widget-hotp.c index af1e51e..535d543 100644 --- a/src/widget-hotp.c +++ b/src/widget-hotp.c @@ -116,7 +116,7 @@ otputil_widget_hotp( return((rc == -1) ? 0 : 1); if ( ((cnf->otp_pass)) && (cnf->argc > optind) ) { - fprintf(stderr, "%s: cannot specify code and use `-p'\n", cnf->prog_name); + fprintf(stderr, "%s: cannot specify code and use `-o'\n", cnf->prog_name); fprintf(stderr, "Try `%s --help' for more information.\n", cnf->prog_name); return(1); }; diff --git a/src/widget-otp.c b/src/widget-otp.c new file mode 100644 index 0000000..ae67a86 --- /dev/null +++ b/src/widget-otp.c @@ -0,0 +1,322 @@ +/* + * OTP Utilities + * Copyright (C) 2022 David M. Syzdek . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of David M. Syzdek nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID M SYZDEK BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * @file src/widget-otp.c + */ +#define _SRC_WIDGET_OTP_C 1 + +/////////////// +// // +// Headers // +// // +/////////////// +#pragma mark - Headers + +#include + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "otputil.h" + + +////////////////// +// // +// Prototypes // +// // +////////////////// +#pragma mark - Prototypes + +static int +otputil_widget_otp_verbose( + otputil_config_t * cnf, + const otputil_bv_t * otp_data, + const otputil_bv_t * otp_verify, + const char * status ); + + +///////////////// +// // +// Functions // +// // +///////////////// +#pragma mark - Functions + + +//---------------// +// main function // +//---------------// +#pragma mark main function + +int +otputil_widget_otp( + otputil_config_t * cnf ) +{ + int rc; + int hash; + int seq; + uint64_t meth; + char * pass; + char * endptr; + const char * str; + const char * status; + static char buff[OTPUTIL_MAX_ENCODE_SIZE]; + otputil_bv_t otp_data; + otputil_bv_t otp_verify; + otputil_bv_t * a; + otputil_bv_t * b; + uint8_t otp_data_val[512]; + uint8_t otp_verify_val[512]; + + assert(cnf != NULL); + + // set OTP method + meth = OTPUTIL_METH_OTP; + if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_METHOD, &meth)) == -1) + { + fprintf(stderr, "%s: otputil_set_param(METHOD): %s\n", cnf->prog_name, otputil_err2string(rc)); + return(1); + }; + + // initial processing of cli arguments + if ((rc = otputil_arguments(cnf, cnf->argc, cnf->argv)) != 0) + return((rc == -1) ? 0 : 1); + if (cnf->argc > optind) + { + seq = (int)strtoul(cnf->argv[optind], &endptr, 0); + if ((endptr == cnf->argv[optind]) || (endptr[0] != '\0')) + { + fprintf(stderr, "%s: invalid sequence number\n", cnf->prog_name); + fprintf(stderr, "Try `%s --help' for more information.\n", cnf->prog_name); + return(1); + }; + if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_OTP_SEQ, &seq)) != OTPUTIL_SUCCESS) + { + fprintf(stderr, "%s: otputil_set_param(OTP_SEQ): %s\n", cnf->prog_name, otputil_err2string(rc)); + return(1); + }; + }; + if (cnf->argc > (optind+1)) + { + if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_OTP_SEED, cnf->argv[optind+1])) != OTPUTIL_SUCCESS) + { + fprintf(stderr, "%s: otputil_set_param(OTP_SEED): %s\n", cnf->prog_name, otputil_err2string(rc)); + return(1); + }; + }; + + // verify password and seed were provided + otputil_get_param(NULL, OTPUTIL_OPT_OTP_PASS, &pass); + if (!(pass)) + { + str = otputil_getpass("Enter user's password:", NULL, 0); + if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_OTP_PASS, str)) != OTPUTIL_SUCCESS) + { + fprintf(stderr, "%s: otputil_set_param(OTP_PASS): %s\n", cnf->prog_name, otputil_err2string(rc)); + return(1); + }; + }; + if ((pass)) + free(pass); + otputil_get_param(NULL, OTPUTIL_OPT_OTP_SEED, &pass); + if (!(pass)) + { + fprintf(stderr, "%s: must provide OTP seed\n", cnf->prog_name); + fprintf(stderr, "Try `%s --help' for more information.\n", cnf->prog_name); + return(1); + }; + free(pass); + + // generate OTP pass phrase + if ((str = otputil_str(NULL, buff, sizeof(buff))) == NULL) + { + fprintf(stderr, "%s: internal error\n", cnf->prog_name); + return(1); + }; + otp_data.bv_val = otp_data_val; + otp_data.bv_len = sizeof(otp_data_val); + otputil_get_param(NULL, OTPUTIL_OPT_OTP_HASH, &hash); + otputil_otp_decode(str, &otp_data, hash); + + // verify existing code + if ((cnf->otp_pass)) + { + otp_verify.bv_val = otp_verify_val; + otp_verify.bv_len = sizeof(otp_verify_val); + if (otputil_otp_decode(cnf->otp_pass, &otp_verify, hash) == NULL) + { + fprintf(stderr, "%s: not a valid OTP passphrase to verify\n", cnf->prog_name); + return(1); + }; + a = &otp_data; + b = &otp_verify; + rc = ((otputil_bvcmp(&a, &b))) ? 2 : 0; + status = ((rc)) ? "invalid code" : "valid code"; + if ((cnf->verbose)) + otputil_widget_otp_verbose(cnf, &otp_data, &otp_verify, status); + else + printf("%s\n", status); + return(rc); + }; + + // print results + if ( ((cnf->quiet)) || (!(cnf->verbose)) ) + { + printf("%s\n", str); + return(0); + }; + otputil_widget_otp_verbose(cnf, &otp_data, NULL, NULL); + + return(0); +} + + +int +otputil_widget_otp_md4( + otputil_config_t * cnf ) +{ + int rc; + int hash; + assert(cnf != NULL); + hash = OTPUTIL_MD_MD4; + if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_OTP_HASH, &hash)) == -1) + { + fprintf(stderr, "%s: otputil_set_param(OTP_HASH): %s\n", cnf->prog_name, otputil_err2string(rc)); + return(1); + }; + return(otputil_widget_otp(cnf)); +} + + +int +otputil_widget_otp_md5( + otputil_config_t * cnf ) +{ + int rc; + int hash; + assert(cnf != NULL); + hash = OTPUTIL_MD_MD5; + if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_OTP_HASH, &hash)) == -1) + { + fprintf(stderr, "%s: otputil_set_param(OTP_HASH): %s\n", cnf->prog_name, otputil_err2string(rc)); + return(1); + }; + return(otputil_widget_otp(cnf)); +} + + +int +otputil_widget_otp_sha1( + otputil_config_t * cnf ) +{ + int rc; + int hash; + assert(cnf != NULL); + hash = OTPUTIL_MD_SHA1; + if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_OTP_HASH, &hash)) == -1) + { + fprintf(stderr, "%s: otputil_set_param(OTP_HASH): %s\n", cnf->prog_name, otputil_err2string(rc)); + return(1); + }; + return(otputil_widget_otp(cnf)); +} + + +int +otputil_widget_otp_usage( + otputil_config_t * cnf ) +{ + assert(cnf != NULL); + printf("ALGORITHMS:\n"); + printf(" md4 MD4 Message-Digest Algorithm\n"); + printf(" md5 MD5 message-digest algorithm\n"); + printf(" sha1 SHA-1 (Secure Hash Algorithm 1)\n"); + printf(" sha256 SHA-2 (Secure Hash Algorithm 2) with 256 bits\n"); + printf(" sha512 SHA-2 (Secure Hash Algorithm 2) with 512 bits\n"); + return(0); +} + + +int +otputil_widget_otp_verbose( + otputil_config_t * cnf, + const otputil_bv_t * otp_data, + const otputil_bv_t * otp_verify, + const char * status ) +{ + int otp_seq; + char * util_desc; + char * otp_seed; + char * otp_pass; + int otp_hash; + + otputil_get_param(NULL, OTPUTIL_OPT_OTP_SEQ, &otp_seq); + otputil_get_param(NULL, OTPUTIL_OPT_OTP_HASH, &otp_hash); + otputil_get_param(NULL, OTPUTIL_OPT_OTP_SEED, &otp_seed); + otputil_get_param(NULL, OTPUTIL_OPT_OTP_PASS, &otp_pass); + otputil_get_param(NULL, OTPUTIL_OPT_DESC, &util_desc); + + // print secret information + printf("S/KEY Secret:\n"); + printf(" Description: %s\n", (((util_desc)) ? util_desc : "n/a") ); + printf(" Method: OTP (RFC2289)\n"); + printf(" Hash: %s\n", otputil_md2str(otp_hash)); + if (cnf->verbose > 1) + printf(" User Passsword: %s\n", otp_pass); + else + printf(" User Passsword: ********\n"); + printf(" Seed: %s\n", otp_seed); + printf(" Sequence: %i\n", otp_seq ); + if ((cnf->otp_pass)) + printf(" Entered Pass Phrase: %s\n", cnf->otp_pass ); + if ((cnf->otp_pass)) + printf(" Expected Code: %s\n", otputil_otp_encode(otp_verify, NULL, 0, OTPUTIL_ENC_HEX) ); + printf(" OTP Code: %s\n", otputil_otp_encode(otp_data, NULL, 0, OTPUTIL_ENC_HEX) ); + if ((cnf->otp_pass)) + printf(" Expected Pass Phrase: %s\n", otputil_otp_encode(otp_verify, NULL, 0, OTPUTIL_ENC_SIXWORD) ); + printf(" OTP Pass Phrase: %s\n", otputil_otp_encode(otp_data, NULL, 0, OTPUTIL_ENC_SIXWORD) ); + if ((status)) + printf(" Status: %s\n", status ); + printf("\n"); + + return(0); +} + +/* end of source file */ diff --git a/src/widget-skey.c b/src/widget-skey.c new file mode 100644 index 0000000..9fa69ea --- /dev/null +++ b/src/widget-skey.c @@ -0,0 +1,252 @@ +/* + * OTP Utilities + * Copyright (C) 2022 David M. Syzdek . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of David M. Syzdek nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID M SYZDEK BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * @file src/widget-otp.c + */ +#define _SRC_WIDGET_OTP_C 1 + +/////////////// +// // +// Headers // +// // +/////////////// +#pragma mark - Headers + +#include + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "otputil.h" + + +////////////////// +// // +// Prototypes // +// // +////////////////// +#pragma mark - Prototypes + +static int +otputil_widget_skey_verbose( + otputil_config_t * cnf, + const otputil_bv_t * otp_data, + const otputil_bv_t * otp_verify, + const char * status ); + + +///////////////// +// // +// Functions // +// // +///////////////// +#pragma mark - Functions + + +//---------------// +// main function // +//---------------// +#pragma mark main function + +int +otputil_widget_skey( + otputil_config_t * cnf ) +{ + int rc; + int hash; + int seq; + uint64_t meth; + char * pass; + char * endptr; + const char * str; + const char * status; + static char buff[OTPUTIL_MAX_ENCODE_SIZE]; + otputil_bv_t skey_data; + otputil_bv_t skey_verify; + otputil_bv_t * a; + otputil_bv_t * b; + uint8_t skey_data_val[512]; + uint8_t skey_verify_val[512]; + + assert(cnf != NULL); + + // set OTP method + meth = OTPUTIL_METH_SKEY; + if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_METHOD, &meth)) == -1) + { + fprintf(stderr, "%s: otputil_set_param(METHOD): %s\n", cnf->prog_name, otputil_err2string(rc)); + return(1); + }; + + // initial processing of cli arguments + if ((rc = otputil_arguments(cnf, cnf->argc, cnf->argv)) != 0) + return((rc == -1) ? 0 : 1); + if (cnf->argc > optind) + { + seq = (int)strtoul(cnf->argv[optind], &endptr, 0); + if ((endptr == cnf->argv[optind]) || (endptr[0] != '\0')) + { + fprintf(stderr, "%s: invalid sequence number\n", cnf->prog_name); + fprintf(stderr, "Try `%s --help' for more information.\n", cnf->prog_name); + return(1); + }; + if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_SKEY_SEQ, &seq)) != OTPUTIL_SUCCESS) + { + fprintf(stderr, "%s: otputil_set_param(SKEY_SEQ): %s\n", cnf->prog_name, otputil_err2string(rc)); + return(1); + }; + }; + + // verify password was provided + otputil_get_param(NULL, OTPUTIL_OPT_SKEY_PASS, &pass); + if (!(pass)) + { + str = otputil_getpass("Enter user's password:", NULL, 0); + if ((rc = otputil_set_param(NULL, OTPUTIL_OPT_SKEY_PASS, str)) != OTPUTIL_SUCCESS) + { + fprintf(stderr, "%s: otputil_set_param(SKEY_PASS): %s\n", cnf->prog_name, otputil_err2string(rc)); + return(1); + }; + }; + if ((pass)) + free(pass); + + // generate OTP pass phrase + if ((str = otputil_str(NULL, buff, sizeof(buff))) == NULL) + { + fprintf(stderr, "%s: internal error\n", cnf->prog_name); + return(1); + }; + skey_data.bv_val = skey_data_val; + skey_data.bv_len = sizeof(skey_data_val); + otputil_get_param(NULL, OTPUTIL_OPT_OTP_HASH, &hash); + otputil_otp_decode(str, &skey_data, hash); + + // verify existing code + if ((cnf->otp_pass)) + { + skey_verify.bv_val = skey_verify_val; + skey_verify.bv_len = sizeof(skey_verify_val); + if (otputil_otp_decode(cnf->otp_pass, &skey_verify, hash) == NULL) + { + fprintf(stderr, "%s: not a valid OTP passphrase to verify\n", cnf->prog_name); + return(1); + }; + a = &skey_data; + b = &skey_verify; + rc = ((otputil_bvcmp(&a, &b))) ? 2 : 0; + status = ((rc)) ? "invalid code" : "valid code"; + if ((cnf->verbose)) + otputil_widget_skey_verbose(cnf, &skey_data, &skey_verify, status); + else + printf("%s\n", status); + return(rc); + }; + + // print results + if ( ((cnf->quiet)) || (!(cnf->verbose)) ) + { + printf("%s\n", str); + return(0); + }; + otputil_widget_skey_verbose(cnf, &skey_data, NULL, NULL); + + return(0); +} + + +int +otputil_widget_skey_usage( + otputil_config_t * cnf ) +{ + assert(cnf != NULL); + printf("ALGORITHMS:\n"); + printf(" md4 MD4 Message-Digest Algorithm\n"); + printf(" md5 MD5 message-digest algorithm\n"); + printf(" sha1 SHA-1 (Secure Hash Algorithm 1)\n"); + printf(" sha256 SHA-2 (Secure Hash Algorithm 2) with 256 bits\n"); + printf(" sha512 SHA-2 (Secure Hash Algorithm 2) with 512 bits\n"); + return(0); +} + + +int +otputil_widget_skey_verbose( + otputil_config_t * cnf, + const otputil_bv_t * skey_data, + const otputil_bv_t * skey_verify, + const char * status ) +{ + int skey_hash; + int skey_seq; + char * util_desc; + char * skey_pass; + + otputil_get_param(NULL, OTPUTIL_OPT_SKEY_SEQ, &skey_seq); + otputil_get_param(NULL, OTPUTIL_OPT_SKEY_HASH, &skey_hash); + otputil_get_param(NULL, OTPUTIL_OPT_SKEY_PASS, &skey_pass); + otputil_get_param(NULL, OTPUTIL_OPT_DESC, &util_desc); + + // print secret information + printf("S/KEY Secret:\n"); + printf(" Description: %s\n", (((util_desc)) ? util_desc : "n/a") ); + printf(" Method: S/KEY (RFC1760)\n"); + printf(" Hash: %s\n", otputil_md2str(skey_hash)); + if (cnf->verbose > 1) + printf(" User Passsword: %s\n", skey_pass); + else + printf(" User Passsword: ********\n"); + printf(" Sequence: %i\n", skey_seq ); + if ((cnf->otp_pass)) + printf(" Entered Pass Phrase: %s\n", cnf->otp_pass ); + if ((cnf->otp_pass)) + printf(" Expected Code: %s\n", otputil_otp_encode(skey_verify, NULL, 0, OTPUTIL_ENC_HEX) ); + printf(" OTP Code: %s\n", otputil_otp_encode(skey_data, NULL, 0, OTPUTIL_ENC_HEX) ); + if ((cnf->otp_pass)) + printf(" Expected Pass Phrase: %s\n", otputil_otp_encode(skey_verify, NULL, 0, OTPUTIL_ENC_SIXWORD) ); + printf(" OTP Pass Phrase: %s\n", otputil_otp_encode(skey_data, NULL, 0, OTPUTIL_ENC_SIXWORD) ); + if ((status)) + printf(" Status: %s\n", status ); + printf("\n"); + + return(0); +} + +/* end of source file */ diff --git a/src/widget-totp.c b/src/widget-totp.c index 0c5a41d..fe08220 100644 --- a/src/widget-totp.c +++ b/src/widget-totp.c @@ -117,7 +117,7 @@ otputil_widget_totp( return((rc == -1) ? 0 : 1); if ( ((cnf->otp_pass)) && (cnf->argc > optind) ) { - fprintf(stderr, "%s: cannot specify code and use `-p'\n", cnf->prog_name); + fprintf(stderr, "%s: cannot specify code and use `-o'\n", cnf->prog_name); fprintf(stderr, "Try `%s --help' for more information.\n", cnf->prog_name); return(1); }; -- cgit v1.2.3