merged in fwknop-2.0.4 changes
authorMichael Rash <mbr@cipherdyne.org>
Fri, 18 Jan 2013 23:24:45 +0000 (18:24 -0500)
committerMichael Rash <mbr@cipherdyne.org>
Fri, 18 Jan 2013 22:25:16 +0000 (17:25 -0500)
23 files changed:
1  2 
client/cmd_opts.h
client/config_init.c
client/fwknop.c
client/fwknop_common.h
client/getpasswd.c
client/spa_comm.c
client/utils.c
client/utils.h
configure.ac
doc/fwknop.man.asciidoc
doc/fwknopd.man.asciidoc
lib/Makefile.am
lib/fko.h
lib/fko_decode.c
lib/fko_encode.c
lib/fko_encryption.c
lib/fko_limits.h
server/access.c
server/fwknopd_common.h
server/incoming_spa.c
server/utils.c
server/utils.h
test/test-fwknop.pl

@@@ -82,8 -80,8 +84,10 @@@ 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'},
+     {"icmp-type",           1, NULL, SPA_ICMP_TYPE },
+     {"icmp-code",           1, NULL, SPA_ICMP_CODE },
      {"last-cmd",            0, NULL, 'l'},
      {"nat-access",          1, NULL, 'N'},
      {"named-config",        1, NULL, 'n'},
