Merge remote-tracking branch 'fjoncourt/master'
Closes #74 - allows a passphrase to be read from STDIN or from a file descriptor via --fd.
This commit is contained in:
commit
66399fed1a
9
CREDITS
9
CREDITS
@ -51,8 +51,10 @@ Franck Joncourt
|
||||
- Bug fix in the client for resolving hostnames in '-P icmp' mode (fixes
|
||||
issue #64).
|
||||
- Added support for saving fwknop client command line arguments via a new
|
||||
options --save-rc-stanza.
|
||||
option --save-rc-stanza.
|
||||
- Added log module support for the client.
|
||||
- Added the ability to read a passphrase from STDIN and also from a file
|
||||
descriptor via --fd (closes #74).
|
||||
|
||||
Jonathan Schulz
|
||||
- Submitted patches to change HTTP connection type to 'close' for -R mode
|
||||
@ -133,3 +135,8 @@ Ryman
|
||||
- Reported a timing attack bug in the HMAC comparison operation (#85) and
|
||||
suggested a fix derived from yaSSL:
|
||||
http://www.mail-archive.com/debian-bugs-rc@lists.debian.org/msg320402.html
|
||||
|
||||
hlein
|
||||
- Suggested the ability to read a passphrase from STDIN and via a new --fd
|
||||
command line argument (github #74) to allow things like:
|
||||
$ gpg -d passphrasefile.pgp | fwknop -R -n myserver
|
||||
|
||||
@ -58,6 +58,8 @@ enum {
|
||||
KEY_RIJNDAEL_BASE64,
|
||||
KEY_HMAC_BASE64,
|
||||
KEY_HMAC,
|
||||
FD_SET_STDIN,
|
||||
FD_SET,
|
||||
/* Put GPG-related items below the following line */
|
||||
GPG_ENCRYPTION = 0x200,
|
||||
GPG_RECIP_KEY,
|
||||
@ -88,6 +90,7 @@ static struct option cmd_opts[] =
|
||||
{"destination", 1, NULL, 'D'},
|
||||
{"save-args-file", 1, NULL, 'E'},
|
||||
{"encryption-mode", 1, NULL, ENCRYPTION_MODE},
|
||||
{"fd", 1, NULL, FD_SET},
|
||||
{"fw-timeout", 1, NULL, 'f'},
|
||||
{"gpg-encryption", 0, NULL, 'g'},
|
||||
{"gpg-recipient-key", 1, NULL, GPG_RECIP_KEY },
|
||||
@ -125,6 +128,7 @@ static struct option cmd_opts[] =
|
||||
{"show-last", 0, NULL, SHOW_LAST_ARGS},
|
||||
{"source-ip", 0, NULL, 's'},
|
||||
{"source-port", 1, NULL, 'S'},
|
||||
{"stdin", 0, NULL, FD_SET_STDIN},
|
||||
{"test", 0, NULL, 'T'},
|
||||
{"time-offset-plus", 1, NULL, TIME_OFFSET_PLUS},
|
||||
{"time-offset-minus", 1, NULL, TIME_OFFSET_MINUS},
|
||||
|
||||
@ -1659,16 +1659,18 @@ validate_options(fko_cli_options_t *options)
|
||||
static void
|
||||
set_defaults(fko_cli_options_t *options)
|
||||
{
|
||||
options->spa_proto = FKO_DEFAULT_PROTO;
|
||||
options->spa_dst_port = FKO_DEFAULT_PORT;
|
||||
options->fw_timeout = -1;
|
||||
options->spa_proto = FKO_DEFAULT_PROTO;
|
||||
options->spa_dst_port = FKO_DEFAULT_PORT;
|
||||
options->fw_timeout = -1;
|
||||
|
||||
options->key_len = FKO_DEFAULT_KEY_LEN;
|
||||
options->hmac_key_len = FKO_DEFAULT_HMAC_KEY_LEN;
|
||||
options->hmac_type = FKO_HMAC_UNKNOWN; /* updated when HMAC key is used */
|
||||
options->key_len = FKO_DEFAULT_KEY_LEN;
|
||||
options->hmac_key_len = FKO_DEFAULT_HMAC_KEY_LEN;
|
||||
options->hmac_type = FKO_HMAC_UNKNOWN; /* updated when HMAC key is used */
|
||||
|
||||
options->spa_icmp_type = ICMP_ECHOREPLY; /* only used in '-P icmp' mode */
|
||||
options->spa_icmp_code = 0; /* only used in '-P icmp' mode */
|
||||
options->spa_icmp_type = ICMP_ECHOREPLY; /* only used in '-P icmp' mode */
|
||||
options->spa_icmp_code = 0; /* only used in '-P icmp' mode */
|
||||
|
||||
options->input_fd = FD_INVALID;
|
||||
|
||||
return;
|
||||
}
|
||||
@ -2062,6 +2064,13 @@ config_init(fko_cli_options_t *options, int argc, char **argv)
|
||||
case FORCE_SAVE_RC_STANZA:
|
||||
options->force_save_rc_stanza = 1;
|
||||
break;
|
||||
case FD_SET_STDIN:
|
||||
options->input_fd = STDIN_FILENO;
|
||||
break;
|
||||
case FD_SET:
|
||||
options->input_fd = strtol_wrapper(optarg, 0,
|
||||
-1, EXIT_UPON_ERR, &is_err);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
@ -2157,6 +2166,9 @@ usage(void)
|
||||
" line args as the last time it was executed\n"
|
||||
" (args are read from the ~/.fwknop.run file).\n"
|
||||
" -G, --get-key Load an encryption key/password from a file.\n"
|
||||
" --stdin Read the encryption key/password from stdin\n"
|
||||
" --fd Specify the file descriptor to read the\n"
|
||||
" encryption key/password from.\n"
|
||||
" -k, --key-gen Generate SPA Rijndael + HMAC keys.\n"
|
||||
" -K, --key-gen-file Write generated Rijndael + HMAC keys to a\n"
|
||||
" file\n"
|
||||
|
||||
@ -1125,7 +1125,7 @@ get_keys(fko_ctx_t ctx, fko_cli_options_t *options,
|
||||
{
|
||||
if(crypt_op == CRYPT_OP_DECRYPT)
|
||||
{
|
||||
key_tmp = getpasswd("Enter passphrase for secret key: ");
|
||||
key_tmp = getpasswd("Enter passphrase for secret key: ", options->input_fd);
|
||||
if(key_tmp == NULL)
|
||||
{
|
||||
log_msg(LOG_VERBOSITY_ERROR, "[*] getpasswd() key error.");
|
||||
@ -1136,7 +1136,7 @@ get_keys(fko_ctx_t ctx, fko_cli_options_t *options,
|
||||
}
|
||||
else if(strlen(options->gpg_signer_key))
|
||||
{
|
||||
key_tmp = getpasswd("Enter passphrase for signing: ");
|
||||
key_tmp = getpasswd("Enter passphrase for signing: ", options->input_fd);
|
||||
if(key_tmp == NULL)
|
||||
{
|
||||
log_msg(LOG_VERBOSITY_ERROR, "[*] getpasswd() key error.");
|
||||
@ -1149,11 +1149,11 @@ get_keys(fko_ctx_t ctx, fko_cli_options_t *options,
|
||||
else
|
||||
{
|
||||
if(crypt_op == CRYPT_OP_ENCRYPT)
|
||||
key_tmp = getpasswd("Enter encryption key: ");
|
||||
key_tmp = getpasswd("Enter encryption key: ", options->input_fd);
|
||||
else if(crypt_op == CRYPT_OP_DECRYPT)
|
||||
key_tmp = getpasswd("Enter decryption key: ");
|
||||
key_tmp = getpasswd("Enter decryption key: ", options->input_fd);
|
||||
else
|
||||
key_tmp = getpasswd("Enter key: ");
|
||||
key_tmp = getpasswd("Enter key: ", options->input_fd);
|
||||
|
||||
if(key_tmp == NULL)
|
||||
{
|
||||
@ -1197,7 +1197,7 @@ get_keys(fko_ctx_t ctx, fko_cli_options_t *options,
|
||||
}
|
||||
else
|
||||
{
|
||||
hmac_key_tmp = getpasswd("Enter HMAC key: ");
|
||||
hmac_key_tmp = getpasswd("Enter HMAC key: ", options->input_fd);
|
||||
|
||||
if(hmac_key_tmp == NULL)
|
||||
{
|
||||
|
||||
@ -161,6 +161,8 @@ typedef struct fko_cli_options
|
||||
unsigned char save_rc_stanza;
|
||||
unsigned char force_save_rc_stanza;
|
||||
|
||||
int input_fd;
|
||||
|
||||
//char config_file[MAX_PATH_LEN];
|
||||
|
||||
} fko_cli_options_t;
|
||||
|
||||
@ -39,116 +39,164 @@
|
||||
|
||||
#include "fwknop_common.h"
|
||||
#include "getpasswd.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define MAX_PASS_LEN 128 ///< Maximum number of chars an encryption key or a password can contain
|
||||
#define PW_BUFSIZE 128 /*!< Maximum number of chars an encryption key or a password can contain */
|
||||
|
||||
#define PW_BREAK_CHAR 0x03 ///< Ascii code for the Ctrl-C char
|
||||
#define PW_BS_CHAR 0x08 ///< Ascii code for the backspace char
|
||||
#define PW_LF_CHAR 0x0A ///< Ascii code for the \n char
|
||||
#define PW_CR_CHAR 0x0D ///< Ascii code for the \r char
|
||||
#define PW_CLEAR_CHAR 0x15 ///< Ascii code for the Ctrl-U char
|
||||
#define PW_BREAK_CHAR 0x03 /*!< Ascii code for the Ctrl-C char */
|
||||
#define PW_BS_CHAR 0x08 /*!< Ascii code for the backspace char */
|
||||
#define PW_LF_CHAR 0x0A /*!< Ascii code for the \n char */
|
||||
#define PW_CR_CHAR 0x0D /*!< Ascii code for the \r char */
|
||||
#define PW_CLEAR_CHAR 0x15 /*!< Ascii code for the Ctrl-U char */
|
||||
|
||||
#define ARRAY_FIRST_ELT_ADR(t) &((t)[0]) /*!< Macro to get the first element of an array */
|
||||
#define ARRAY_LAST_ELT_ADR(t) &((t)[sizeof(t)-1]) /*!< Macro to get the last element of an array */
|
||||
|
||||
/**
|
||||
* Function for accepting password input from users
|
||||
* @brief Read a password from a stream object
|
||||
*
|
||||
* The functions reads chars from the terminal and store them in a buffer of chars.
|
||||
* @param stream Pointer to a FILE object that identifies an input stream.
|
||||
*
|
||||
* @return The password buffer or NULL if not set
|
||||
*/
|
||||
static char *
|
||||
read_passwd_from_stream(FILE *stream)
|
||||
{
|
||||
static char password[PW_BUFSIZE] = {0};
|
||||
int c;
|
||||
char *ptr;
|
||||
|
||||
ptr = ARRAY_FIRST_ELT_ADR(password);
|
||||
|
||||
#ifdef WIN32
|
||||
while((c = _getch()) != PW_CR_CHAR)
|
||||
#else
|
||||
while( ((c = getc(stream)) != EOF) && (c != PW_LF_CHAR) && (c != PW_BREAK_CHAR) )
|
||||
#endif
|
||||
{
|
||||
/* Handle a backspace without backing up too far. */
|
||||
if (c == PW_BS_CHAR)
|
||||
{
|
||||
if (ptr != ARRAY_FIRST_ELT_ADR(password))
|
||||
ptr--;
|
||||
}
|
||||
|
||||
/* Handle a Ctrl-U to clear the password entry and start over */
|
||||
else if (c == PW_CLEAR_CHAR)
|
||||
ptr = ARRAY_FIRST_ELT_ADR(password);
|
||||
|
||||
/* Fill in the password buffer until it reaches the last -1 char.
|
||||
* The last char is used to NULL terminate the string. */
|
||||
else if (ptr < ARRAY_LAST_ELT_ADR(password))
|
||||
{
|
||||
*ptr++ = c;
|
||||
}
|
||||
|
||||
/* Discard char */
|
||||
else;
|
||||
}
|
||||
|
||||
/* A CTRL-C char has been detected, we discard the password */
|
||||
if (c == PW_BREAK_CHAR)
|
||||
password[0] = '\0';
|
||||
|
||||
/* Otherwise we NULL terminate the string here. Overflows are handled
|
||||
* previously, so we can add the char without worrying */
|
||||
else
|
||||
*ptr = '\0';
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function for accepting password input from users
|
||||
*
|
||||
* The functions reads chars from a buffered stream and store them in a buffer of
|
||||
* chars. If a file descriptor is supplied then, the password is read from
|
||||
* the associated stream, otherwise a new buffered stream is created and a
|
||||
* prompt is displayed to the user.
|
||||
*
|
||||
* @param prompt String displayed on the terminal to prompt the user for a
|
||||
* password or an encryption key
|
||||
* @param fd File descriptor to use to read the pasword from. If fd is set
|
||||
* to FD_INVALID, then a new stream is opened.
|
||||
*
|
||||
* @return NULL if a problem occured or the user killed the terminal (Ctrl-C)\n
|
||||
* otherwise the password - empty password is accepted.
|
||||
*/
|
||||
char*
|
||||
getpasswd(
|
||||
const char *prompt) ///< String displayed on the terminal to prompt the user for a password or an encryption key
|
||||
getpasswd(const char *prompt, int fd)
|
||||
{
|
||||
static char pwbuf[MAX_KEY_LEN + 1] = {0};
|
||||
char *ptr;
|
||||
int c;
|
||||
|
||||
char *ptr;
|
||||
|
||||
#ifndef WIN32
|
||||
FILE *fp;
|
||||
sigset_t sig, old_sig;
|
||||
struct termios ts, old_ts;
|
||||
FILE *fp;
|
||||
|
||||
if((fp = fopen(ctermid(NULL), "r+")) == NULL)
|
||||
return(NULL);
|
||||
|
||||
setbuf(fp, NULL);
|
||||
|
||||
/* Setup blocks for SIGINT and SIGTSTP and save the original signal
|
||||
* mask.
|
||||
*/
|
||||
sigemptyset(&sig);
|
||||
sigaddset(&sig, SIGINT);
|
||||
sigaddset(&sig, SIGTSTP);
|
||||
sigprocmask(SIG_BLOCK, &sig, &old_sig);
|
||||
|
||||
/*
|
||||
* Save current tty state for later restoration after we :
|
||||
* - disable echo of characters to the tty
|
||||
* - disable signal generation
|
||||
* - disable cannonical mode (input read line by line mode)
|
||||
*/
|
||||
tcgetattr(fileno(fp), &ts);
|
||||
old_ts = ts;
|
||||
ts.c_lflag &= ~(ECHO | ICANON | ISIG);
|
||||
tcsetattr(fileno(fp), TCSAFLUSH, &ts);
|
||||
|
||||
fputs(prompt, fp);
|
||||
#endif
|
||||
|
||||
/* Read in the password.
|
||||
*/
|
||||
ptr = pwbuf;
|
||||
|
||||
#ifdef WIN32
|
||||
_cputs(prompt);
|
||||
while((c = _getch()) != PW_CR_CHAR)
|
||||
#else
|
||||
while( ((c = getc(fp)) != EOF) && (c != PW_LF_CHAR) && (c != PW_BREAK_CHAR) )
|
||||
#endif
|
||||
/* If a valid file descriptor is supplied, we try to open a stream from it */
|
||||
if (FD_IS_VALID(fd))
|
||||
{
|
||||
/* Handle a backspace without backing up too far.
|
||||
*/
|
||||
if (c == PW_BS_CHAR)
|
||||
fp = fdopen(fd, "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
if (ptr != pwbuf)
|
||||
ptr--;
|
||||
log_msg(LOG_VERBOSITY_ERROR, "getpasswd() - "
|
||||
"Unable to create a stream from the file descriptor : %s",
|
||||
strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Handle a Ctrl-U to clear the password entry and start over
|
||||
*/
|
||||
else if (c == PW_CLEAR_CHAR)
|
||||
ptr = pwbuf;
|
||||
|
||||
/* Store data in the buffer and check for a possible overflow
|
||||
*/
|
||||
else if (ptr < &pwbuf[MAX_PASS_LEN])
|
||||
*ptr++ = c;
|
||||
}
|
||||
|
||||
/* If a Ctrl-C char has been detected we set an error
|
||||
*/
|
||||
if (c == PW_BREAK_CHAR)
|
||||
ptr = NULL;
|
||||
|
||||
/* Otherwise we make the password as a NULL terminated string and point
|
||||
* to the start of the password in order to be returned by the function.
|
||||
*/
|
||||
/* Otherwise we are going to open a new stream */
|
||||
else
|
||||
{
|
||||
*ptr = '\0';
|
||||
ptr = pwbuf;
|
||||
if((fp = fopen(ctermid(NULL), "r+")) == NULL)
|
||||
return(NULL);
|
||||
|
||||
setbuf(fp, NULL);
|
||||
|
||||
/* Setup blocks for SIGINT and SIGTSTP and save the original signal
|
||||
* mask.
|
||||
*/
|
||||
sigemptyset(&sig);
|
||||
sigaddset(&sig, SIGINT);
|
||||
sigaddset(&sig, SIGTSTP);
|
||||
sigprocmask(SIG_BLOCK, &sig, &old_sig);
|
||||
|
||||
/*
|
||||
* Save current tty state for later restoration after we :
|
||||
* - disable echo of characters to the tty
|
||||
* - disable signal generation
|
||||
* - disable cannonical mode (input read line by line mode)
|
||||
*/
|
||||
tcgetattr(fileno(fp), &ts);
|
||||
old_ts = ts;
|
||||
ts.c_lflag &= ~(ECHO | ICANON | ISIG);
|
||||
tcsetattr(fileno(fp), TCSAFLUSH, &ts);
|
||||
|
||||
fputs(prompt, fp);
|
||||
}
|
||||
#else
|
||||
_cputs(prompt);
|
||||
#endif
|
||||
|
||||
/* Read the password */
|
||||
ptr = read_passwd_from_stream(fp);
|
||||
|
||||
#ifndef WIN32
|
||||
/* we can go ahead and echo out a newline.
|
||||
*/
|
||||
putc(PW_LF_CHAR, fp);
|
||||
|
||||
/* Restore our tty state and signal handlers.
|
||||
*/
|
||||
tcsetattr(fileno(fp), TCSAFLUSH, &old_ts);
|
||||
sigprocmask(SIG_BLOCK, &old_sig, NULL);
|
||||
/* If we used a new buffered stream */
|
||||
if (FD_IS_VALID(fd) == 0)
|
||||
{
|
||||
/* we can go ahead and echo out a newline.
|
||||
*/
|
||||
putc(PW_LF_CHAR, fp);
|
||||
|
||||
/* Restore our tty state and signal handlers.
|
||||
*/
|
||||
tcsetattr(fileno(fp), TCSAFLUSH, &old_ts);
|
||||
sigprocmask(SIG_BLOCK, &old_sig, NULL);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
#else
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
/* Prototypes
|
||||
*/
|
||||
char* getpasswd(const char *prompt);
|
||||
char* getpasswd(const char *prompt, int fd);
|
||||
|
||||
/* This can be used to acquire an encryption key or HMAC key
|
||||
*/
|
||||
|
||||
@ -48,6 +48,9 @@
|
||||
|
||||
#define PROTOCOL_BUFSIZE 16 /*!< Maximum number of chars for a protocol string (TCP for example) */
|
||||
|
||||
#define FD_INVALID -1
|
||||
#define FD_IS_VALID(x) ((x)>=0)
|
||||
|
||||
/* Prototypes
|
||||
*/
|
||||
void hex_dump(const unsigned char *data, const int size);
|
||||
|
||||
@ -16,6 +16,7 @@ use strict;
|
||||
#==================== config =====================
|
||||
my $logfile = 'test.log';
|
||||
our $local_key_file = 'local_spa.key';
|
||||
our $local_spa_key = 'fwknoptest';
|
||||
our $local_hmac_key_file = 'local_hmac_spa.key';
|
||||
my $output_dir = 'output';
|
||||
our $conf_dir = 'conf';
|
||||
|
||||
@ -21,7 +21,6 @@
|
||||
"-O $conf_dir/override_fwknopd.conf --dump-config",
|
||||
'fatal' => $NO
|
||||
},
|
||||
|
||||
{
|
||||
'category' => 'basic operations',
|
||||
'subcategory' => 'client',
|
||||
@ -700,5 +699,14 @@
|
||||
'cmdline' => $default_client_args . " --test --encryption-mode badmode",
|
||||
'positive_output_matches' => [qr/Invalid\sencryption\smode:\sbadmode/],
|
||||
'fatal' => $NO
|
||||
},
|
||||
},
|
||||
{
|
||||
'category' => 'basic operations',
|
||||
'subcategory' => 'client',
|
||||
'detail' => 'bad file descriptor',
|
||||
'function' => \&generic_exec,
|
||||
'cmdline' => $default_client_args . " --test --fd -1",
|
||||
'positive_output_matches' => [qr/Value\s.*out\sof\srange/],
|
||||
'fatal' => $NO
|
||||
},
|
||||
);
|
||||
|
||||
@ -11,6 +11,32 @@
|
||||
'fw_rule_removed' => $NEW_RULE_REMOVED,
|
||||
'fatal' => $NO
|
||||
},
|
||||
{
|
||||
'category' => 'Rijndael',
|
||||
'subcategory' => 'client+server',
|
||||
'detail' => 'use of encryption key with fd 0',
|
||||
'function' => \&spa_cycle,
|
||||
'cmdline' => "echo $local_spa_key | $default_client_args_no_get_key " .
|
||||
"--fd 0",
|
||||
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
|
||||
"$fwknopdCmd $default_server_conf_args $intf_str",
|
||||
'fw_rule_created' => $NEW_RULE_REQUIRED,
|
||||
'fw_rule_removed' => $NEW_RULE_REMOVED,
|
||||
'fatal' => $NO
|
||||
},
|
||||
{
|
||||
'category' => 'Rijndael',
|
||||
'subcategory' => 'client+server',
|
||||
'detail' => 'use of encryption key with stdin',
|
||||
'function' => \&spa_cycle,
|
||||
'cmdline' => "echo $local_spa_key | $default_client_args_no_get_key " .
|
||||
"--stdin",
|
||||
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
|
||||
"$fwknopdCmd $default_server_conf_args $intf_str",
|
||||
'fw_rule_created' => $NEW_RULE_REQUIRED,
|
||||
'fw_rule_removed' => $NEW_RULE_REMOVED,
|
||||
'fatal' => $NO
|
||||
},
|
||||
{
|
||||
'category' => 'Rijndael',
|
||||
'subcategory' => 'client+server',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user