use File::Path;
use IO::Socket;
use Data::Dumper;
+use Cwd;
use Getopt::Long 'GetOptions';
use strict;
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 $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";
+my $ofb_mode_access_conf = "$conf_dir/ofb_mode_access.conf";
my $expired_access_conf = "$conf_dir/expired_stanza_access.conf";
my $future_expired_access_conf = "$conf_dir/future_expired_stanza_access.conf";
my $expired_epoch_access_conf = "$conf_dir/expired_epoch_stanza_access.conf";
my $invalid_expire_access_conf = "$conf_dir/invalid_expire_access.conf";
+my $invalid_source_access_conf = "$conf_dir/invalid_source_access.conf";
my $force_nat_access_conf = "$conf_dir/force_nat_access.conf";
my $dual_key_usage_access_conf = "$conf_dir/dual_key_usage_access.conf";
my $gpg_access_conf = "$conf_dir/gpg_access.conf";
my $saved_last_results = 0;
my $diff_mode = 0;
my $enable_recompilation_warnings_check = 0;
+my $enable_profile_coverage_check = 0;
my $sudo_path = '';
+my $gcov_path = '';
my $platform = '';
my $help = 0;
my $YES = 1;
'test-exclude=s' => \$test_exclude,
'exclude=s' => \$test_exclude, ### synonym
'enable-recompile-check' => \$enable_recompilation_warnings_check,
+ 'enable-profile-coverage-check' => \$enable_profile_coverage_check,
'List-mode' => \$list_mode,
'enable-valgrind' => \$use_valgrind,
'valgrind-path=s' => \$valgrindCmd,
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
+ 'detail' => 'invalid SOURCE (tcp/22 ssh)',
+ 'err_msg' => 'SPA packet accepted',
+ 'function' => \&spa_cycle,
+ 'cmdline' => $default_client_args,
+ 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
+ "$fwknopdCmd -c $default_conf -a $invalid_source_access_conf " .
+ "-d $default_digest_file -p $default_pid_file $intf_str",
+ 'server_positive_output_matches' => [qr/Fatal\serror\sparsing\sIP\sto\sint/],
+ 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
+ 'fatal' => $NO
+ },
+ {
+ 'category' => 'Rijndael SPA',
+ 'subcategory' => 'client+server',
'detail' => 'expired stanza (tcp/22 ssh)',
'err_msg' => 'SPA packet accepted',
'function' => \&spa_cycle,
'server_conf' => $nat_conf,
'fatal' => $NO
},
+ {
+ 'category' => 'Rijndael SPA',
+ 'subcategory' => 'client+server',
+ 'detail' => 'ECB mode (tcp/22 ssh)',
+ 'err_msg' => 'could not complete SPA cycle',
+ 'function' => \&spa_cycle,
+ 'cmdline' => "$default_client_args -M ecb",
+ 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
+ "$fwknopdCmd -c $default_conf -a $ecb_mode_access_conf " .
+ "-d $default_digest_file -p $default_pid_file $intf_str",
+ 'server_negative_output_matches' => [qr/Decryption\sfailed/i],
+ 'fw_rule_created' => $NEW_RULE_REQUIRED,
+ 'fw_rule_removed' => $NEW_RULE_REMOVED,
+ 'fatal' => $NO
+ },
+ {
+ 'category' => 'Rijndael SPA',
+ 'subcategory' => 'client+server',
+ 'detail' => 'CFB mode (tcp/22 ssh)',
+ 'err_msg' => 'could not complete SPA cycle',
+ 'function' => \&spa_cycle,
+ 'cmdline' => "$default_client_args -M cfb",
+ 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
+ "$fwknopdCmd -c $default_conf -a $cfb_mode_access_conf " .
+ "-d $default_digest_file -p $default_pid_file $intf_str",
+ 'server_negative_output_matches' => [qr/Decryption\sfailed/i],
+ 'fw_rule_created' => $NEW_RULE_REQUIRED,
+ 'fw_rule_removed' => $NEW_RULE_REMOVED,
+ 'fatal' => $NO
+ },
+ {
+ 'category' => 'Rijndael SPA',
+ 'subcategory' => 'client+server',
+ 'detail' => 'CTR mode (tcp/22 ssh)',
+ 'err_msg' => 'could not complete SPA cycle',
+ 'function' => \&spa_cycle,
+ 'cmdline' => "$default_client_args -M ctr",
+ 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
+ "$fwknopdCmd -c $default_conf -a $ctr_mode_access_conf " .
+ "-d $default_digest_file -p $default_pid_file $intf_str",
+ 'server_negative_output_matches' => [qr/Decryption\sfailed/i],
+ 'fw_rule_created' => $NEW_RULE_REQUIRED,
+ 'fw_rule_removed' => $NEW_RULE_REMOVED,
+ 'fatal' => $NO
+ },
+ {
+ 'category' => 'Rijndael SPA',
+ 'subcategory' => 'client+server',
+ 'detail' => 'OFB mode (tcp/22 ssh)',
+ 'err_msg' => 'could not complete SPA cycle',
+ 'function' => \&spa_cycle,
+ 'cmdline' => "$default_client_args -M ofb",
+ 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
+ "$fwknopdCmd -c $default_conf -a $ofb_mode_access_conf " .
+ "-d $default_digest_file -p $default_pid_file $intf_str",
+ 'server_negative_output_matches' => [qr/Decryption\sfailed/i],
+ 'fw_rule_created' => $NEW_RULE_REQUIRED,
+ 'fw_rule_removed' => $NEW_RULE_REMOVED,
+ 'fatal' => $NO
+ },
+
+ {
+ 'category' => 'Rijndael SPA',
+ 'subcategory' => 'client+server',
+ 'detail' => 'mode mismatch (tcp/22 ssh)',
+ 'err_msg' => 'server accepted mismatch enc mode',
+ 'function' => \&spa_cycle,
+ 'cmdline' => "$default_client_args -M ecb",
+ 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
+ "$fwknopdCmd -c $default_conf -a $default_access_conf " .
+ "-d $default_digest_file -p $default_pid_file $intf_str",
+ 'server_positive_output_matches' => [qr/Decryption\sfailed/i],
+ 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
+ 'fatal' => $NO
+ },
{
'category' => 'Rijndael SPA',
'function' => \&digest_cache_structure,
'fatal' => $NO
},
+
+ {
+ 'category' => 'profile coverage',
+ 'detail' => 'gcov profile coverage',
+ 'err_msg' => 'profile coverage failed',
+ 'function' => \&profile_coverage,
+ 'fatal' => $NO
+ },
);
if ($use_valgrind) {
### look for compilation warnings - something like:
### warning: ‘test’ is used uninitialized in this function
- return 0 if &file_find_regex([qr/\swarning:\s/, qr/gcc\:.*\sunused/], $current_test_file);
+ return 0 if &file_find_regex([qr/\swarning:\s/, qr/gcc\:.*\sunused/],
+ $current_test_file);
### the new binaries should exist
unless (-e $fwknopCmd and -x $fwknopCmd) {
return 1;
}
+sub profile_coverage() {
+
+ ### check for any *.gcno files - if they don't exist, then fwknop was
+ ### not compiled with profile support
+ unless (glob('../client/*.gcno') and glob('../server/*.gcno')) {
+ &write_test_file("[-] ../client/*.gcno and " .
+ "../server/*.gcno files do not exist.\n", $current_test_file);
+ return 0;
+ }
+
+ my $curr_dir = getcwd() or die $!;
+
+ ### gcov -b ../client/*.gcno
+ for my $dir ('../client', '../server', '../lib/.libs') {
+ next unless -d $dir;
+ chdir $dir or die $!;
+ system "$gcov_path -b -u *.gcno > /dev/null 2>&1";
+ chdir $curr_dir or die $!;
+
+ &run_cmd(qq|grep "called 0 returned" $dir/*.gcov|,
+ $cmd_out_tmp, $current_test_file);
+ }
+
+ return 1;
+}
+
sub binary_exists() {
my $test_hr = shift;
return 0 unless $test_hr->{'binary'};
push @tests_to_exclude, 'recompilation';
}
+ unless ($enable_profile_coverage_check) {
+ push @tests_to_exclude, 'profile coverage';
+ }
+
$sudo_path = &find_command('sudo');
unless ((&find_command('cc') or &find_command('gcc')) and &find_command('make')) {
push @tests_to_exclude, 'recompilation';
}
+ $gcov_path = &find_command('gcov');
+
+ if ($gcov_path) {
+ if ($enable_profile_coverage_check) {
+ for my $extension ('*.gcov', '*.gcda') {
+ ### remove profile output from any previous run
+ system qq{find .. -name $extension | xargs rm 2> /dev/null};
+ }
+ }
+ } else {
+ push @tests_to_exclude, 'profile coverage';
+ }
+
open UNAME, "uname |" or die "[*] Could not execute uname: $!";
while (<UNAME>) {
if (/linux/i) {