/* * This code is designed to repeatedly call libfko functions multiple times * with and without calling fko_destroy(). This allows valgrind to verify * whether memory is properly handled between calls. In addition, libfko * functions are called with bogus inputs in order to validate how well libfko * validates input arguments. */ #include #include #include #include #include "fko.h" #define ENABLE_GPG_TESTS 0 #define FCN_CALLS 5 #define F_INT 100 #define CTX_DESTROY 0 #define NO_CTX_DESTROY 1 #define NEW_CTX 0 #define NO_NEW_CTX 1 #define DO_PRINT 1 #define NO_PRINT 2 #define NO_DIGEST 0 #define DO_DIGEST 1 #define RAW_DIGEST 2 #define MAX_LINE_LEN 3000 /* really long for fuzzing tests */ /* We use HMAC and encryption keys that are as long as the max * sizes since we pass in bogus key lengths. That is, libfko * functions cannot be expected to handle key lengths that are * longer than the key buffers themselves. */ #define ENC_KEY "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* 32 bytes (RIJNDAEL_MAX_KEYSIZE) */ #define HMAC_KEY "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* 136 bytes (SHA3_256_BLOCK_LEN) */ #define STR_8BYTES "12345678" #define STR_16BYTES "1234567890123456" #define STR_64BYTES "1234567890123456789012345678901234567890123456789012345678901234" #define SPA_MSG1 "1.1.1.1,tcp/22" #define SPA_MSG2 "123.123.123.123,tcp/22" #define SPA_NAT_MSG "1.2.3.4,1234" #define SERVER_AUTH_MSG "passwd" #define IS_EMPTY_LINE(x) ( \ x == '#' || x == '\n' || x == '\r' || x == ';' || x == '\0' \ ) static void display_ctx(fko_ctx_t ctx); static void test_loop(int new_ctx_flag, int destroy_ctx_flag); static void test_loop_compounded(void); #if FUZZING_INTERFACES static void spa_encoded_msg_fuzzing(void); #endif static void ctx_update(fko_ctx_t *ctx, int new_ctx_flag, int destroy_ctx_flag, int print_flag); static void spa_default_ctx(fko_ctx_t *ctx); static void spa_func_int(fko_ctx_t *ctx, char *name, int (*spa_func)(fko_ctx_t ctx, const int modifier), int min, int max, int final_val, int new_ctx_flag, int destroy_ctx_flag); static void spa_func_getset_int(fko_ctx_t *ctx, char *set_name, int (*spa_set)(fko_ctx_t ctx, const int modifier), char *get_name, int (*spa_get)(fko_ctx_t ctx, int *val), int min, int max, int final_val, int new_ctx_flag, int destroy_ctx_flag); static void spa_func_getset_short(fko_ctx_t *ctx, char *set_name, int (*spa_set)(fko_ctx_t ctx, const short modifier), char *get_name, int (*spa_get)(fko_ctx_t ctx, short *val), int min, int max, int final_val, int digest_flag, int new_ctx_flag, int destroy_ctx_flag); int spa_calls = 0; int spa_compounded_calls = 0; int main(void) { test_loop(NO_NEW_CTX, NO_CTX_DESTROY); test_loop(NEW_CTX, CTX_DESTROY); test_loop(NEW_CTX, NO_CTX_DESTROY); test_loop(NO_NEW_CTX, CTX_DESTROY); printf("\n[+] Total libfko function calls (before compounded tests): %d\n\n", spa_calls); printf("[+] Running compounded tests via: test_loop_compounded()...\n"); test_loop_compounded(); printf("\n[+] Total compounded function calls: %d\n", spa_compounded_calls); printf("[+] Total libfko function calls (after compounded tests): %d\n\n", spa_calls); #if FUZZING_INTERFACES printf("[+] libfko fuzzing by setting SPA buffer manually...\n"); spa_encoded_msg_fuzzing(); #endif return 0; } #if FUZZING_INTERFACES static void spa_encoded_msg_fuzzing(void) { fko_ctx_t decode_ctx = NULL, decrypt_ctx = NULL; int res = 0, pkt_id, require_success, require_digest, digest_type, msg_len; int line_ctr = 0, spa_payload_ctr = 0; FILE *fz = NULL; char line[MAX_LINE_LEN] = {0}; char *spa_data_final = NULL, *spa_data_copy = NULL; char b64_encoded_msg[MAX_LINE_LEN] = {0}; unsigned char b64_decoded_msg[MAX_LINE_LEN] = {0}; /* fuzzing file contents are formatted like this (and are generated by the spa_fuzzing.py * python fuzzer): * * */ if ((fz = fopen("fuzz_spa_payloads", "r")) == NULL) return; while ((fgets(line, MAX_LINE_LEN, fz)) != NULL) { line_ctr++; line[MAX_LINE_LEN-1] = '\0'; if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0'; if(IS_EMPTY_LINE(line[0])) continue; if(sscanf(line, "%d %d %d %d %s", &pkt_id, &require_success, &require_digest, &digest_type, b64_encoded_msg) != 5) { printf("[+] fuzzing parsing error at line: %d\n", line_ctr); continue; } msg_len = fko_base64_decode(b64_encoded_msg, b64_decoded_msg); spa_payload_ctr++; fko_new(&decode_ctx); if ((res = fko_set_encoded_data(decode_ctx, (char *) b64_decoded_msg, msg_len, require_digest, digest_type)) != FKO_SUCCESS) { printf("[-] pkt_id: %d, fko_set_encoded_data(): %s\n", pkt_id, fko_errstr(res)); } res = fko_decode_spa_data(decode_ctx); if (require_success) { if (res != FKO_SUCCESS) { printf("[-] pkt_id: %d, expected decode success but: fko_decode_spa_data(): %s\n", pkt_id, fko_errstr(res)); } } else { if (res == FKO_SUCCESS) { printf("[-] pkt_id: %d, expected decode failure but: fko_decode_spa_data(): %s\n", pkt_id, fko_errstr(res)); } } /* decode again for good measure */ res = fko_decode_spa_data(decode_ctx); if (require_success) { if (res != FKO_SUCCESS) { printf("[-] pkt_id: %d, expected decode success but: fko_decode_spa_data(): %s\n", pkt_id, fko_errstr(res)); } } else { if (res == FKO_SUCCESS) { printf("[-] pkt_id: %d, expected decode failure but: fko_decode_spa_data(): %s\n", pkt_id, fko_errstr(res)); } } if (0) { fko_destroy(decode_ctx); decode_ctx = NULL; } fko_set_spa_hmac_type(decode_ctx, FKO_HMAC_SHA256); res = fko_spa_data_final(decode_ctx, ENC_KEY, strlen(ENC_KEY), HMAC_KEY, strlen(HMAC_KEY)); if (res == FKO_SUCCESS) { if ((res = fko_get_spa_data(decode_ctx, &spa_data_final)) != FKO_SUCCESS) { printf("fko_get_spa_data(): %s\n", fko_errstr(res)); } else { printf("PKT_ID: %d, PKT: %s\n", pkt_id, spa_data_final); spa_data_copy = strdup(spa_data_final); if (spa_data_final != NULL) memset(spa_data_final, 0x0, strlen(spa_data_final)); fko_destroy(decode_ctx); decode_ctx = NULL; res = fko_new_with_data(&decrypt_ctx, spa_data_copy, ENC_KEY, strlen(ENC_KEY), FKO_ENC_MODE_CBC, HMAC_KEY, strlen(HMAC_KEY), FKO_HMAC_SHA256); if (spa_data_copy != NULL) { memset(spa_data_copy, 0x0, strlen(spa_data_copy)); free(spa_data_copy); } if (res == FKO_SUCCESS) { printf("pkt_id: %d Success\n", pkt_id); } else { printf("fko_new_with_data(): %s\n", fko_errstr(res)); } fko_destroy(decrypt_ctx); decrypt_ctx = NULL; } } else { printf("fko_spa_data_final(): %s\n", fko_errstr(res)); fko_destroy(decode_ctx); decode_ctx = NULL; } memset(line, 0x0, MAX_LINE_LEN); memset(b64_encoded_msg, 0x0, MAX_LINE_LEN); memset(b64_decoded_msg, 0x0, MAX_LINE_LEN); } fclose(fz); printf("[+] Sent %d SPA payloads through libfko encode/decode cycle...\n", spa_payload_ctr); return; } #endif static void ctx_set_null_vals(fko_ctx_t *ctx) { fko_set_rand_value(*ctx, NULL); fko_set_username(*ctx, NULL); fko_set_spa_message(*ctx, NULL); fko_set_spa_nat_access(*ctx, NULL); fko_set_spa_server_auth(*ctx, NULL); fko_set_spa_data(*ctx, NULL); fko_set_timestamp(*ctx, 0); fko_set_spa_message_type(*ctx, 0); fko_set_spa_message(*ctx, NULL); fko_set_spa_nat_access(*ctx, NULL); fko_set_spa_server_auth(*ctx, NULL); fko_set_spa_client_timeout(*ctx, 0); fko_set_spa_digest_type(*ctx, 0); fko_set_spa_digest(*ctx); fko_set_spa_hmac_type(*ctx, 0); fko_set_spa_encryption_mode(*ctx, 0); fko_set_spa_data(*ctx, NULL); fko_set_spa_hmac(*ctx, NULL, 0); fko_set_raw_spa_digest_type(*ctx, 0); fko_set_raw_spa_digest(*ctx); spa_calls += 20; return; } static void ctx_add_dupe_data(fko_ctx_t *ctx) { fko_set_rand_value(*ctx, STR_8BYTES); fko_set_rand_value(*ctx, STR_16BYTES); fko_set_rand_value(*ctx, STR_16BYTES); fko_set_username(*ctx, STR_64BYTES); fko_set_username(*ctx, STR_64BYTES); fko_set_timestamp(*ctx, 12345); fko_set_timestamp(*ctx, 12345); fko_set_spa_message_type(*ctx, FKO_ACCESS_MSG); fko_set_spa_message_type(*ctx, FKO_ACCESS_MSG); fko_set_spa_message(*ctx, SPA_MSG1); fko_set_spa_message(*ctx, SPA_MSG1); fko_set_spa_nat_access(*ctx, SPA_NAT_MSG); fko_set_spa_nat_access(*ctx, SPA_NAT_MSG); fko_set_spa_server_auth(*ctx, SERVER_AUTH_MSG); fko_set_spa_server_auth(*ctx, SERVER_AUTH_MSG); fko_set_spa_client_timeout(*ctx, 30); fko_set_spa_client_timeout(*ctx, 30); fko_set_spa_digest_type(*ctx, FKO_DEFAULT_DIGEST); fko_set_spa_digest_type(*ctx, FKO_DEFAULT_DIGEST); fko_set_spa_hmac_type(*ctx, FKO_DEFAULT_HMAC_MODE); fko_set_spa_hmac_type(*ctx, FKO_DEFAULT_HMAC_MODE); fko_set_spa_encryption_mode(*ctx, FKO_ENC_MODE_CBC); fko_set_spa_encryption_mode(*ctx, FKO_ENC_MODE_CBC); fko_set_spa_data(*ctx, STR_8BYTES); fko_set_spa_data(*ctx, STR_64BYTES); spa_calls += 24; return; } static void test_loop_compounded(void) { fko_ctx_t ctx = NULL, decrypt_ctx = NULL; char *spa_data = NULL; int i, j, k, l, res; for (i=0; i" : spa_data); ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT); } printf("fko_new_with_data(): %s (data: %s)\n", fko_errstr(fko_new_with_data(&decrypt_ctx, spa_data, NULL, 0, FKO_ENC_MODE_CBC, NULL, 0, FKO_HMAC_SHA256)), spa_data); /* verify hmac, decrypt, and display ctx all together*/ for (i=0; i" : rand_val); printf(" Username: %s\n", username == NULL ? "" : username); printf(" Timestamp: %u\n", (unsigned int) timestamp); printf(" FKO Version: %s\n", version == NULL ? "" : version); printf(" Message Type: %i\n", msg_type); printf(" Message String: %s\n", spa_message == NULL ? "" : spa_message); printf(" Nat Access: %s\n", nat_access == NULL ? "" : nat_access); printf(" Server Auth: %s\n", server_auth == NULL ? "" : server_auth); printf(" Client Timeout: %d\n", client_timeout); printf(" Digest Type: %d\n", digest_type); printf(" HMAC Type: %d\n", hmac_type); printf("Encryption Mode: %d\n", encryption_mode); printf(" Encoded Data: %s\n", enc_data == NULL ? "" : enc_data); printf("SPA Data Digest: %s\n", spa_digest == NULL ? "" : spa_digest); printf(" HMAC: %s\n", hmac_data == NULL ? "" : hmac_data); printf(" Final SPA Data: %s\n", spa_data); spa_calls += 31; return; }