diff --git a/ChangeLog b/ChangeLog index 17c531c5..dc0027ea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,16 @@ fwknop-2.0.2 (08//2012): + - [server] For GPG mode, added a new access.conf variable + "GPG_ALLOW_NO_PW" to make it possible to leverage a server-side GPG key + pair that has no associated password. This comes in handy when a system + requires the user to leverage gpg-agent / pinentry which can present a + problem in automated environments as required by the fwknopd server. + Now, it might seem like a problem to remove the passphrase from a GPG + key pair, but it's important to note that simply doing this is little + worse than storing the passphrase in the clear on disk anyway in the + access.conf file. Further, this link helps provide additional detail: + + http://www.gnupg.org/faq/GnuPG-FAQ.html#how-can-i-use-gnupg-in-an-automated-environment + - [client] In IP resolution mode (-R) changed HTTP connection type to 'close' since there is no need for connection persistence, and indeed the client expects to just get the IP and the connection to be closed. @@ -7,6 +19,14 @@ fwknop-2.0.2 (08//2012): remote webserver IP resolution mode (-R). Previously IP resolution could fail if HTTP headers were transferred separately from the data (for whatever reason). Jonathan Schulz submitted a patch for this. + - [server] Bug fix to implement FLUSH_IPT_AT_INIT and FLUSH_IPT_AT_EXIT + functionality. These are enabled by default, and now iptables rules + added by fwknopd can be made persistant by setting these variables to + "N" in the fwknopd.conf file (this is not a recommended setting + however). + [server] Added FLUSH_IPFW_AT_INIT and FLUSH_IPFW_AT_EXIT for ipfw + firewalls to emulate the corresponding functionality that is implemented + for iptables firewalls. This was suggested by Jonathan Schulz. - [server] Replay attack bug fix to ensure that an attacker cannot force a replay attack by intercepting an SPA packet and the replaying it with the base64 version of "Salted__" (for Rindael) or the "hQ" prefix (for @@ -36,6 +56,9 @@ fwknop-2.0.2 (08//2012): by 0x10DABF: pcap_capture (pcap_capture.c:226) by 0x10A798: main (fwknopd.c:299) + - [test suite] Added GPG tests for keyrings that have no associated + passphrases. + fwknop-2.0.1 (07/23/2012): - [server] Bug fix where the same encryption key used for two stanzas in the access.conf file would result in access requests that matched the diff --git a/Makefile.am b/Makefile.am index b682fa3d..16dfecb1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -109,6 +109,15 @@ EXTRA_DIST = \ test/conf/client-gpg/pubring.gpg \ test/conf/client-gpg/secring.gpg \ test/conf/client-gpg/trustdb.gpg \ + test/conf/client-gpg-no-pw/pubring.gpg \ + test/conf/client-gpg-no-pw/secring.gpg \ + test/conf/client-gpg-no-pw/trustdb.gpg \ + test/conf/server-gpg/pubring.gpg \ + test/conf/server-gpg/secring.gpg \ + test/conf/server-gpg/trustdb.gpg \ + test/conf/server-gpg-no-pw/pubring.gpg \ + test/conf/server-gpg-no-pw/secring.gpg \ + test/conf/server-gpg-no-pw/trustdb.gpg \ test/conf/default_access.conf \ test/conf/default_fwknopd.conf \ test/conf/dual_key_usage_access.conf \ @@ -133,9 +142,6 @@ EXTRA_DIST = \ test/conf/override_fwknopd.conf \ test/conf/require_src_access.conf \ test/conf/require_user_access.conf \ - test/conf/server-gpg/pubring.gpg \ - test/conf/server-gpg/secring.gpg \ - test/conf/server-gpg/trustdb.gpg \ test/conf/subnet_source_match_access.conf \ test/conf/local_nat_fwknopd.conf \ test/hardening-check \ diff --git a/server/access.c b/server/access.c index 15057d3b..c81fb936 100644 --- a/server/access.c +++ b/server/access.c @@ -46,6 +46,9 @@ static void add_acc_string(char **var, const char *val) { + if(*var != NULL) + free(*var); + if((*var = strdup(val)) == NULL) { log_msg(LOG_ERR, @@ -396,6 +399,9 @@ add_string_list_ent(acc_string_list_t **stlist, const char *str_str) last_stlist->next = new_stlist; } + if(new_stlist->str != NULL) + free(new_stlist->str); + new_stlist->str = strdup(str_str); if(new_stlist->str == NULL) @@ -930,6 +936,13 @@ parse_access_file(fko_srv_options_t *opts) } add_acc_string(&(curr_acc->gpg_decrypt_pw), val); } + else if(CONF_VAR_IS(var, "GPG_ALLOW_NO_PW")) + { + if(curr_acc->gpg_decrypt_pw != NULL && curr_acc->gpg_decrypt_pw[0] != '\0') + free(curr_acc->gpg_decrypt_pw); + + add_acc_string(&(curr_acc->gpg_decrypt_pw), ""); + } else if(CONF_VAR_IS(var, "GPG_REQUIRE_SIG")) { add_acc_bool(&(curr_acc->gpg_require_sig), val); diff --git a/server/incoming_spa.c b/server/incoming_spa.c index 7f272484..2703a77c 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -436,7 +436,7 @@ incoming_spa(fko_srv_options_t *opts) else { log_msg(LOG_ERR, - "(stanza #%d) No GPG_DECRYPT_PW for GPG encrypted messages", + "(stanza #%d) No GPG_DECRYPT_PW for GPG encrypted messages, set GPG_ALLOW_NO_PW", stanza_num ); acc = acc->next; diff --git a/test/conf/client-gpg-no-pw/pubring.gpg b/test/conf/client-gpg-no-pw/pubring.gpg new file mode 100644 index 00000000..615e12f6 Binary files /dev/null and b/test/conf/client-gpg-no-pw/pubring.gpg differ diff --git a/test/conf/client-gpg-no-pw/secring.gpg b/test/conf/client-gpg-no-pw/secring.gpg new file mode 100644 index 00000000..e84fd95c Binary files /dev/null and b/test/conf/client-gpg-no-pw/secring.gpg differ diff --git a/test/conf/client-gpg-no-pw/trustdb.gpg b/test/conf/client-gpg-no-pw/trustdb.gpg new file mode 100644 index 00000000..58ec2d6d Binary files /dev/null and b/test/conf/client-gpg-no-pw/trustdb.gpg differ diff --git a/test/conf/gpg_no_pw_access.conf b/test/conf/gpg_no_pw_access.conf new file mode 100644 index 00000000..2f6e810f --- /dev/null +++ b/test/conf/gpg_no_pw_access.conf @@ -0,0 +1,7 @@ +SOURCE: ANY; +KEY: fwknoptest; +FW_ACCESS_TIMEOUT: 3; +GPG_HOME_DIR: conf/server-gpg-no-pw; +GPG_DECRYPT_ID: 361BBAD4; +GPG_ALLOW_NO_PW: Y; +GPG_REMOTE_ID: 6A3FAD56; diff --git a/test/conf/server-gpg-no-pw/pubring.gpg b/test/conf/server-gpg-no-pw/pubring.gpg new file mode 100644 index 00000000..b0aa06e8 Binary files /dev/null and b/test/conf/server-gpg-no-pw/pubring.gpg differ diff --git a/test/conf/server-gpg-no-pw/secring.gpg b/test/conf/server-gpg-no-pw/secring.gpg new file mode 100644 index 00000000..c3a465a5 Binary files /dev/null and b/test/conf/server-gpg-no-pw/secring.gpg differ diff --git a/test/conf/server-gpg-no-pw/trustdb.gpg b/test/conf/server-gpg-no-pw/trustdb.gpg new file mode 100644 index 00000000..d5b5b60c Binary files /dev/null and b/test/conf/server-gpg-no-pw/trustdb.gpg differ diff --git a/test/test-fwknop.pl b/test/test-fwknop.pl index e2e580b4..324f8cb7 100755 --- a/test/test-fwknop.pl +++ b/test/test-fwknop.pl @@ -18,6 +18,7 @@ my $configure_path = '../configure'; my $cmd_out_tmp = 'cmd.out'; my $server_cmd_tmp = 'server_cmd.out'; my $gpg_client_home_dir = "$conf_dir/client-gpg"; +my $gpg_client_home_dir_no_pw = "$conf_dir/client-gpg-no-pw"; my %cf = ( 'nat' => "$conf_dir/nat_fwknopd.conf", @@ -31,6 +32,7 @@ my %cf = ( 'local_nat' => "$conf_dir/local_nat_fwknopd.conf", 'dual_key_access' => "$conf_dir/dual_key_usage_access.conf", 'gpg_access' => "$conf_dir/gpg_access.conf", + 'gpg_no_pw_access' => "$conf_dir/gpg_no_pw_access.conf", 'open_ports_access' => "$conf_dir/open_ports_access.conf", 'multi_gpg_access' => "$conf_dir/multi_gpg_access.conf", 'multi_stanza_access' => "$conf_dir/multi_stanzas_access.conf", @@ -160,6 +162,10 @@ my $default_client_gpg_args = "$default_client_args " . "--gpg-signer-key $gpg_client_key " . "--gpg-home-dir $gpg_client_home_dir"; +my $default_client_gpg_args_no_homedir = "$default_client_args " . + "--gpg-recipient-key $gpg_server_key " . + "--gpg-signer-key $gpg_client_key "; + my $default_server_conf_args = "-c $cf{'def'} -a $cf{'def_access'} " . "-d $default_digest_file -p $default_pid_file"; @@ -168,6 +174,11 @@ my $default_server_gpg_args = "LD_LIBRARY_PATH=$lib_dir " . "-a $cf{'gpg_access'} $intf_str " . "-d $default_digest_file -p $default_pid_file"; +my $default_server_gpg_args_no_pw = "LD_LIBRARY_PATH=$lib_dir " . + "$valgrind_str $fwknopdCmd -c $cf{'def'} " . + "-a $cf{'gpg_no_pw_access'} $intf_str " . + "-d $default_digest_file -p $default_pid_file"; + ### point the compiled binaries at the local libary path ### instead of any installed libfko instance $ENV{'LD_LIBRARY_PATH'} = $lib_dir; @@ -1183,6 +1194,171 @@ my @tests = ( 'fatal' => $NO }, + { + 'category' => 'GPG (no pw) SPA', + 'subcategory' => 'client+server', + 'detail' => 'complete cycle (tcp/22 ssh)', + 'err_msg' => 'could not complete SPA cycle', + 'function' => \&spa_cycle, + 'cmdline' => "$default_client_gpg_args_no_homedir " + . "--gpg-home-dir $gpg_client_home_dir_no_pw", + 'fwknopd_cmdline' => $default_server_gpg_args_no_pw, + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'fatal' => $NO + }, + { + 'category' => 'GPG (no pw) SPA', + 'subcategory' => 'client+server', + 'detail' => 'multi gpg-IDs (tcp/22 ssh)', + 'err_msg' => 'could not complete SPA cycle', + 'function' => \&spa_cycle, + 'cmdline' => "$default_client_gpg_args_no_homedir " + . "--gpg-home-dir $gpg_client_home_dir_no_pw", + 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir " . + "$valgrind_str $fwknopdCmd -c $cf{'def'} " . + "-a $cf{'multi_gpg_access'} $intf_str " . + "-d $default_digest_file -p $default_pid_file", + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'fatal' => $NO + }, + + { + 'category' => 'GPG (no pw) SPA', + 'subcategory' => 'client+server', + 'detail' => 'complete cycle (tcp/23 telnet)', + 'err_msg' => 'could not complete SPA cycle', + 'function' => \&spa_cycle, + 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " . + "$fwknopCmd -A tcp/23 -a $fake_ip -D $loopback_ip --get-key " . + "$local_key_file --verbose --verbose " . + "--gpg-recipient-key $gpg_server_key " . + "--gpg-signer-key $gpg_client_key " . + "--gpg-home-dir $gpg_client_home_dir_no_pw", + 'fwknopd_cmdline' => $default_server_gpg_args_no_pw, + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'fatal' => $NO + }, + { + 'category' => 'GPG (no pw) SPA', + 'subcategory' => 'client+server', + 'detail' => 'complete cycle (tcp/9418 git)', + 'err_msg' => 'could not complete SPA cycle', + 'function' => \&spa_cycle, + 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " . + "$fwknopCmd -A tcp/9418 -a $fake_ip -D $loopback_ip --get-key " . + "$local_key_file --verbose --verbose " . + "--gpg-recipient-key $gpg_server_key " . + "--gpg-signer-key $gpg_client_key " . + "--gpg-home-dir $gpg_client_home_dir_no_pw", + 'fwknopd_cmdline' => $default_server_gpg_args_no_pw, + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'fatal' => $NO + }, + { + 'category' => 'GPG (no pw) SPA', + 'subcategory' => 'client+server', + 'detail' => 'complete cycle (udp/53 dns)', + 'err_msg' => 'could not complete SPA cycle', + 'function' => \&spa_cycle, + 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " . + "$fwknopCmd -A udp/53 -a $fake_ip -D $loopback_ip --get-key " . + "$local_key_file --verbose --verbose " . + "--gpg-recipient-key $gpg_server_key " . + "--gpg-signer-key $gpg_client_key " . + "--gpg-home-dir $gpg_client_home_dir_no_pw", + 'fwknopd_cmdline' => $default_server_gpg_args_no_pw, + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'fatal' => $NO + }, + + { + 'category' => 'GPG (no pw) SPA', + 'subcategory' => 'client+server', + 'detail' => 'replay attack detection', + 'err_msg' => 'could not detect replay attack', + 'function' => \&replay_detection, + 'cmdline' => "$default_client_gpg_args_no_homedir " + . "--gpg-home-dir $gpg_client_home_dir_no_pw", + 'fwknopd_cmdline' => $default_server_gpg_args_no_pw, + 'replay_positive_output_matches' => [qr/Replay\sdetected\sfrom\ssource\sIP/], + 'fatal' => $NO + }, + { + 'category' => 'GPG (no pw) SPA', + 'subcategory' => 'client+server', + 'detail' => 'replay detection (GnuPG prefix)', + 'err_msg' => 'could not detect replay attack', + 'function' => \&replay_detection, + 'pkt_prefix' => 'hQ', + 'cmdline' => "$default_client_gpg_args_no_homedir " + . "--gpg-home-dir $gpg_client_home_dir_no_pw", + 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " . + "$fwknopdCmd $default_server_conf_args $intf_str", + 'replay_positive_output_matches' => [qr/Data\sis\snot\sa\svalid\sSPA\smessage\sformat/], + 'fatal' => $NO + }, + + { + 'category' => 'GPG (no pw) SPA', + 'subcategory' => 'client+server', + 'detail' => 'non-base64 altered SPA data', + 'err_msg' => 'allowed improper SPA data', + 'function' => \&altered_non_base64_spa_data, + 'cmdline' => "$default_client_gpg_args_no_homedir " + . "--gpg-home-dir $gpg_client_home_dir_no_pw", + 'fwknopd_cmdline' => $default_server_gpg_args_no_pw, + 'fatal' => $NO + }, + { + 'category' => 'GPG (no pw) SPA', + 'subcategory' => 'client+server', + 'detail' => 'base64 altered SPA data', + 'err_msg' => 'allowed improper SPA data', + 'function' => \&altered_base64_spa_data, + 'cmdline' => "$default_client_gpg_args_no_homedir " + . "--gpg-home-dir $gpg_client_home_dir_no_pw", + 'fwknopd_cmdline' => $default_server_gpg_args_no_pw, + 'fatal' => $NO + }, + { + 'category' => 'GPG (no pw) SPA', + 'subcategory' => 'client+server', + 'detail' => 'appended data to SPA pkt', + 'err_msg' => 'allowed improper SPA data', + 'function' => \&appended_spa_data, + 'cmdline' => "$default_client_gpg_args_no_homedir " + . "--gpg-home-dir $gpg_client_home_dir_no_pw", + 'fwknopd_cmdline' => $default_server_gpg_args_no_pw, + 'fatal' => $NO + }, + { + 'category' => 'GPG (no pw) SPA', + 'subcategory' => 'client+server', + 'detail' => 'prepended data to SPA pkt', + 'err_msg' => 'allowed improper SPA data', + 'function' => \&prepended_spa_data, + 'cmdline' => "$default_client_gpg_args_no_homedir " + . "--gpg-home-dir $gpg_client_home_dir_no_pw", + 'fwknopd_cmdline' => $default_server_gpg_args_no_pw, + 'fatal' => $NO + }, + { + 'category' => 'GPG (no pw) SPA', + 'subcategory' => 'client+server', + 'detail' => 'spoof username (tcp/22 ssh)', + 'err_msg' => 'could not spoof username', + 'function' => \&spoof_username, + 'cmdline' => "SPOOF_USER=$spoof_user $default_client_gpg_args_no_homedir " + . "--gpg-home-dir $gpg_client_home_dir_no_pw", + 'fwknopd_cmdline' => $default_server_gpg_args_no_pw, + 'fatal' => $NO + }, + { 'category' => 'GnuPG (GPG) SPA', 'subcategory' => 'client+server',