diff --git a/client/cmd_opts.h b/client/cmd_opts.h index ab2f8f4a..dbfd57cb 100644 --- a/client/cmd_opts.h +++ b/client/cmd_opts.h @@ -43,6 +43,7 @@ enum { TIME_OFFSET_PLUS, NO_SAVE_ARGS, SHOW_LAST_ARGS, + RC_FILE_PATH, RESOLVE_URL, /* Put GPG-related items below the following line */ GPG_ENCRYPTION = 0x200, @@ -56,7 +57,7 @@ enum { /* Our getopt_long options string. */ -#define GETOPTS_OPTION_STRING "a:A:bB:C:D:f:gG:hH:lm:M:n:N:p:P:Q:rRsS:Tu:U:vV" +#define GETOPTS_OPTION_STRING "a:A:bB:C:D:f:gG:hH:kK:lm:M:n:N:p:P:Q:rRsS:Tu:U:vV" /* Our program command-line options... */ @@ -80,6 +81,8 @@ static struct option cmd_opts[] = {"get-key", 1, NULL, 'G'}, {"help", 0, NULL, 'h'}, {"http-proxy", 1, NULL, 'H'}, + {"key-gen", 0, NULL, 'k'}, + {"key-gen-file", 1, NULL, 'K'}, {"last-cmd", 0, NULL, 'l'}, {"nat-access", 1, NULL, 'N'}, {"named-config", 1, NULL, 'n'}, @@ -89,6 +92,7 @@ static struct option cmd_opts[] = {"server-port", 1, NULL, 'p'}, {"server-proto", 1, NULL, 'P'}, {"spoof-src", 1, NULL, 'Q'}, + {"rc-file", 1, NULL, RC_FILE_PATH}, {"rand-port", 0, NULL, 'r'}, {"resolve-ip-http", 0, NULL, 'R'}, {"resolve-url", 1, NULL, RESOLVE_URL}, diff --git a/client/config_init.c b/client/config_init.c index 2632abd8..744177ad 100644 --- a/client/config_init.c +++ b/client/config_init.c @@ -367,6 +367,39 @@ parse_rc_param(fko_cli_options_t *options, const char *var, char * val) if(val[0] == 'y' || val[0] == 'Y') options->rand_port = 1; } + /* Rijndael key */ + else if(CONF_VAR_IS(var, "KEY")) + { + strlcpy(options->key, val, MAX_KEY_LEN); + options->have_key = 1; + } + /* Rijndael key (base-64 encoded) */ + else if(CONF_VAR_IS(var, "KEY_BASE64")) + { + if (! is_base64((unsigned char *) val, strlen(val))) + { + fprintf(stderr, + "KEY_BASE64 argument '%s' doesn't look like base64-encoded data.\n", + val); + exit(EXIT_FAILURE); + } + strlcpy(options->key_base64, val, MAX_KEY_LEN); + options->have_base64_key = 1; + } + /* HMAC key */ + else if(CONF_VAR_IS(var, "HMAC_KEY_BASE64")) + { + if (! is_base64((unsigned char *) val, strlen(val))) + { + fprintf(stderr, + "HMAC_KEY_BASE64 argument '%s' doesn't look like base64-encoded data.\n", + val); + exit(EXIT_FAILURE); + } + strlcpy(options->hmac_key_base64, val, MAX_KEY_LEN); + options->have_hmac_base64_key = 1; + } + /* Key file */ else if(CONF_VAR_IS(var, "KEY_FILE")) { @@ -437,38 +470,45 @@ process_rc(fko_cli_options_t *options) char *ndx, *emark, *homedir; -#ifdef WIN32 - homedir = getenv("USERPROFILE"); -#else - homedir = getenv("HOME"); -#endif - - if(homedir == NULL) - { - fprintf(stderr, "Warning: Unable to determine HOME directory.\n" - " No .fwknoprc file processed.\n"); - return; - } - memset(rcfile, 0x0, MAX_PATH_LEN); - strlcpy(rcfile, homedir, MAX_PATH_LEN); - - rcf_offset = strlen(rcfile); - - /* Sanity check the path to .fwknoprc. - * The preceeding path plus the path separator and '.fwknoprc' = 11 - * cannot exceed MAX_PATH_LEN. - */ - if(rcf_offset > (MAX_PATH_LEN - 11)) + if(options->rc_file[0] == 0x0) { - fprintf(stderr, "Warning: Path to .fwknoprc file is too long.\n" - " No .fwknoprc file processed.\n"); - return; - } +#ifdef WIN32 + homedir = getenv("USERPROFILE"); +#else + homedir = getenv("HOME"); +#endif - rcfile[rcf_offset] = PATH_SEP; - strlcat(rcfile, ".fwknoprc", MAX_PATH_LEN); + if(homedir == NULL) + { + fprintf(stderr, "Warning: Unable to determine HOME directory.\n" + " No .fwknoprc file processed.\n"); + return; + } + + strlcpy(rcfile, homedir, MAX_PATH_LEN); + + rcf_offset = strlen(rcfile); + + /* Sanity check the path to .fwknoprc. + * The preceeding path plus the path separator and '.fwknoprc' = 11 + * cannot exceed MAX_PATH_LEN. + */ + if(rcf_offset > (MAX_PATH_LEN - 11)) + { + fprintf(stderr, "Warning: Path to .fwknoprc file is too long.\n" + " No .fwknoprc file processed.\n"); + return; + } + + rcfile[rcf_offset] = PATH_SEP; + strlcat(rcfile, ".fwknoprc", MAX_PATH_LEN); + } + else + { + strlcpy(rcfile, options->rc_file, MAX_PATH_LEN); + } /* Open the rc file for reading, if it does not exist, then create * an initial .fwknoprc file with defaults and go on. @@ -545,6 +585,13 @@ process_rc(fko_cli_options_t *options) if((ndx = strrchr(var, ':')) != NULL) *ndx = '\0'; + /* Even though sscanf should automatically add a terminating + * NULL byte, an assumption is made that the input arrays are + * big enough, so we'll force a terminating NULL byte regardless + */ + var[MAX_LINE_LEN-1] = 0x0; + val[MAX_LINE_LEN-1] = 0x0; + if(options->verbose > 3) fprintf(stderr, "RC FILE: %s, LINE: %s\tVar: %s, Val: '%s'\n", @@ -590,6 +637,7 @@ validate_options(fko_cli_options_t *options) * the version, and must use one of [-s|-R|-a]. */ if(!options->test + && !options->key_gen && !options->version && !options->show_last_command && !options->run_last_command) @@ -677,7 +725,7 @@ config_init(fko_cli_options_t *options, int argc, char **argv) */ set_defaults(options); - /* First pass over cmd_line args to see if a named-stanza in the + /* First pass over cmd_line args to see if a named-stanza in the * rc file is used. */ while ((cmd_arg = getopt_long(argc, argv, @@ -690,6 +738,9 @@ config_init(fko_cli_options_t *options, int argc, char **argv) options->no_save_args = 1; strlcpy(options->use_rc_stanza, optarg, MAX_LINE_LEN); break; + case RC_FILE_PATH: + strlcpy(options->rc_file, optarg, MAX_PATH_LEN); + break; case 'v': options->verbose++; break; @@ -747,6 +798,9 @@ config_init(fko_cli_options_t *options, int argc, char **argv) options->spa_proto = FKO_PROTO_HTTP; strlcpy(options->http_proxy, optarg, MAX_PATH_LEN); break; + case 'k': + options->key_gen = 1; + break; case 'l': options->run_last_command = 1; break; @@ -798,6 +852,9 @@ config_init(fko_cli_options_t *options, int argc, char **argv) case 'Q': strlcpy(options->spoof_ip_src_str, optarg, MAX_IPV4_STR_LEN); break; + case RC_FILE_PATH: + strlcpy(options->rc_file, optarg, MAX_PATH_LEN); + break; case 'r': options->rand_port = 1; break; diff --git a/client/fwknop.c b/client/fwknop.c index 52734486..fe6d2ef0 100644 --- a/client/fwknop.c +++ b/client/fwknop.c @@ -36,7 +36,7 @@ /* prototypes */ -static char * get_user_pw(fko_cli_options_t *options, const int crypt_op); +static char *get_user_pw(fko_cli_options_t *options, const int crypt_op); static void display_ctx(fko_ctx_t ctx); static void errmsg(const char *msg, const int err); static void show_last_command(void); @@ -79,9 +79,20 @@ main(int argc, char **argv) return(EXIT_FAILURE); } + /* Generate Rijndael + HMAC keys from /dev/random (base64 + * encoded) and exit. + */ + if(options.key_gen) + { + fko_key_gen(options.key_base64, options.hmac_key_base64); + printf("KEY_BASE64: %s\nHMAC_KEY_BASE64: %s\n", options.key_base64, options.hmac_key_base64); + return(EXIT_SUCCESS); + } + /* Display version info and exit. */ - if (options.version) { + if(options.version) + { fko_get_version(ctx, &version); fprintf(stdout, "fwknop client %s, FKO protocol version %s\n", @@ -738,6 +749,15 @@ get_user_pw(fko_cli_options_t *options, const int crypt_op) { pw_ptr = getpasswd_file(options->get_key_file, options->spa_server_str); } + else if (options->have_key) + { + pw_ptr = options->key; + } + else if (options->have_base64_key) + { + fko_base64_decode(options->key_base64, (unsigned char *) options->key); + pw_ptr = options->key; + } else if (options->use_gpg) { if(crypt_op == CRYPT_OP_DECRYPT) diff --git a/client/fwknop_common.h b/client/fwknop_common.h index 4e494aa7..83a46c16 100644 --- a/client/fwknop_common.h +++ b/client/fwknop_common.h @@ -55,7 +55,7 @@ #define TIME_OFFSET_DAYS 86400 /* For resolving the allow IP via HTTP and sending SPA packets over - * HTTP - http://www.whatismyip.com/automation/n09230945.asp + * HTTP - http://www.whatismyip.com/automation/n09230945.asp #define HTTP_RESOLVE_HOST "www.whatismyip.com" #define HTTP_RESOLVE_URL "/automation/n09230945.asp" * --DSS Note: The whatismyip.com site has some usage restrictions. @@ -70,6 +70,7 @@ #define MAX_HOSTNAME_LEN 70 #define MAX_URL_HOST_LEN 256 #define MAX_URL_PATH_LEN 1024 +#define MAX_KEY_LEN 128 /* fwknop client configuration parameters and values */ @@ -77,6 +78,8 @@ typedef struct fko_cli_options { char config_file[MAX_PATH_LEN]; char access_str[MAX_PATH_LEN]; + char rc_file[MAX_PATH_LEN]; + char key_gen_file[MAX_PATH_LEN]; char server_command[MAX_LINE_LEN]; char get_key_file[MAX_PATH_LEN]; char save_packet_file[MAX_PATH_LEN]; @@ -93,6 +96,15 @@ typedef struct fko_cli_options char gpg_signer_key[MAX_GPG_KEY_ID]; char gpg_home_dir[MAX_PATH_LEN]; + /* Encryption keys read from a .fwknoprc stanza + */ + char key[MAX_KEY_LEN+1]; + char key_base64[MAX_KEY_LEN+1]; + char hmac_key_base64[MAX_KEY_LEN+1]; + int have_key; + int have_base64_key; + int have_hmac_base64_key; + /* NAT access */ char nat_access_str[MAX_PATH_LEN]; @@ -128,6 +140,7 @@ typedef struct fko_cli_options int time_offset_plus; int time_offset_minus; int fw_timeout; + int key_gen; char use_rc_stanza[MAX_LINE_LEN]; unsigned char got_named_stanza; diff --git a/client/getpasswd.c b/client/getpasswd.c index e1cec86d..2d51bf6d 100644 --- a/client/getpasswd.c +++ b/client/getpasswd.c @@ -40,14 +40,12 @@ #include "fwknop_common.h" #include "getpasswd.h" -#define MAX_PASS_LEN 128 - /* Function for accepting password input from users */ char* getpasswd(const char *prompt) { - static char pwbuf[MAX_PASS_LEN + 1] = {0}; + static char pwbuf[MAX_KEY_LEN + 1] = {0}; char *ptr; int c; @@ -109,7 +107,7 @@ getpasswd(const char *prompt) while((c = getc(fp)) != EOF && c != '\n') { #endif - if(ptr < &pwbuf[MAX_PASS_LEN]) + if(ptr < &pwbuf[MAX_KEY_LEN]) *ptr++ = c; } @@ -146,7 +144,7 @@ getpasswd_file(const char *pw_file, const char *server_str) FILE *pwfile_ptr; unsigned int numLines = 0, i = 0, found_dst; - static char pwbuf[MAX_PASS_LEN + 1] = {0}; + static char pwbuf[MAX_KEY_LEN + 1] = {0}; char conf_line_buf[MAX_LINE_LEN] = {0}; char tmp_char_buf[MAX_LINE_LEN] = {0}; char *lptr; diff --git a/client/utils.c b/client/utils.c index 5a60528b..61fa9a8e 100644 --- a/client/utils.c +++ b/client/utils.c @@ -28,8 +28,7 @@ * ***************************************************************************** */ -#include -#include +#include "fwknop_common.h" #include "utils.h" /* Generic hex dump function. @@ -69,5 +68,25 @@ hex_dump(const unsigned char *data, const int size) } } +/* Determine if a buffer contains only characters from the base64 + * encoding set +*/ +int +is_base64(const unsigned char *buf, const unsigned short int len) +{ + unsigned short int i; + int rv = 1; + + for(i=0; iverbose > 3) @@ -888,6 +902,42 @@ parse_access_file(fko_srv_options_t *opts) } add_acc_string(&(curr_acc->key), val); } + else if(CONF_VAR_IS(var, "KEY_BASE64")) + { + if(strcasecmp(val, "__CHANGEME__") == 0) + { + fprintf(stderr, + "[*] KEY_BASE64 value is not properly set in stanza source '%s' in access file: '%s'\n", + curr_acc->source, opts->config[CONF_ACCESS_FILE]); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + if (! is_base64((unsigned char *) val, strlen(val))) + { + fprintf(stderr, + "KEY_BASE64 argument '%s' doesn't look like base64-encoded data.\n", + val); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + add_acc_string(&(curr_acc->key_base64), val); + } + else if(CONF_VAR_IS(var, "HMAC_KEY_BASE64")) + { + if(strcasecmp(val, "__CHANGEME__") == 0) + { + fprintf(stderr, + "[*] HMAC_KEY_BASE64 value is not properly set in stanza source '%s' in access file: '%s'\n", + curr_acc->source, opts->config[CONF_ACCESS_FILE]); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + if (! is_base64((unsigned char *) val, strlen(val))) + { + fprintf(stderr, + "HMAC_KEY_BASE64 argument '%s' doesn't look like base64-encoded data.\n", + val); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + add_acc_string(&(curr_acc->hmac_key_base64), val); + } else if(CONF_VAR_IS(var, "FW_ACCESS_TIMEOUT")) { add_acc_int(&(curr_acc->fw_access_timeout), val); diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 36612276..f82d6a64 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -267,6 +267,8 @@ typedef struct acc_stanza char *restrict_ports; acc_port_list_t *rport_list; char *key; + char *key_base64; + char *hmac_key_base64; int fw_access_timeout; unsigned char enable_cmd_exec; char *cmd_exec_user; diff --git a/server/incoming_spa.c b/server/incoming_spa.c index 23832191..7cf1ab14 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -242,8 +242,25 @@ incoming_spa(fko_srv_options_t *opts) if(enc_type == FKO_ENCRYPTION_RIJNDAEL) { if(acc->key != NULL) + { res = fko_new_with_data(&ctx, (char *)spa_pkt->packet_data, acc->key, acc->encryption_mode); + } + else if (acc->key_base64 != NULL) + { + if ((acc->key = strdup(acc->key_base64)) == NULL) + { + log_msg(LOG_ERR, + "Fatal memory allocation error copying key_base64 -> key: %s", + acc->key_base64 + ); + exit(EXIT_FAILURE); + } + memset(acc->key, 0x0, strlen(acc->key_base64)); + fko_base64_decode(acc->key_base64, (unsigned char *) acc->key); + res = fko_new_with_data(&ctx, + (char *)spa_pkt->packet_data, acc->key, acc->encryption_mode); + } else { log_msg(LOG_ERR, diff --git a/server/utils.c b/server/utils.c index e145ba89..1633b9fc 100644 --- a/server/utils.c +++ b/server/utils.c @@ -164,7 +164,7 @@ is_valid_dir(const char *path) * encoding set */ int -is_base64(const unsigned char *buf, unsigned short int len) +is_base64(const unsigned char *buf, const unsigned short int len) { unsigned short int i; int rv = 1; diff --git a/server/utils.h b/server/utils.h index 09584e1f..42c5966c 100644 --- a/server/utils.h +++ b/server/utils.h @@ -60,7 +60,7 @@ */ void hex_dump(const unsigned char *data, const int size); char* dump_ctx(fko_ctx_t ctx); -int is_base64(const unsigned char *buf, unsigned short int len); +int is_base64(const unsigned char *buf, const unsigned short int len); int is_valid_dir(const char *path); size_t strlcat(char *dst, const char *src, size_t siz); diff --git a/test/conf/base64_key_access.conf b/test/conf/base64_key_access.conf new file mode 100644 index 00000000..4a52f440 --- /dev/null +++ b/test/conf/base64_key_access.conf @@ -0,0 +1,3 @@ +SOURCE: ANY; +KEY_BASE64: w8KMBQlKf4UCARNQmi25DPxw4xAUaRs21nf8nbRNzUo=; +FW_ACCESS_TIMEOUT: 3; diff --git a/test/conf/fwknoprc_with_default_base64_key b/test/conf/fwknoprc_with_default_base64_key new file mode 100644 index 00000000..1566caf7 --- /dev/null +++ b/test/conf/fwknoprc_with_default_base64_key @@ -0,0 +1,71 @@ +# .fwknoprc +############################################################################## +# +# Firewall Knock Operator (fwknop) client rc file. +# +# This file contains user-specific fwknop client configuration default +# and named parameter sets for specific invocations of the fwknop client. +# +# Each section (or stanza) is identified and started by a line in this +# file that contains a single identifier surrounded by square brackets. +# +# The parameters within the stanza typicaly match corresponding client +# command-line parameters. +# +# The first one should always be `[default]' as it defines the global +# default settings for the user. These override the program defaults +# for these parameter. If a named stanza is used, its entries will +# override any of the default. Command-line options will trump them +# all. +# +# Subsequent stanzas will have only the overriding and destination +# specific parameters. +# +# Lines starting with `#' and empty lines are ignored. +# +# See the fwknop.8 man page for a complete list of valid parameters +# and their values. +# +############################################################################## +# +# We start with the 'default' stanza. Uncomment and edit for your +# preferences. The client will use its build-in default for those items +# that are commented out. +# +[default] + +#DIGEST_TYPE sha256 +#FW_TIMEOUT 30 +#SPA_SERVER_PORT 62201 +#SPA_SERVER_PROTO udp +#ALLOW_IP +#SPOOF_USER +#SPOOF_SOURCE_IP +#TIME_OFFSET 0 +#USE_GPG N +#GPG_HOMEDIR /path/to/.gnupg +#GPG_SIGNER +#GPG_RECIPIENT +KEY_BASE64 w8KMBQlKf4UCARNQmi25DPxw4xAUaRs21nf8nbRNzUo= + +# User-provided named stanzas: + +# Example for a destination server of 192.168.1.20 to open access to +# SSH for an IP that is resoved exteranlly, and one with a NAT request +# for a specific source IP that maps port 8088 on the server +# to port 88 on 192.168.1.55 with timeout. +# +#[myssh] +#SPA_SERVER 192.168.1.20 +#ACCESS tcp/22 +#ALLOW_IP resolve +# +#[mynatreq] +#SPA_SERVER 192.168.1.20 +#ACCESS tcp/8088 +#ALLOW_IP 10.21.2.6 +#NAT_ACCESS 192.168.1.55,88 +#CLIENT_TIMEOUT 60 +# + +###EOF### diff --git a/test/conf/fwknoprc_with_default_key b/test/conf/fwknoprc_with_default_key new file mode 100644 index 00000000..e823f0b3 --- /dev/null +++ b/test/conf/fwknoprc_with_default_key @@ -0,0 +1,71 @@ +# .fwknoprc +############################################################################## +# +# Firewall Knock Operator (fwknop) client rc file. +# +# This file contains user-specific fwknop client configuration default +# and named parameter sets for specific invocations of the fwknop client. +# +# Each section (or stanza) is identified and started by a line in this +# file that contains a single identifier surrounded by square brackets. +# +# The parameters within the stanza typicaly match corresponding client +# command-line parameters. +# +# The first one should always be `[default]' as it defines the global +# default settings for the user. These override the program defaults +# for these parameter. If a named stanza is used, its entries will +# override any of the default. Command-line options will trump them +# all. +# +# Subsequent stanzas will have only the overriding and destination +# specific parameters. +# +# Lines starting with `#' and empty lines are ignored. +# +# See the fwknop.8 man page for a complete list of valid parameters +# and their values. +# +############################################################################## +# +# We start with the 'default' stanza. Uncomment and edit for your +# preferences. The client will use its build-in default for those items +# that are commented out. +# +[default] + +#DIGEST_TYPE sha256 +#FW_TIMEOUT 30 +#SPA_SERVER_PORT 62201 +#SPA_SERVER_PROTO udp +#ALLOW_IP +#SPOOF_USER +#SPOOF_SOURCE_IP +#TIME_OFFSET 0 +#USE_GPG N +#GPG_HOMEDIR /path/to/.gnupg +#GPG_SIGNER +#GPG_RECIPIENT +KEY fwknoptest + +# User-provided named stanzas: + +# Example for a destination server of 192.168.1.20 to open access to +# SSH for an IP that is resoved exteranlly, and one with a NAT request +# for a specific source IP that maps port 8088 on the server +# to port 88 on 192.168.1.55 with timeout. +# +#[myssh] +#SPA_SERVER 192.168.1.20 +#ACCESS tcp/22 +#ALLOW_IP resolve +# +#[mynatreq] +#SPA_SERVER 192.168.1.20 +#ACCESS tcp/8088 +#ALLOW_IP 10.21.2.6 +#NAT_ACCESS 192.168.1.55,88 +#CLIENT_TIMEOUT 60 +# + +###EOF### diff --git a/test/conf/fwknoprc_with_named_key b/test/conf/fwknoprc_with_named_key new file mode 100644 index 00000000..5bc12f33 --- /dev/null +++ b/test/conf/fwknoprc_with_named_key @@ -0,0 +1,73 @@ +# .fwknoprc +############################################################################## +# +# Firewall Knock Operator (fwknop) client rc file. +# +# This file contains user-specific fwknop client configuration default +# and named parameter sets for specific invocations of the fwknop client. +# +# Each section (or stanza) is identified and started by a line in this +# file that contains a single identifier surrounded by square brackets. +# +# The parameters within the stanza typicaly match corresponding client +# command-line parameters. +# +# The first one should always be `[default]' as it defines the global +# default settings for the user. These override the program defaults +# for these parameter. If a named stanza is used, its entries will +# override any of the default. Command-line options will trump them +# all. +# +# Subsequent stanzas will have only the overriding and destination +# specific parameters. +# +# Lines starting with `#' and empty lines are ignored. +# +# See the fwknop.8 man page for a complete list of valid parameters +# and their values. +# +############################################################################## +# +# We start with the 'default' stanza. Uncomment and edit for your +# preferences. The client will use its build-in default for those items +# that are commented out. +# +[default] + +#DIGEST_TYPE sha256 +#FW_TIMEOUT 30 +#SPA_SERVER_PORT 62201 +#SPA_SERVER_PROTO udp +#ALLOW_IP +#SPOOF_USER +#SPOOF_SOURCE_IP +#TIME_OFFSET 0 +#USE_GPG N +#GPG_HOMEDIR /path/to/.gnupg +#GPG_SIGNER +#GPG_RECIPIENT + +# User-provided named stanzas: + +# Example for a destination server of 192.168.1.20 to open access to +# SSH for an IP that is resoved exteranlly, and one with a NAT request +# for a specific source IP that maps port 8088 on the server +# to port 88 on 192.168.1.55 with timeout. +# +#[myssh] +#SPA_SERVER 192.168.1.20 +#ACCESS tcp/22 +#ALLOW_IP resolve +# +#[mynatreq] +#SPA_SERVER 192.168.1.20 +#ACCESS tcp/8088 +#ALLOW_IP 10.21.2.6 +#NAT_ACCESS 192.168.1.55,88 +#CLIENT_TIMEOUT 60 +# + +[testssh] +KEY fwknoptest; + +###EOF### diff --git a/test/test-fwknop.pl b/test/test-fwknop.pl index ef0ec8ca..9895fcb9 100755 --- a/test/test-fwknop.pl +++ b/test/test-fwknop.pl @@ -23,6 +23,7 @@ my $gpg_client_home_dir = "$conf_dir/client-gpg"; my $nat_conf = "$conf_dir/nat_fwknopd.conf"; my $default_conf = "$conf_dir/default_fwknopd.conf"; my $default_access_conf = "$conf_dir/default_access.conf"; +my $base64_key_access_conf = "$conf_dir/base64_key_access.conf"; my $ecb_mode_access_conf = "$conf_dir/ecb_mode_access.conf"; my $ctr_mode_access_conf = "$conf_dir/ctr_mode_access.conf"; my $cfb_mode_access_conf = "$conf_dir/cfb_mode_access.conf"; @@ -36,6 +37,10 @@ my $force_nat_access_conf = "$conf_dir/force_nat_access.conf"; my $gpg_access_conf = "$conf_dir/gpg_access.conf"; my $default_digest_file = "$run_dir/digest.cache"; my $default_pid_file = "$run_dir/fwknopd.pid"; +my $tmp_rc_file = "$run_dir/fwknoprc"; +my $rc_file_default_key = "$conf_dir/fwknoprc_with_default_key"; +my $rc_file_default_base64_key = "$conf_dir/fwknoprc_with_default_base64_key"; +my $rc_file_named_key = "$conf_dir/fwknoprc_with_named_key"; my $open_ports_access_conf = "$conf_dir/open_ports_access.conf"; my $multi_gpg_access_conf = "$conf_dir/multi_gpg_access.conf"; my $multi_stanzas_access_conf = "$conf_dir/multi_stanzas_access.conf"; @@ -145,11 +150,20 @@ my $default_client_args = "LD_LIBRARY_PATH=$lib_dir $valgrind_str " . "$fwknopCmd -A tcp/22 -a $fake_ip -D $loopback_ip --get-key " . "$local_key_file --no-save-args --verbose --verbose"; +my $default_client_args_no_get_key = "LD_LIBRARY_PATH=$lib_dir " . + "$valgrind_str $fwknopCmd -A tcp/22 -a $fake_ip -D $loopback_ip " . + "--no-save-args --verbose --verbose"; + my $default_client_gpg_args = "$default_client_args " . "--gpg-recipient-key $gpg_server_key " . "--gpg-signer-key $gpg_client_key " . "--gpg-home-dir $gpg_client_home_dir"; +my $default_client_gpg_args_no_get_key = "$default_client_args_no_get_key " . + "--gpg-recipient-key $gpg_server_key " . + "--gpg-signer-key $gpg_client_key " . + "--gpg-home-dir $gpg_client_home_dir"; + my $default_server_conf_args = "-c $default_conf -a $default_access_conf " . "-d $default_digest_file -p $default_pid_file"; @@ -612,6 +626,82 @@ my @tests = ( 'fw_rule_removed' => $NEW_RULE_REMOVED, 'fatal' => $NO }, + { + 'category' => 'Rijndael SPA', + 'subcategory' => 'client+server', + 'detail' => 'create rc file (tcp/22 ssh)', + 'err_msg' => 'could not complete SPA cycle', + 'function' => \&spa_cycle, + 'cmdline' => "$default_client_args --rc-file $tmp_rc_file", + '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' => 'basic operations', + 'subcategory' => 'client', + 'detail' => "rc file created", + 'err_msg' => "rc file $tmp_rc_file does not exist", + 'function' => \&rc_file_exists, + 'fatal' => $NO + }, + { + 'category' => 'Rijndael SPA', + 'subcategory' => 'client+server', + 'detail' => 'rc file default key (tcp/22 ssh)', + 'err_msg' => 'could not complete SPA cycle', + 'function' => \&spa_cycle, + 'cmdline' => "$default_client_args_no_get_key " . + "--rc-file $rc_file_default_key", + '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 SPA', + 'subcategory' => 'client+server', + 'detail' => 'rc file base64 key (tcp/22 ssh)', + 'err_msg' => 'could not complete SPA cycle', + 'function' => \&spa_cycle, + 'cmdline' => "$default_client_args_no_get_key " . + "--rc-file $rc_file_default_base64_key", + 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " . + "$fwknopdCmd -c $default_conf -a $base64_key_access_conf " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'fatal' => $NO + }, + { + 'category' => 'Rijndael SPA', + 'subcategory' => 'client+server', + 'detail' => 'rc file named key (tcp/22 ssh)', + 'err_msg' => 'could not complete SPA cycle', + 'function' => \&spa_cycle, + 'cmdline' => "$default_client_args_no_get_key " . + "--rc-file $rc_file_named_key -n testssh", + '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 SPA', + 'subcategory' => 'client+server', + 'detail' => 'rc file invalid stanza (tcp/22 ssh)', + 'err_msg' => 'SPA packet generated/accepted', + 'function' => \&generic_exec, + 'cmdline' => "$default_client_args_no_get_key " . + "--rc-file $rc_file_named_key -n invalidstanza", + 'positive_output_matches' => [qr/Named\sconfiguration.*not\sfound/], + 'fatal' => $NO + }, + { 'category' => 'Rijndael SPA', 'subcategory' => 'client+server', @@ -1201,6 +1291,32 @@ my @tests = ( 'fw_rule_removed' => $NEW_RULE_REMOVED, 'fatal' => $NO }, + { + 'category' => 'GnuPG (GPG) SPA', + 'subcategory' => 'client+server', + 'detail' => 'rc file default key (tcp/22 ssh)', + 'err_msg' => 'could not complete SPA cycle', + 'function' => \&spa_cycle, + 'cmdline' => "$default_client_gpg_args_no_get_key " . + "--rc-file $rc_file_default_key", + 'fwknopd_cmdline' => $default_server_gpg_args, + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'fatal' => $NO + }, + { + 'category' => 'GnuPG (GPG) SPA', + 'subcategory' => 'client+server', + 'detail' => 'rc file named key (tcp/22 ssh)', + 'err_msg' => 'could not complete SPA cycle', + 'function' => \&spa_cycle, + 'cmdline' => "$default_client_gpg_args_no_get_key " . + "--rc-file $rc_file_named_key -n testssh", + 'fwknopd_cmdline' => $default_server_gpg_args, + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'fatal' => $NO + }, { 'category' => 'GnuPG (GPG) SPA', 'subcategory' => 'client+server', @@ -1683,6 +1799,18 @@ sub spa_cycle() { $rv = 0 if $fw_rule_removed; } + if ($test_hr->{'client_positive_output_matches'}) { + $rv = 0 unless &file_find_regex( + $test_hr->{'client_positive_output_matches'}, + $current_test_file); + } + + if ($test_hr->{'client_negative_output_matches'}) { + $rv = 0 if &file_find_regex( + $test_hr->{'client_negative_output_matches'}, + $current_test_file); + } + if ($test_hr->{'server_positive_output_matches'}) { $rv = 0 unless &file_find_regex( $test_hr->{'server_positive_output_matches'}, @@ -2256,6 +2384,24 @@ sub send_packets() { return; } +sub rc_file_exists() { + my $test_hr = shift; + + my $rv = 1; + + if (-e $tmp_rc_file) { + $rv = 0 unless &file_find_regex([qr/This\sfile\scontains/], + $tmp_rc_file); + } else { + &write_test_file("[-] $tmp_rc_file does not exist.\n", + $current_test_file); + $rv = 0; + } + + return $rv; +} + + sub generic_exec() { my $test_hr = shift; @@ -2623,6 +2769,9 @@ sub init() { if (-e "$output_dir/init") { unlink "$output_dir/init" or die $!; } + if (-e $tmp_rc_file) { + unlink $tmp_rc_file or die $!; + } if (-e $logfile) { unlink $logfile or die $!;