diff --git a/Makefile.am b/Makefile.am index 251b17c2..de4b6039 100644 --- a/Makefile.am +++ b/Makefile.am @@ -362,16 +362,19 @@ EXTRA_DIST = \ test/afl/fuzzing-wrappers/helpers/fwknopd-parse-conf.sh \ test/afl/fuzzing-wrappers/helpers/fwknopd-stdin-hangs.sh \ test/afl/fuzzing-wrappers/helpers/fwknopd-stdin-test.sh \ + test/afl/fuzzing-wrappers/helpers/fwknopd-enc-pkt-file.sh \ test/afl/fuzzing-wrappers/server-access.sh \ test/afl/fuzzing-wrappers/server-conf.sh \ test/afl/fuzzing-wrappers/server-digest-cache.sh \ test/afl/fuzzing-wrappers/spa-pkts.sh \ + test/afl/fuzzing-wrappers/server-enc-pkts.sh \ test/afl/test-cases/client-rc/fwknoprc \ test/afl/test-cases/server-access/access.conf \ test/afl/test-cases/server-conf/fwknopd.conf \ test/afl/test-cases/spa-pkts/spa.start \ test/afl/test-cases/spa-pkts/spa2.start \ test/afl/test-cases/spa-pkts/spa3.start \ + test/afl/test-cases/enc-pkts/spa.enc \ test/tests/build_security.pl \ test/tests/preliminaries.pl \ test/tests/code_structure.pl \ diff --git a/lib/cipher_funcs.c b/lib/cipher_funcs.c index b53a3f73..fa632511 100644 --- a/lib/cipher_funcs.c +++ b/lib/cipher_funcs.c @@ -331,6 +331,11 @@ add_salted_str(fko_ctx_t ctx) { char *tbuf; +#if AFL_FUZZING + ctx->added_salted_str = 1; + return(FKO_SUCCESS); +#endif + /* We only add the base64 encoded salt to data that is already base64 * encoded */ diff --git a/lib/fko.h b/lib/fko.h index 7a259bfa..2d9b216b 100644 --- a/lib/fko.h +++ b/lib/fko.h @@ -356,6 +356,10 @@ DLL_API int fko_set_raw_spa_digest(fko_ctx_t ctx); DLL_API int fko_set_spa_encryption_type(fko_ctx_t ctx, const short encrypt_type); DLL_API int fko_set_spa_encryption_mode(fko_ctx_t ctx, const int encrypt_mode); DLL_API int fko_set_spa_data(fko_ctx_t ctx, const char * const enc_msg); +#if AFL_FUZZING +DLL_API int fko_afl_set_spa_data(fko_ctx_t ctx, const char * const enc_msg, + const int enc_msg_len); +#endif DLL_API int fko_set_spa_hmac_type(fko_ctx_t ctx, const short hmac_type); /* Data processing and misc utility functions diff --git a/lib/fko_encryption.c b/lib/fko_encryption.c index f73bc46c..a485573a 100644 --- a/lib/fko_encryption.c +++ b/lib/fko_encryption.c @@ -164,7 +164,7 @@ _rijndael_decrypt(fko_ctx_t ctx, { unsigned char *ndx; unsigned char *cipher; - int cipher_len, pt_len, i, err = 0, res = FKO_SUCCESS; + int cipher_len=0, pt_len, i, err = 0, res = FKO_SUCCESS; int zero_free_rv = FKO_SUCCESS; if(key_len < 0 || key_len > RIJNDAEL_MAX_KEYSIZE) @@ -187,6 +187,10 @@ _rijndael_decrypt(fko_ctx_t ctx, if(cipher == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); +#if AFL_FUZZING + cipher_len = ctx->encrypted_msg_len; + memcpy(cipher, ctx->encrypted_msg, ctx->encrypted_msg_len); +#else if((cipher_len = b64_decode(ctx->encrypted_msg, cipher)) < 0) { if(zero_free((char *)cipher, ctx->encrypted_msg_len) == FKO_SUCCESS) @@ -194,6 +198,7 @@ _rijndael_decrypt(fko_ctx_t ctx, else return(FKO_ERROR_ZERO_OUT_DATA); } +#endif /* Since we're using AES, make sure the incoming data is a multiple of * the blocksize diff --git a/lib/fko_funcs.c b/lib/fko_funcs.c index 4a0814c9..e059ed24 100644 --- a/lib/fko_funcs.c +++ b/lib/fko_funcs.c @@ -597,4 +597,39 @@ fko_set_spa_data(fko_ctx_t ctx, const char * const enc_msg) return(FKO_SUCCESS); } +#if AFL_FUZZING +/* provide a way to set the encrypted data directly without base64 encoding. + * This allows direct AFL fuzzing against decryption routines. +*/ +int +fko_afl_set_spa_data(fko_ctx_t ctx, const char * const enc_msg, const int enc_msg_len) +{ + /* Must be initialized + */ + if(!CTX_INITIALIZED(ctx)) + return FKO_ERROR_CTX_NOT_INITIALIZED; + + if(enc_msg == NULL) + return(FKO_ERROR_INVALID_DATA_FUNCS_SET_MSGLEN_VALIDFAIL); + + if(! is_valid_encoded_msg_len(enc_msg_len)) + return(FKO_ERROR_INVALID_DATA_FUNCS_SET_MSGLEN_VALIDFAIL); + + if(ctx->encrypted_msg != NULL) + free(ctx->encrypted_msg); + + /* Copy the raw encrypted data into the context + */ + ctx->encrypted_msg = calloc(1, enc_msg_len); + if(ctx->encrypted_msg == NULL) + return(FKO_ERROR_MEMORY_ALLOCATION); + + memcpy(ctx->encrypted_msg, enc_msg, enc_msg_len); + + ctx->encrypted_msg_len = enc_msg_len; + + return(FKO_SUCCESS); +} +#endif + /***EOF***/ diff --git a/server/cmd_opts.h b/server/cmd_opts.h index 9b18e2d4..c00358fc 100644 --- a/server/cmd_opts.h +++ b/server/cmd_opts.h @@ -127,6 +127,9 @@ static char *config_map[NUMBER_OF_CONFIG_ENTRIES] = { "GPG_EXE", "FIREWALL_EXE", "VERBOSE", +#if AFL_FUZZING + "AFL_PKT_FILE", +#endif "FAULT_INJECTION_TAG" }; @@ -137,6 +140,7 @@ enum { FW_LIST = 0x200, FW_LIST_ALL, FW_FLUSH, + AFL_PKT_FILE, GPG_HOME_DIR, GPG_EXE_PATH, FIREWD_DISABLE_CHECK_SUPPORT, @@ -161,6 +165,7 @@ static struct option cmd_opts[] = { {"access-file", 1, NULL, 'a'}, {"afl-fuzzing", 0, NULL, 'A'}, + {"afl-pkt-file", 1, NULL, AFL_PKT_FILE }, {"config-file", 1, NULL, 'c'}, {"packet-limit", 1, NULL, 'C'}, {"digest-file", 1, NULL, 'd'}, diff --git a/server/config_init.c b/server/config_init.c index d0a64463..463f755c 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -1036,6 +1036,15 @@ config_init(fko_srv_options_t *opts, int argc, char **argv) #else log_msg(LOG_ERR, "[*] fwknopd not compiled with AFL fuzzing support"); clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); +#endif + break; + case AFL_PKT_FILE: +#if AFL_FUZZING + opts->afl_fuzzing = 1; + set_config_entry(opts, CONF_AFL_PKT_FILE, optarg); +#else + log_msg(LOG_ERR, "[*] fwknopd not compiled with AFL fuzzing support"); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); #endif break; case 'a': diff --git a/server/fwknopd.c b/server/fwknopd.c index 3df5c517..fb0149ec 100644 --- a/server/fwknopd.c +++ b/server/fwknopd.c @@ -59,6 +59,7 @@ static void init_digest_cache(fko_srv_options_t *opts); static void set_locale(fko_srv_options_t *opts); static pid_t get_running_pid(const fko_srv_options_t *opts); #if AFL_FUZZING +static void afl_enc_pkt_from_file(fko_srv_options_t *opts); static void afl_pkt_from_stdin(fko_srv_options_t *opts); #endif @@ -187,7 +188,16 @@ main(int argc, char **argv) #if AFL_FUZZING /* SPA data from STDIN. */ if(opts.afl_fuzzing) - afl_pkt_from_stdin(&opts); + { + if(opts.config[CONF_AFL_PKT_FILE] != 0x0) + { + afl_enc_pkt_from_file(&opts); + } + else + { + afl_pkt_from_stdin(&opts); + } + } #endif /* Prepare the firewall - i.e. flush any old rules and (for iptables) @@ -290,6 +300,61 @@ static void set_locale(fko_srv_options_t *opts) } #if AFL_FUZZING +static void afl_enc_pkt_from_file(fko_srv_options_t *opts) +{ + FILE *fp = NULL; + fko_ctx_t decrypt_ctx = NULL; + unsigned char enc_spa_pkt[AFL_MAX_PKT_SIZE] = {0}, rc; + int res = 0, es = EXIT_SUCCESS, enc_msg_len; + char dump_buf[AFL_DUMP_CTX_SIZE]; + + fp = fopen(opts->config[CONF_AFL_PKT_FILE], "rb"); + if(fp != NULL) + { + enc_msg_len = 0; + while(fread(&rc, 1, 1, fp)) + { + enc_spa_pkt[enc_msg_len] = rc; + enc_msg_len++; + if(enc_msg_len == AFL_MAX_PKT_SIZE-1) + break; + } + fclose(fp); + + fko_new(&decrypt_ctx); + + res = fko_afl_set_spa_data(decrypt_ctx, (const char *)enc_spa_pkt, + enc_msg_len); + if(res == FKO_SUCCESS) + res = fko_decrypt_spa_data(decrypt_ctx, "fwknoptest", + strlen("fwknoptest")); + if(res == FKO_SUCCESS) + res = dump_ctx_to_buffer(decrypt_ctx, dump_buf, sizeof(dump_buf)); + if(res == FKO_SUCCESS) + log_msg(LOG_INFO, "%s", dump_buf); + else + log_msg(LOG_ERR, "Error (%d): %s", res, fko_errstr(res)); + + fko_destroy(decrypt_ctx); + + if(res == FKO_SUCCESS) + { + log_msg(LOG_INFO, "SPA packet decode: %s", fko_errstr(res)); + es = EXIT_SUCCESS; + } + else + { + log_msg(LOG_ERR, "Could not decode SPA packet: %s", fko_errstr(res)); + es = EXIT_FAILURE; + } + } + else + log_msg(LOG_ERR, "Could not acquire SPA packet from file: %s.", + opts->config[CONF_AFL_PKT_FILE]); + + clean_exit(opts, NO_FW_CLEANUP, es); +} + static void afl_pkt_from_stdin(fko_srv_options_t *opts) { FILE *fp = NULL; diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index f06b6e15..68a2db2a 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -305,6 +305,9 @@ enum { CONF_GPG_EXE, CONF_FIREWALL_EXE, CONF_VERBOSE, +#if AFL_FUZZING + CONF_AFL_PKT_FILE, +#endif CONF_FAULT_INJECTION_TAG, NUMBER_OF_CONFIG_ENTRIES /* Marks the end and number of entries */ diff --git a/server/replay_cache.c b/server/replay_cache.c index 638028eb..7fea6765 100644 --- a/server/replay_cache.c +++ b/server/replay_cache.c @@ -677,10 +677,16 @@ add_replay_dbm_cache(fko_srv_options_t *opts, char *digest) void free_replay_list(fko_srv_options_t *opts) { + struct digest_cache_list *digest_list_ptr = NULL, *digest_tmp = NULL; + #ifdef NO_DIGEST_CACHE return; #endif - struct digest_cache_list *digest_list_ptr = NULL, *digest_tmp = NULL; + +#if AFL_FUZZING + if(opts->afl_fuzzing) + return; +#endif if (opts->digest_cache == NULL) return;