@@@ -821,12 -757,21 +847,27 @@@ config_init(fko_cli_options_t *options
                  options->spa_proto = FKO_PROTO_HTTP;
                  strlcpy(options->http_proxy, optarg, MAX_PATH_LEN);
                  break;
 +            case 'k':
 +                options->key_gen = 1;
 +                break;
 +            case 'K':
 +                options->key_gen = 1;
 +                strlcpy(options->key_gen_file, optarg, MAX_PATH_LEN);
+             case SPA_ICMP_TYPE:
+                 options->spa_icmp_type = atoi(optarg);
+                 if (options->spa_icmp_type < 0 || options->spa_icmp_type > MAX_ICMP_TYPE)
+                 {
+                     fprintf(stderr, "Unrecognized icmp type value: %s\n", optarg);
+                     exit(EXIT_FAILURE);
+                 }
+                 break;
+             case SPA_ICMP_CODE:
+                 options->spa_icmp_code = atoi(optarg);
+                 if (options->spa_icmp_code < 0 || options->spa_icmp_code > MAX_ICMP_CODE)
+                 {
+                     fprintf(stderr, "Unrecognized icmp code value: %s\n", optarg);
+                     exit(EXIT_FAILURE);
+                 }
                  break;
              case 'l':
                  options->run_last_command = 1;
diff --cc client/fwknop.c
Simple merge
@@@ -132,9 -117,11 +132,12 @@@ typedef struct fko_cli_option
      unsigned int spa_dst_port;
      unsigned int spa_src_port; /* only used with --source-port */
  
 +    short digest_type;
 +    int encryption_mode;
 +
+     int spa_icmp_type;  /* only used in '-P icmp' mode */
+     int spa_icmp_code;  /* only used in '-P icmp' mode */
 -    unsigned int digest_type;
 -
      /* Various command-line flags */
      unsigned char   verbose; /* --verbose mode */
      unsigned char   version; /* --version */
  #include "fwknop_common.h"
  #include "getpasswd.h"
  
- /* Function for accepting password input from users
- */
+ #define MAX_PASS_LEN    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
+ /**
+  * Function for accepting password input from users
+  *
+  * The functions reads chars from the terminal and store them in a buffer of chars.
+  *
+  * @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)
+ getpasswd(
+     const char *prompt)     ///< String displayed on the terminal to prompt the user for a password or an encryption key
  {
 -    static char     pwbuf[MAX_PASS_LEN + 1] = {0};
 +    static char     pwbuf[MAX_KEY_LEN + 1] = {0};
      char           *ptr;
      int             c;
  
@@@ -93,23 -93,23 +93,6 @@@ chksum(unsigned short *buf, int nbytes
      return (unsigned short) ~sum;
  }
  
--/*
--static int is_ip(char *str)
--{
--    int rv = 1;
--    unsigned int i;
--
--    for (i=0; i < strlen(str); i++) {
--        if (str[i] != '.' && ! isdigit(str[i])) {
--            rv = 0;
--            break;
--        }
--    }
--
--    return rv;
--}
--*/
--
  /* Send the SPA data via UDP packet.
  */
  static int
diff --cc client/utils.c
@@@ -68,46 -69,7 +69,28 @@@ hex_dump(const unsigned char *data, con
      }
  }
  
 +/* 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; i<len; i++)
 +    {
 +        if(!(isalnum(buf[i]) || buf[i] == '/' || buf[i] == '+' || buf[i] == '='))
 +        {
 +            rv = 0;
 +            break;
 +        }
 +    }
 +
 +    return rv;
 +}
 +
  int
- set_file_perms(const char *file)
- {
-     int res = 0;
-     res = chmod(file, S_IRUSR | S_IWUSR);
-     if(res != 0)
-     {
-         fprintf(stderr,
-             "[-] unable to chmod file %s to user read/write (0600, -rw-------): %s\n",
-             file,
-             strerror(errno)
-         );
-     }
-     return res;
- }
- int
  verify_file_perms_ownership(const char *file)
  {
      int res = 1;
diff --cc client/utils.h
Simple merge
diff --cc configure.ac
Simple merge
Simple merge
Simple merge
diff --cc lib/Makefile.am
@@@ -5,15 -5,23 +5,23 @@@ libfko_source_files = 
      fko_client_timeout.c fko_common.h fko_digest.c fko_encode.c \
      fko_decode.c fko_encryption.c fko_error.c fko_funcs.c fko_message.c \
      fko_message.h fko_nat_access.c fko_rand_value.c fko_server_auth.c \
 -    fko.h fko_limits.h fko_timestamp.c fko_user.c fko_user.h \
 -    md5.c md5.h rijndael.c rijndael.h sha1.c sha1.h sha2.c sha2.h \
 -    fko_context.h fko_state.h fko_context.h gpgme_funcs.c \
 -    gpgme_funcs.h
 +    fko.h fko_limits.h fko_timestamp.c fko_hmac.c hmac.c hmac.h \
-     fko_user.c fko_util.c fko_util.h md5.c md5.h rijndael.c rijndael.h \
-     sha1.c sha1.h  sha2.c sha2.h strlcat.c strlcpy.c fko_state.h \
++    fko_user.c fko_user.h fko_util.c fko_util.h md5.c md5.h rijndael.c \
++    rijndael.h sha1.c sha1.h sha2.c sha2.h fko_state.h \
 +    fko_context.h gpgme_funcs.c gpgme_funcs.h
  
- libfko_la_SOURCES   = $(libfko_source_files)
+ libfko_la_SOURCES             = $(libfko_source_files)
+ libfko_la_LIBADD              = 
+ libfko_la_DEPENDENCIES        = strlcpy.lo strlcat.lo
+ libfko_la_LDFLAGS             = -version-info 1:0:0 $(GPGME_LIBS) -export-symbols-regex '^fko_'
  
- libfko_la_LDFLAGS   = -version-info 0:3:0 $(GPGME_LIBS)
+ libfko_util_source_files      = strlcpy.c strlcat.c fko_util.h
+ libfko_util_a_SOURCES         = $(libfko_util_source_files)
+ libfko_util_a_LIBADD          = 
+ libfko_util_a_DEPENDENCIES  = strlcpy.lo strlcat.lo
  
- AM_CPPFLAGS         = $(GPGME_CFLAGS)
+ noinst_LIBRARIES              = libfko_util.a
  
- include_HEADERS     = fko.h
+ AM_CPPFLAGS                   = $(GPGME_CFLAGS) -I $(top_srcdir)/common
+ include_HEADERS               = fko.h
diff --cc lib/fko.h
+++ b/lib/fko.h
  #define FKO_H 1
  
  #include <time.h>
- #include "fko_limits.h"
- #include "fko_message.h"
  
 +#include "rijndael.h"   /* For encryption modes */
 +#include "digest.h"
 +
  #ifdef __cplusplus
  extern "C" {
  #endif
@@@ -42,9 -42,22 +42,15 @@@ fko_decode_spa_data(fko_ctx_t ctx
      char       *tbuf, *ndx, *tmp;
      int         t_size, i;
  
 -    /* Check for required data.
 -    */
 -    if(ctx->encoded_msg == NULL || strnlen(ctx->encoded_msg,
 -            MAX_SPA_ENCODED_MSG_SIZE) < MIN_SPA_ENCODED_MSG_SIZE)
 -        return(FKO_ERROR_INVALID_DATA);
 -
 -    if(strnlen(ctx->encoded_msg,
 -            MAX_SPA_ENCODED_MSG_SIZE) == MAX_SPA_ENCODED_MSG_SIZE)
 +    if (! is_valid_encoded_msg_len(ctx->encoded_msg_len))
          return(FKO_ERROR_INVALID_DATA);
  
+     /* Make sure there are no non-ascii printable chars
+     */
+     for (i=0; i < (int)strnlen(ctx->encoded_msg, MAX_SPA_ENCODED_MSG_SIZE); i++)
+         if(isprint(ctx->encoded_msg[i]) == 0)
+             return(FKO_ERROR_INVALID_DATA);
      /* Make sure there are enough fields in the SPA packet
       * delimited with ':' chars
      */
Simple merge
@@@ -134,17 -135,9 +134,18 @@@ _rijndael_decrypt(fko_ctx_t ctx
      if(cipher == NULL)
          return(FKO_ERROR_MEMORY_ALLOCATION);
  
-     cipher_len = b64_decode(ctx->encrypted_msg, cipher);
+     if((cipher_len = b64_decode(ctx->encrypted_msg, cipher)) < 0)
+         return(FKO_ERROR_INVALID_DATA);
  
 +    /* Since we're using AES, make sure the incoming data is a multiple of
 +     * the blocksize
 +    */
 +    if((cipher_len % RIJNDAEL_BLOCKSIZE) != 0)
 +    {
 +        free(cipher);
 +        return(FKO_ERROR_INVALID_DATA);
 +    }
 +
      /* Create a bucket for the plaintext data and decrypt the message
       * data into it.
      */
Simple merge
diff --cc server/access.c
Simple merge
Simple merge
Simple merge
diff --cc server/utils.c
Simple merge
diff --cc server/utils.h
@@@ -60,9 -60,8 +60,8 @@@
  */
  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);
- int set_file_perms(const char *file);
  int verify_file_perms_ownership(const char *file);
  
  size_t strlcat(char *dst, const char *src, size_t siz);
@@@ -36,14 -38,14 +40,18 @@@ my %cf = 
      '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",
+     'tcp_server'              => "$conf_dir/tcp_server_fwknopd.conf",
+     'tcp_pcap_filter'         => "$conf_dir/tcp_pcap_filter_fwknopd.conf",
+     'icmp_pcap_filter'        => "$conf_dir/icmp_pcap_filter_fwknopd.conf",
      'open_ports_access'       => "$conf_dir/open_ports_access.conf",
      'multi_gpg_access'        => "$conf_dir/multi_gpg_access.conf",
+     'multi_gpg_no_pw_access'  => "$conf_dir/multi_gpg_no_pw_access.conf",
      'multi_stanza_access'     => "$conf_dir/multi_stanzas_access.conf",
      'broken_keys_access'      => "$conf_dir/multi_stanzas_with_broken_keys.conf",
 +    'ecb_mode_access'         => "$conf_dir/ecb_mode_access.conf",
 +    'ctr_mode_access'         => "$conf_dir/ctr_mode_access.conf",
 +    'cfb_mode_access'         => "$conf_dir/cfb_mode_access.conf",
 +    'ofb_mode_access'         => "$conf_dir/ofb_mode_access.conf",
      'open_ports_mismatch'     => "$conf_dir/mismatch_open_ports_access.conf",
      'require_user_access'     => "$conf_dir/require_user_access.conf",
      'user_mismatch_access'    => "$conf_dir/mismatch_user_access.conf",
      'multi_src_access'        => "$conf_dir/multi_source_match_access.conf",
      'ip_src_match'            => "$conf_dir/ip_source_match_access.conf",
      'subnet_src_match'        => "$conf_dir/ip_source_match_access.conf",
 +    'rc_file_def_key'         => "$conf_dir/fwknoprc_with_default_key",
 +    'rc_file_def_b64_key'     => "$conf_dir/fwknoprc_with_default_base64_key",
 +    'rc_file_named_key'       => "$conf_dir/fwknoprc_named_key",
 +    'rc_file_invalid_b64_key' => "$conf_dir/fwknoprc_invalid_base64_key",
 +    'rc_file_hmac_b64_key'    => "$conf_dir/fwknoprc_default_hmac_base64_key",
 +    'base64_key_access'       => "$conf_dir/base64_key_access.conf",
      'disable_aging'           => "$conf_dir/disable_aging_fwknopd.conf",
+     'disable_aging_nat'       => "$conf_dir/disable_aging_nat_fwknopd.conf",
      'fuzz_source'             => "$conf_dir/fuzzing_source_access.conf",
      'fuzz_open_ports'         => "$conf_dir/fuzzing_open_ports_access.conf",
      'fuzz_restrict_ports'     => "$conf_dir/fuzzing_restrict_ports_access.conf",
@@@ -87,8 -82,10 +96,13 @@@ my $default_spa_port = 62201
  my $non_std_spa_port = 12345;
  
  my $spoof_user = 'testuser';
 +
 +my $valgrind_cov_dir = 'valgrind-coverage';
++
+ my $spoof_ip   = '1.2.3.4';
+ my $perl_mod_fko_dir = 'FKO';
+ my $cmd_exec_test_file = '/tmp/fwknoptest';
+ my $default_key = 'fwknoptest';
  #================== end config ===================
  
  my $passed = 0;
@@@ -109,7 -104,14 +123,15 @@@ my $loopback_intf = ''
  my $anonymize_results = 0;
  my $curr_test_file = "$output_dir/init";
  my $tarfile = 'test_fwknop.tar.gz';
 +my $key_gen_file = "$output_dir/key_gen";
+ my $fuzzing_pkts_file = 'fuzzing/fuzzing_spa_packets';
+ my $fuzzing_pkts_append = 0;
+ my $fuzzing_key = 'testtest';
+ my $fuzzing_num_pkts = 0;
+ my $fuzzing_test_tag = '';
+ my $fuzzing_class = 'bogus data';
+ my %fuzzing_spa_packets = ();
+ my $total_fuzzing_pkts = 0;
  my $server_test_file  = '';
  my $use_valgrind = 0;
  my $valgrind_str = '';
@@@ -117,11 -119,14 +139,16 @@@ my $enable_client_ip_resolve_test = 0
  my $enable_all = 0;
  my $saved_last_results = 0;
  my $diff_mode = 0;
+ my $fko_obj = ();
  my $enable_recompilation_warnings_check = 0;
 +my $enable_profile_coverage_check = 0;
  my $enable_make_distcheck = 0;
+ my $enable_perl_module_checks = 0;
+ my $enable_perl_module_fuzzing_spa_pkt_generation = 0;
  my $sudo_path = '';
 +my $gcov_path = '';
+ my $killall_path = '';
+ my $pinentry_fail = 0;
  my $platform = '';
  my $help = 0;
  my $YES = 1;
@@@ -157,14 -162,18 +185,20 @@@ exit 1 unless GetOptions
      'include=s'         => \$test_include,  ### synonym
      'test-exclude=s'    => \$test_exclude,
      'exclude=s'         => \$test_exclude,  ### synonym
+     'enable-perl-module-checks' => \$enable_perl_module_checks,
+     'enable-perl-module-pkt-generation' => \$enable_perl_module_fuzzing_spa_pkt_generation,
+     'fuzzing-pkts-file=s' => \$fuzzing_pkts_file,
+     'fuzzing-pkts-append' => \$fuzzing_pkts_append,
+     'fuzzing-test-tag=s'  => \$fuzzing_test_tag,
+     'fuzzing-class=s'     => \$fuzzing_class,
      'enable-recompile-check' => \$enable_recompilation_warnings_check,
 +    'enable-profile-coverage-check' => \$enable_profile_coverage_check,
      'enable-ip-resolve' => \$enable_client_ip_resolve_test,
      'enable-distcheck'  => \$enable_make_distcheck,
 -    'enable-all'        => \$enable_all,
      'List-mode'         => \$list_mode,
 +    'test-limit=i'      => \$test_limit,
      'enable-valgrind'   => \$use_valgrind,
 +    'enable-all'        => \$enable_all,
      'valgrind-path=s'   => \$valgrindCmd,
      'output-dir=s'      => \$output_dir,
      'diff'              => \$diff_mode,
@@@ -1389,82 -1210,26 +1529,101 @@@ my @tests = 
          'server_conf' => $cf{'nat'},
          '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 $cf{'def'} -a $cf{'ecb_mode_access'} " .
 +            "-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 $cf{'def'} -a $cf{'cfb_mode_access'} " .
 +            "-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 $cf{'def'} -a $cf{'ctr_mode_access'} " .
 +            "-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 $cf{'def'} -a $cf{'ofb_mode_access'} " .
 +            "-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 $cf{'def'} -a $cf{'def_access'} " .
 +            "-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
 +    },
  
+     ### --pcap-file
+     {
+         'category' => 'Rijndael SPA',
+         'subcategory' => 'client+server',
+         'detail'   => '--pcap-file processing',
+         'err_msg'  => 'could not complete SPA cycle',
+         'function' => \&process_pcap_file_directly,
+         'cmdline'  => '',
+         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
+             "$fwknopdCmd $default_server_conf_args " .
+             "--pcap-file $replay_pcap_file --foreground --verbose --verbose " .
+             "--verbose",
+         'server_positive_output_matches' => [qr/Replay\sdetected/i,
+             qr/candidate\sSPA/, qr/0x0000\:\s+2b/],
+         'fw_rule_created' => $NEW_RULE_REQUIRED,
+         'fw_rule_removed' => $NEW_RULE_REMOVED,
+         'fatal'    => $NO
+     },
      {
          'category' => 'Rijndael SPA',
          'subcategory' => 'client+server',
          'fatal'    => $NO
      },
  
+     ### command execution tests
+     {
+         'category' => 'Rijndael SPA',
+         'subcategory' => 'client+server',
+         'detail'   => 'command execution',
+         'err_msg'  => 'could not complete SPA cycle',
+         'function' => \&spa_cmd_exec_cycle,
+         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
+             qq|$fwknopCmd --server-cmd "echo fwknoptest > $cmd_exec_test_file" | .
+             "-a $fake_ip -D $loopback_ip --get-key $local_key_file " .
+             "--verbose --verbose",
+         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
+             "$fwknopdCmd -c $cf{'def'} -a $cf{'cmd_access'} " .
+             "-d $default_digest_file -p $default_pid_file $intf_str",
+         'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
+         'fatal'    => $NO
+     },
      {
          'category' => 'Rijndael SPA',
 +        'subcategory' => 'client+server',
 +        'detail'   => 'replay detection (Rijndael prefix)',
 +        'err_msg'  => 'could not detect replay attack',
 +        'function' => \&replay_detection,
 +        'pkt_prefix' => 'U2FsdGVkX1',
 +        'cmdline'  => $default_client_args,
 +        'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
 +            "$fwknopdCmd $default_server_conf_args $intf_str",
 +        'fatal'    => $NO
 +    },
 +    {
 +        'category' => 'Rijndael SPA',
          'subcategory' => 'server',
          'detail'   => 'digest cache structure',
          'err_msg'  => 'improper digest cache structure',
@@@ -4320,8 -5620,24 +6344,25 @@@ sub usage() 
      --enable-recompile            - Recompile fwknop sources and look for
                                      compilation warnings.
      --enable-valgrind             - Run every test underneath valgrind.
+     --enable-ip-resolve           - Enable client IP resolution (-R) test -
+                                     this requires internet access.
+     --enable-distcheck            - Enable 'make dist' check.
+     --enable-perl-module-checks   - Run a series of tests against libfko via
+                                     the perl FKO module.
+     --enable-perl-module-pkt-gen  - Generate a series of fuzzing packets via
+                                     the perl FKO module (assumes a patched
+                                     libfko code to accept fuzzing values). The
+                                     generated packets are placed in:
+                                     $fuzzing_pkts_file
+     --enable-all                  - Enable tests that aren't enabled by
+                                     default, except that --enable-valgrind
+                                     must also be set if valgrind mode is
+                                     desired.
+     --fuzzing-pkts-file <file>    - Specify path to fuzzing packet file.
+     --fuzzing-pkts-append         - When generating new fuzzing packets,
+                                     append them to the fuzzing packets file.
      --List                        - List test names.
 +    --test-limit=<num>            - Limit the number of tests that will run.
      --loopback-intf=<intf>        - Specify loopback interface name (default
                                      depends on the OS where the test suite
                                      is executed).