From 9cd1409047efb42cdeb0ec262b05b0c735fd6965 Mon Sep 17 00:00:00 2001 From: Viktor Krikun Date: Sun, 27 Nov 2011 21:47:26 +0000 Subject: [PATCH] Add more unit-tests and bug-fixes for random-access ZRTP cache (refs #24) --- include/zrtp_iface_cache.h | 2 +- src/zrtp_iface_cache.c | 143 +++++++---- test/cache_test.c | 497 ++++++++++++++++++++++++++++++++----- test/pc/zrtp_test_core.c | 4 +- 4 files changed, 535 insertions(+), 111 deletions(-) diff --git a/include/zrtp_iface_cache.h b/include/zrtp_iface_cache.h index 81d8fbd359..0bdde3cf92 100644 --- a/include/zrtp_iface_cache.h +++ b/include/zrtp_iface_cache.h @@ -136,7 +136,7 @@ void zrtp_def_cache_foreach( zrtp_global_t *global, * May be used in server solutions for periodically flushing the cache to prevent data loss. * * @return - * - zrtp_status_ok - if operation complited successfully; + * - zrtp_status_ok - if operation completed successfully; * - zrtp_status_wrong_state - if a call is performed from a routine which * doesn't use the default cache. */ diff --git a/src/zrtp_iface_cache.c b/src/zrtp_iface_cache.c index e28bb7bee7..b3e1500f3d 100644 --- a/src/zrtp_iface_cache.c +++ b/src/zrtp_iface_cache.c @@ -22,13 +22,14 @@ static uint32_t g_cache_elems_counter = 0; static mlist_t mitmcache_head; static uint32_t g_mitmcache_elems_counter = 0; static uint8_t inited = 0; +static uint8_t g_needs_rewriting = 0; static zrtp_global_t* zrtp; static zrtp_mutex_t* def_cache_protector = NULL; /* Create cache ID like a pair of ZIDs. ZID with lowest value at the beginning */ -static void cache_create_id( const zrtp_stringn_t* first_ZID, +void zrtp_cache_create_id( const zrtp_stringn_t* first_ZID, const zrtp_stringn_t* second_ZID, zrtp_cache_id_t id); @@ -110,7 +111,7 @@ zrtp_status_t zrtp_def_cache_set_verified( const zrtp_stringn_t* one_ZID, zrtp_cache_elem_t* new_elem = NULL; ZRTP_CACHE_CHECK_ZID(one_ZID, another_ZID); - cache_create_id(one_ZID, another_ZID, id); + zrtp_cache_create_id(one_ZID, another_ZID, id); zrtp_mutex_lock(def_cache_protector); new_elem = get_elem(id, 0); @@ -131,7 +132,7 @@ zrtp_status_t zrtp_def_cache_get_verified( const zrtp_stringn_t* one_ZID, zrtp_cache_elem_t* elem = NULL; ZRTP_CACHE_CHECK_ZID(one_ZID, another_ZID); - cache_create_id(one_ZID, another_ZID, id); + zrtp_cache_create_id(one_ZID, another_ZID, id); zrtp_mutex_lock(def_cache_protector); elem = get_elem(id, 0); @@ -154,7 +155,15 @@ static zrtp_status_t cache_put( const zrtp_stringn_t* one_ZID, zrtp_cache_id_t id; ZRTP_CACHE_CHECK_ZID(one_ZID, another_ZID); - cache_create_id(one_ZID, another_ZID, id); + zrtp_cache_create_id(one_ZID, another_ZID, id); + + { + char zid1str[24+1], zid2str[24+1]; + ZRTP_LOG(3,(_ZTU_,"\tcache_put() zid1=%s, zis2=%s MiTM=%s\n", + hex2str(one_ZID->buffer, one_ZID->length, zid1str, sizeof(zid1str)), + hex2str(another_ZID->buffer, another_ZID->length, zid2str, sizeof(zid2str)), + is_mitm?"YES":"NO")); + } zrtp_mutex_lock(def_cache_protector); do { @@ -180,6 +189,11 @@ static zrtp_status_t cache_put( const zrtp_stringn_t* one_ZID, } else { new_elem->_index = g_cache_elems_counter++; } + + ZRTP_LOG(3,(_ZTU_,"\tcache_put() can't find element in the cache - create a new entry index=%u.\n", new_elem->_index)); + } + else { + ZRTP_LOG(3,(_ZTU_,"\tcache_put() Just update existing value.\n")); } /* Save current cache value as previous one and new as a current */ @@ -225,15 +239,24 @@ static zrtp_status_t cache_get( const zrtp_stringn_t* one_ZID, zrtp_cache_elem_t* curr = 0; zrtp_cache_id_t id; zrtp_status_t s = zrtp_status_ok; + + { + char zid1str[24+1], zid2str[24+1]; + ZRTP_LOG(3,(_ZTU_,"\tache_get(): zid1=%s, zis2=%s MiTM=%s\n", + hex2str(one_ZID->buffer, one_ZID->length, zid1str, sizeof(zid1str)), + hex2str(another_ZID->buffer, another_ZID->length, zid2str, sizeof(zid2str)), + is_mitm?"YES":"NO")); + } ZRTP_CACHE_CHECK_ZID(one_ZID, another_ZID); - cache_create_id(one_ZID, another_ZID, id); + zrtp_cache_create_id(one_ZID, another_ZID, id); zrtp_mutex_lock(def_cache_protector); do { curr = get_elem(id, is_mitm); if (!curr || (!curr->prev_cache.length && prev_requested)) { s = zrtp_status_fail; + ZRTP_LOG(3,(_ZTU_,"\tache_get() - not found.\n")); break; } @@ -241,7 +264,7 @@ static zrtp_status_t cache_get( const zrtp_stringn_t* one_ZID, prev_requested ? ZSTR_GV(curr->prev_cache) : ZSTR_GV(curr->curr_cache)); rss->lastused_at = curr->lastused_at; - if (!is_mitm) { + if (!is_mitm) { rss->ttl = curr->ttl; } } while (0); @@ -274,12 +297,11 @@ zrtp_status_t zrtp_def_cache_set_presh_counter( const zrtp_stringn_t* one_zid, zrtp_cache_id_t id; ZRTP_CACHE_CHECK_ZID(one_zid, another_zid); - cache_create_id(one_zid, another_zid, id); + zrtp_cache_create_id(one_zid, another_zid, id); zrtp_mutex_lock(def_cache_protector); new_elem = get_elem(id, 0); if (new_elem) { - ZRTP_LOG(3,(_ZTU_,"\tTEST! Update counter to %u.\n", counter)); new_elem->presh_counter = counter; new_elem->_is_dirty = 1; @@ -297,12 +319,11 @@ zrtp_status_t zrtp_def_cache_get_presh_counter( const zrtp_stringn_t* one_zid, zrtp_cache_id_t id; ZRTP_CACHE_CHECK_ZID(one_zid, another_zid); - cache_create_id(one_zid, another_zid, id); + zrtp_cache_create_id(one_zid, another_zid, id); zrtp_mutex_lock(def_cache_protector); new_elem = get_elem(id, 0); if (new_elem) { - ZRTP_LOG(3,(_ZTU_,"\tTEST! Return counter to %u.\n", new_elem->presh_counter)); *counter = new_elem->presh_counter; } zrtp_mutex_unlock(def_cache_protector); @@ -311,7 +332,7 @@ zrtp_status_t zrtp_def_cache_get_presh_counter( const zrtp_stringn_t* one_zid, } /*-----------------------------------------------------------------------------*/ -static void cache_create_id( const zrtp_stringn_t* first_ZID, + void zrtp_cache_create_id( const zrtp_stringn_t* first_ZID, const zrtp_stringn_t* second_ZID, zrtp_cache_id_t id ) { @@ -408,6 +429,10 @@ zrtp_status_t zrtp_cache_user_init() unsigned is_unsupported = 0; ZRTP_LOG(3,(_ZTU_,"\tLoad ZRTP cache from <%s>...\n", zrtp->def_cache_path.buffer)); + + g_mitmcache_elems_counter = 0; + g_cache_elems_counter = 0; + g_needs_rewriting = 0; /* Try to open existing file. If ther is no cache file - start with empty cache */ #if (ZRTP_PLATFORM == ZP_WIN32) @@ -456,8 +481,6 @@ zrtp_status_t zrtp_cache_user_init() fclose(cache_file); return zrtp_status_ok; } - - g_mitmcache_elems_counter = 0; /* * Load MitM caches: first 32 bits is a MiTM secrets counter. Read it and then @@ -517,8 +540,6 @@ zrtp_status_t zrtp_cache_user_init() } cache_elems_count = zrtp_ntoh32(cache_elems_count); - g_cache_elems_counter = 0; - ZRTP_LOG(3,(_ZTU_,"\tZRTP cache file contains %u RS secrets.\n", cache_elems_count)); for (i=0; i_index * ZRTP_MITMCACHE_ELEM_LENGTH); - printf("flush_elem_(): \t pos=%u (Header, MiTM Count + %u MiTM Secrets).\n", pos, elem->_index); +// printf("flush_elem_(): \t pos=%u (Header, MiTM Count + %u MiTM Secrets).\n", pos, elem->_index); } else { /* Skip MiTM Secrets block */ pos += (g_mitmcache_elems_counter * ZRTP_MITMCACHE_ELEM_LENGTH); @@ -595,7 +618,7 @@ static zrtp_status_t flush_elem_(zrtp_cache_elem_t *elem, FILE *cache_file, unsi pos += (elem->_index * ZRTP_CACHE_ELEM_LENGTH); /* Skip previous RS elements */ - printf("flush_elem_(): \t pos=%u (Header, MiTM Count + ALL %u Secrets, RS counter and %u prev. RS).\n", pos, g_mitmcache_elems_counter, elem->_index); +// printf("flush_elem_(): \t pos=%u (Header, MiTM Count + ALL %u Secrets, RS counter and %u prev. RS).\n", pos, g_mitmcache_elems_counter, elem->_index); } fseek(cache_file, pos, SEEK_SET); @@ -603,16 +626,16 @@ static zrtp_status_t flush_elem_(zrtp_cache_elem_t *elem, FILE *cache_file, unsi /* Prepare element for storing, convert all fields to the network byte-order. */ cache_make_cross(elem, &tmp_elem, 0); - printf("flush_elem_(): write to offset=%lu\n", ftell(cache_file)); +// printf("flush_elem_(): write to offset=%lu\n", ftell(cache_file)); /* Flush the element. */ if (fwrite(&tmp_elem, (is_mitm ? ZRTP_MITMCACHE_ELEM_LENGTH : ZRTP_CACHE_ELEM_LENGTH), 1, cache_file) != 1) { - printf("flush_elem_(): ERROR!!! write failed!\n"); +// printf("flush_elem_(): ERROR!!! write failed!\n"); return zrtp_status_write_fail; } else { elem->_is_dirty = 0; - printf("flush_elem_(): OK! %lu bytes were written\n", (is_mitm ? ZRTP_MITMCACHE_ELEM_LENGTH : ZRTP_CACHE_ELEM_LENGTH)); +// printf("flush_elem_(): OK! %lu bytes were written\n", (is_mitm ? ZRTP_MITMCACHE_ELEM_LENGTH : ZRTP_CACHE_ELEM_LENGTH)); return zrtp_status_ok; } } @@ -628,17 +651,23 @@ zrtp_status_t zrtp_cache_user_down() /* Open/create file for writing */ #if (ZRTP_PLATFORM == ZP_WIN32) - if (0 != fopen_s(&cache_file, zrtp->def_cache_path.buffer, "wb+")) { - ZRTP_LOG(2,(_ZTU_,"\tERROR! unable to open ZRTP cache file <%s>.\n", zrtp->def_cache_path.buffer)); - return zrtp_status_open_fail; + if (g_needs_rewriting || 0 != fopen_s(&cache_file, zrtp->def_cache_path.buffer, "r+")) { + if (0 != fopen_s(&cache_file, zrtp->def_cache_path.buffer, "w+")) { + ZRTP_LOG(2,(_ZTU_,"\tERROR! unable to open ZRTP cache file <%s>.\n", zrtp->def_cache_path.buffer)); + return zrtp_status_open_fail; + } } -#else - cache_file = fopen(zrtp->def_cache_path.buffer, "wb+"); - if (!cache_file) { - ZRTP_LOG(2,(_ZTU_,"\tERROR! unable to open ZRTP cache file <%s>.\n", zrtp->def_cache_path.buffer)); - return zrtp_status_open_fail; +#else + if (g_needs_rewriting || !(cache_file = fopen(zrtp->def_cache_path.buffer, "r+"))) { + cache_file = fopen(zrtp->def_cache_path.buffer, "w+"); + if (!cache_file) { + ZRTP_LOG(2,(_ZTU_,"\tERROR! unable to open ZRTP cache file <%s>.\n", zrtp->def_cache_path.buffer)); + return zrtp_status_open_fail; + } } #endif + + fseek(cache_file, 0, SEEK_SET); /* Store version string first. Format: &ZRTP_DEF_CACHE_VERSION_STR&ZRTP_DEF_CACHE_VERSION_VAL */ if (1 != fwrite(ZRTP_DEF_CACHE_VERSION_STR, strlen(ZRTP_DEF_CACHE_VERSION_STR), 1, cache_file)) { @@ -663,13 +692,13 @@ zrtp_status_t zrtp_cache_user_down() mlist_for_each(node, &mitmcache_head) { zrtp_cache_elem_t* elem = mlist_get_struct(zrtp_cache_elem_t, _mlist, node); /* Store dirty values only. */ - if (elem->_is_dirty) { - printf("zrtp_cache_user_down: Store MiTM elem index=%u, not modified.\n", elem->_index); + if (g_needs_rewriting || elem->_is_dirty) { +// printf("zrtp_cache_user_down: Store MiTM elem index=%u, not modified.\n", elem->_index); if (zrtp_status_ok != flush_elem_(elem, cache_file, 1)) { ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); } } else { - printf("zrtp_cache_user_down: Skip MiTM elem index=%u, not modified.\n", elem->_index); +// printf("zrtp_cache_user_down: Skip MiTM elem index=%u, not modified.\n", elem->_index); } } @@ -700,14 +729,15 @@ zrtp_status_t zrtp_cache_user_down() zrtp_cache_elem_t* elem = mlist_get_struct(zrtp_cache_elem_t, _mlist, node); /* Store dirty values only. */ - if (elem->_is_dirty) { - printf("zrtp_cache_user_down: Store RS elem index=%u, not modified.\n", elem->_index); + if (g_needs_rewriting || elem->_is_dirty) { +// printf("zrtp_cache_user_down: Store RS elem index=%u, not modified.\n", elem->_index); if (zrtp_status_ok != flush_elem_(elem, cache_file, 0)) { ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); } - } else { - printf("zrtp_cache_user_down: Skip RS elem index=%u, not modified.\n", elem->_index); } +// else { +// printf("zrtp_cache_user_down: Skip RS elem index=%u, not modified.\n", elem->_index); +// } } fseek(cache_file, pos, SEEK_SET); @@ -717,6 +747,8 @@ zrtp_status_t zrtp_cache_user_down() ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); } ZRTP_LOG(3,(_ZTU_,"\t%u regular cache entries have been stored successfully.\n", zrtp_ntoh32(count))); + + g_needs_rewriting = 0; ZRTP_DOWN_CACHE_RETURN(zrtp_status_ok, cache_file); } @@ -739,7 +771,7 @@ static zrtp_status_t put_name( const zrtp_stringn_t* one_ZID, zrtp_status_t s = zrtp_status_ok; ZRTP_CACHE_CHECK_ZID(one_ZID, another_ZID); - cache_create_id(one_ZID, another_ZID, id); + zrtp_cache_create_id(one_ZID, another_ZID, id); zrtp_mutex_lock(def_cache_protector); do { @@ -781,7 +813,7 @@ static zrtp_status_t get_name( const zrtp_stringn_t* one_ZID, zrtp_status_t s = zrtp_status_fail; ZRTP_CACHE_CHECK_ZID(one_ZID, another_ZID); - cache_create_id(one_ZID, another_ZID, id); + zrtp_cache_create_id(one_ZID, another_ZID, id); zrtp_mutex_lock(def_cache_protector); do { @@ -817,7 +849,7 @@ zrtp_status_t zrtp_def_cache_get_since( const zrtp_stringn_t* one_ZID, zrtp_cache_id_t id; ZRTP_CACHE_CHECK_ZID(one_ZID, another_ZID); - cache_create_id(one_ZID, another_ZID, id); + zrtp_cache_create_id(one_ZID, another_ZID, id); zrtp_mutex_lock(def_cache_protector); new_elem = get_elem(id, 0); @@ -836,7 +868,7 @@ zrtp_status_t zrtp_def_cache_reset_since( const zrtp_stringn_t* one_zid, zrtp_cache_id_t id; ZRTP_CACHE_CHECK_ZID(one_zid, another_zid); - cache_create_id(one_zid, another_zid, id); + zrtp_cache_create_id(one_zid, another_zid, id); zrtp_mutex_lock(def_cache_protector); new_elem = get_elem(id, 0); @@ -858,23 +890,44 @@ void zrtp_def_cache_foreach( zrtp_global_t *global, void *data) { int delete, result; + unsigned index_decrease = 0; mlist_t* node = NULL, *tmp_node = NULL; - zrtp_mutex_lock(def_cache_protector); + zrtp_mutex_lock(def_cache_protector); mlist_for_each_safe(node, tmp_node, (is_mitm ? &mitmcache_head : &cache_head)) - { + { zrtp_cache_elem_t* elem = mlist_get_struct(zrtp_cache_elem_t, _mlist, node); + + /* + * We are about to delete cache element, in order to keep our + * random-access file working, we should re-arrange indexes of + * cache elements go after the deleting one. + */ + if (index_decrease >0) { + elem->_index -= index_decrease; + } + + delete = 0; result = callback(elem, is_mitm, data, &delete); if (delete) { + { + char idstr[24*2+1]; + ZRTP_LOG(3,(_ZTU_,"\zrtp_def_cache_foreach() Delete element id=%s index=%u\n", + hex2str(elem->id, sizeof(elem->id), idstr, sizeof(idstr)), + elem->_index)); + } + + index_decrease++; + mlist_del(&elem->_mlist); + /* Decrement global cache counter. */ if (is_mitm) g_mitmcache_elems_counter--; else g_cache_elems_counter--; - - // TODO: rearrange INDEXES here! + g_needs_rewriting = 1; } if (!result) { break; diff --git a/test/cache_test.c b/test/cache_test.c index 7a4fbef707..8ba699ee3f 100644 --- a/test/cache_test.c +++ b/test/cache_test.c @@ -1,3 +1,12 @@ +/* + * libZRTP SDK library, implements the ZRTP secure VoIP protocol. + * Copyright (c) 2006-2009 Philip R. Zimmermann. All rights reserved. + * Contact: http://philzimmermann.com + * For licensing and other legal details, see the file zrtp_legal.c. + * + * Viktor Krykun + */ + #include #include #include @@ -11,38 +20,88 @@ static zrtp_global_t g_zrtp_cfg; +static zrtp_string16_t zid_my = ZSTR_INIT_WITH_CONST_CSTRING("000000000_00"); +static zrtp_string16_t zid_a = ZSTR_INIT_WITH_CONST_CSTRING("000000000_02"); +static zrtp_string16_t zid_b = ZSTR_INIT_WITH_CONST_CSTRING("000000000_03"); +static zrtp_string16_t zid_c = ZSTR_INIT_WITH_CONST_CSTRING("000000000_04"); +static zrtp_string16_t zid_mitm1 = ZSTR_INIT_WITH_CONST_CSTRING("000000000_m1"); +static zrtp_string16_t zid_mitm2 = ZSTR_INIT_WITH_CONST_CSTRING("000000000_m2"); + +static zrtp_shared_secret_t rs_my4a, rs_my4b, rs_my4c, rs_my4mitm1, rs_my4mitm2; +static zrtp_shared_secret_t rs_my4a_r, rs_my4b_r, rs_my4c_r, rs_my4mitm1_r, rs_my4mitm2_r; + +static zrtp_cache_id_t secerets_to_delete[24]; +static unsigned secerets_to_delete_count = 0; + +static void init_rs_secret_(zrtp_shared_secret_t *sec, unsigned char val_fill); + +extern void zrtp_cache_create_id(const zrtp_stringn_t* first_ZID, + const zrtp_stringn_t* second_ZID, + zrtp_cache_id_t id); + + void cache_setup() { + zrtp_status_t status; + + /* Delete cache file from previous test if it exists. */ remove(TEST_CACHE_PATH); + secerets_to_delete_count = 0; + ZSTR_SET_EMPTY(g_zrtp_cfg.def_cache_path); /* Configure and Initialize ZRTP cache */ zrtp_zstrcpyc(ZSTR_GV(g_zrtp_cfg.def_cache_path), TEST_CACHE_PATH); + + init_rs_secret_(&rs_my4a, 'a'); init_rs_secret_(&rs_my4b, 'b'); init_rs_secret_(&rs_my4c, 'c'); + init_rs_secret_(&rs_my4mitm1, '1'); init_rs_secret_(&rs_my4mitm2, '2'); + + init_rs_secret_(&rs_my4a_r, 0); init_rs_secret_(&rs_my4b_r, 0); init_rs_secret_(&rs_my4c_r, 0); + init_rs_secret_(&rs_my4mitm1_r, 0); init_rs_secret_(&rs_my4mitm2_r, 0); + + /* It should NOT crash and return OK. */ + status = zrtp_def_cache_init(&g_zrtp_cfg); + assert_int_equal(status, zrtp_status_ok); + + /* Add few values into it */ + printf("==> Add few test entries.\n"); + + status = zrtp_def_cache_put(ZSTR_GV(zid_my), ZSTR_GV(zid_a), &rs_my4a); + assert_int_equal(status, zrtp_status_ok); + status = zrtp_def_cache_put(ZSTR_GV(zid_my), ZSTR_GV(zid_b), &rs_my4b); + assert_int_equal(status, zrtp_status_ok); + status = zrtp_def_cache_put(ZSTR_GV(zid_my), ZSTR_GV(zid_c), &rs_my4c); + assert_int_equal(status, zrtp_status_ok); + + status = zrtp_def_cache_put_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), &rs_my4mitm1); + assert_int_equal(status, zrtp_status_ok); + status = zrtp_def_cache_put_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm2), &rs_my4mitm2); + assert_int_equal(status, zrtp_status_ok); + + status = zrtp_def_cache_put(ZSTR_GV(zid_my), ZSTR_GV(zid_c), &rs_my4c); + assert_int_equal(status, zrtp_status_ok); + + /* Close the cache, it should be flushed to the file. */ + printf("==> Close the cache.\n"); + + zrtp_def_cache_down(); + + printf("==> Open just prepared cache file.\n"); + + status = zrtp_def_cache_init(&g_zrtp_cfg); + assert_int_equal(status, zrtp_status_ok); + + printf("==> Ready for the test!.\n"); } void cache_teardown() { zrtp_def_cache_down(); } -static void init_rs_secret_(zrtp_shared_secret_t *sec) { - ZSTR_SET_EMPTY(sec->value); - - sec->_cachedflag = 0; - sec->ttl = 0; - sec->lastused_at = 0; -} - - /* * Simply init ZRTP cache with empty or non-existing filer and close it. * The app should not crash and trigger no errors. */ void cache_init_store_empty_test() { - zrtp_status_t status; - - /* It should NOT crash and return OK. */ - status = zrtp_def_cache_init(&g_zrtp_cfg); - assert_int_equal(status, zrtp_status_ok); - zrtp_def_cache_down(); } @@ -51,77 +110,389 @@ void cache_init_store_empty_test() { * all the entries were restored successfully. */ void cache_add2empty_test() { - zrtp_status_t status; - + zrtp_status_t status; int intres; - zrtp_string16_t zid_my = ZSTR_INIT_WITH_CONST_CSTRING("000000000_01"); - zrtp_string16_t zid_a = ZSTR_INIT_WITH_CONST_CSTRING("000000000_02"); - zrtp_string16_t zid_b = ZSTR_INIT_WITH_CONST_CSTRING("000000000_03"); - zrtp_string16_t zid_c = ZSTR_INIT_WITH_CONST_CSTRING("000000000_04"); - zrtp_string16_t zid_mitm1 = ZSTR_INIT_WITH_CONST_CSTRING("000000000_04"); + /* Now, let's open the cache again and check if all the previously added values were restored successfully */ + printf("==> And open it again, it should contain all the stored values.\n"); - zrtp_shared_secret_t rs_my4a, rs_my4b, rs_my4c, rs_my4mitm1; - zrtp_shared_secret_t rs_my4a_r, rs_my4b_r, rs_my4c_r, rs_my4mitm1_r; + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_a), &rs_my4a_r, 0); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4a_r.value), ZSTR_GV(rs_my4a.value))); - init_rs_secret_(&rs_my4a); init_rs_secret_(&rs_my4b); - init_rs_secret_(&rs_my4c); init_rs_secret_(&rs_my4mitm1); + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_b), &rs_my4b_r, 0); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4b_r.value), ZSTR_GV(rs_my4b.value))); + + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), &rs_my4mitm1_r); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4mitm1_r.value), ZSTR_GV(rs_my4mitm1.value))); + + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm2), &rs_my4mitm2_r); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4mitm2_r.value), ZSTR_GV(rs_my4mitm2.value))); +} - init_rs_secret_(&rs_my4a_r); init_rs_secret_(&rs_my4b_r); - init_rs_secret_(&rs_my4c_r); init_rs_secret_(&rs_my4mitm1_r); - - printf("Open empty cache file for.\n"); - status = zrtp_def_cache_init(&g_zrtp_cfg); - assert_int_equal(status, zrtp_status_ok); - - /* Test if cache-init does bot corrupt config. */ - assert_false(strncmp(g_zrtp_cfg.def_cache_path.buffer, TEST_CACHE_PATH, strlen(TEST_CACHE_PATH))); - - /* Add few values into it */ - printf("Add few test entries.\n"); - - status = zrtp_def_cache_put(ZSTR_GV(zid_my), ZSTR_GV(zid_a), &rs_my4a); - assert_int_equal(status, zrtp_status_ok); - - status = zrtp_def_cache_put(ZSTR_GV(zid_my), ZSTR_GV(zid_b), &rs_my4b); - assert_int_equal(status, zrtp_status_ok); - - status = zrtp_def_cache_put_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), &rs_my4mitm1); - assert_int_equal(status, zrtp_status_ok); - - status = zrtp_def_cache_put(ZSTR_GV(zid_my), ZSTR_GV(zid_c), &rs_my4c); - assert_int_equal(status, zrtp_status_ok); - - /* Close the cache, it should be flushed to the file. */ - printf("Close the cache.\n"); - - zrtp_def_cache_down(); - - /* Test if cache-close does bot corrupt config. */ - assert_false(strncmp(g_zrtp_cfg.def_cache_path.buffer, TEST_CACHE_PATH, strlen(TEST_CACHE_PATH))); +/* + * Test if cache properly handles Open-Close-Open with now no changes to the cache values. + */ +void cache_save_unchanged_test() { + zrtp_status_t status; /* Now, let's open the cache again and check if all the previously added values were restored successfully */ - printf("And open it again, it should contain all the stored values.\n"); + printf("==> Now let's Open the cache and Close it right after, make no changes.\n"); + + zrtp_def_cache_down(); + + /* + * TEST: now let's store the cache making no changes to it. + * After opening it should include all the secrets untouched. + */ + + printf("==> And the cache again, it should contain all the stored values.\n"); status = zrtp_def_cache_init(&g_zrtp_cfg); assert_int_equal(status, zrtp_status_ok); status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_a), &rs_my4a_r, 0); assert_int_equal(status, zrtp_status_ok); - assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4a_r.value), ZSTR_GV(rs_my4a.value))); - /* Test if cache-close does bot corrupt config. */ - assert_false(strncmp(g_zrtp_cfg.def_cache_path.buffer, TEST_CACHE_PATH, strlen(TEST_CACHE_PATH))); + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_b), &rs_my4b_r, 0); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4b_r.value), ZSTR_GV(rs_my4b.value))); + + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), &rs_my4mitm1_r); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4mitm1_r.value), ZSTR_GV(rs_my4mitm1.value))); + + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm2), &rs_my4mitm2_r); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4mitm2_r.value), ZSTR_GV(rs_my4mitm2.value))); } +/* + * Check how the cache handles flushing of several dirty (modified) values. The cache should + * flush to the disk modified values only and leave rest of the items untouched. + */ +void cache_modify_and_save_test() { + zrtp_status_t status; + int intres; + + printf("==> And open it again, it should contain all the stored values.\n"); + + /* + * Now, let's modify just few entries and check of the fill will be stored. + * + * We will change RS secrets rs_my4b, rs_my4c and rs_my4mitm1 while leaving + * rs_my4a and rs_my4mitm2 untouched. + */ + + init_rs_secret_(&rs_my4b, 'x'); init_rs_secret_(&rs_my4c, 'y'); + init_rs_secret_(&rs_my4mitm1, 'z'); + + printf("==> Now we gonna to update few cache entries and flush the cache mack to the file.\n"); + + status = zrtp_def_cache_put(ZSTR_GV(zid_my), ZSTR_GV(zid_b), &rs_my4b); + assert_int_equal(status, zrtp_status_ok); + status = zrtp_def_cache_put(ZSTR_GV(zid_my), ZSTR_GV(zid_c), &rs_my4c); + assert_int_equal(status, zrtp_status_ok); + status = zrtp_def_cache_put_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), &rs_my4mitm1); + assert_int_equal(status, zrtp_status_ok); + + /* Flush the cache and open it again. */ + zrtp_def_cache_down(); + + printf("==> Open the cache and make sure all our prev. modifications saved properly.\n"); + + status = zrtp_def_cache_init(&g_zrtp_cfg); + assert_int_equal(status, zrtp_status_ok); + + /* Let's check if all our modifications are in place. */ + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_a), &rs_my4a_r, 0); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4a_r.value), ZSTR_GV(rs_my4a.value))); + + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_b), &rs_my4b_r, 0); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4b_r.value), ZSTR_GV(rs_my4b.value))); + + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_c), &rs_my4c_r, 0); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4c_r.value), ZSTR_GV(rs_my4c.value))); + + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), &rs_my4mitm1_r); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4mitm1_r.value), ZSTR_GV(rs_my4mitm1.value))); + + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm2), &rs_my4mitm2_r); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4mitm2_r.value), ZSTR_GV(rs_my4mitm2.value))); +} +/* + * The basic idea of all cache_delete_* tests is to delete few cache entries + * from preconfigured setup, flush caches, open the cache again and check if + * non-deleted values are Ok. + */ + +static int cache_foreach_del_func(zrtp_cache_elem_t* elem, int is_mitm, void* data, int* del) { + unsigned c; + + //printf("AAAA cache_foreach_del_func(): elem index=%u\n", elem->_index); + + for (c=0; cid, secerets_to_delete[c], sizeof(zrtp_cache_id_t))) { + printf("\t==> Delete cache element index=%u.\n", elem->_index); + *del = 1; + break; + } + } + + return 1; +} + +void cache_delete_few_rs_test() { + zrtp_status_t status; + + printf("==> Delete few RS secrets and flush the cache.\n"); + + secerets_to_delete_count = 0; + zrtp_cache_create_id(ZSTR_GV(zid_my), ZSTR_GV(zid_b), secerets_to_delete[secerets_to_delete_count++]); + zrtp_cache_create_id(ZSTR_GV(zid_my), ZSTR_GV(zid_a), secerets_to_delete[secerets_to_delete_count++]); + + zrtp_def_cache_foreach(&g_zrtp_cfg, 0, &cache_foreach_del_func, NULL); + + /* Flush the cache and open it again. */ + zrtp_def_cache_down(); + + printf("==> Open the cache and make sure all our prev. Modifications saved properly.\n"); + + status = zrtp_def_cache_init(&g_zrtp_cfg); + assert_int_equal(status, zrtp_status_ok); + + /* Let's check if all our modifications are in place. */ + + /* my4a should be deleted. */ + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_a), &rs_my4a_r, 0); + assert_int_not_equal(status, zrtp_status_ok); + + /* my4b should be deleted. */ + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_b), &rs_my4b_r, 0); + assert_int_not_equal(status, zrtp_status_ok); + + /* The rest of the secrets should be in place. */ + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_c), &rs_my4c_r, 0); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4c_r.value), ZSTR_GV(rs_my4c.value))); + + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), &rs_my4mitm1_r); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4mitm1_r.value), ZSTR_GV(rs_my4mitm1.value))); + + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm2), &rs_my4mitm2_r); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4mitm2_r.value), ZSTR_GV(rs_my4mitm2.value))); +} + +void cache_delete_few_mitm_test() { + zrtp_status_t status; + + printf("==> Delete few MiTM secrets and flush the cache.\n"); + + secerets_to_delete_count = 0; + zrtp_cache_create_id(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), secerets_to_delete[secerets_to_delete_count++]); + + zrtp_def_cache_foreach(&g_zrtp_cfg, 1, &cache_foreach_del_func, NULL); + + /* Flush the cache and open it again. */ + zrtp_def_cache_down(); + + printf("==> Open the cache and make sure all our prev. Modifications saved properly.\n"); + + status = zrtp_def_cache_init(&g_zrtp_cfg); + assert_int_equal(status, zrtp_status_ok); + + /* Let's check if all our modifications are in place. */ + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_a), &rs_my4a_r, 0); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4a_r.value), ZSTR_GV(rs_my4a.value))); + + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_b), &rs_my4b_r, 0); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4b_r.value), ZSTR_GV(rs_my4b.value))); + + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_c), &rs_my4c_r, 0); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4c_r.value), ZSTR_GV(rs_my4c.value))); + + /* Should be deleted */ + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), &rs_my4mitm1_r); + assert_int_not_equal(status, zrtp_status_ok); + + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm2), &rs_my4mitm2_r); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4mitm2_r.value), ZSTR_GV(rs_my4mitm2.value))); +} + +void cache_delete_few_rs_and_mitm_test() { + zrtp_status_t status; + + printf("==> Delete few RS secrets and flush the cache.\n"); + + secerets_to_delete_count = 0; + zrtp_cache_create_id(ZSTR_GV(zid_my), ZSTR_GV(zid_b), secerets_to_delete[secerets_to_delete_count++]); + zrtp_cache_create_id(ZSTR_GV(zid_my), ZSTR_GV(zid_a), secerets_to_delete[secerets_to_delete_count++]); + + zrtp_def_cache_foreach(&g_zrtp_cfg, 0, &cache_foreach_del_func, NULL); + + secerets_to_delete_count = 0; + zrtp_cache_create_id(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), secerets_to_delete[secerets_to_delete_count++]); + + zrtp_def_cache_foreach(&g_zrtp_cfg, 1, &cache_foreach_del_func, NULL); + + /* Flush the cache and open it again. */ + zrtp_def_cache_down(); + + printf("==> Open the cache and make sure all our prev. Modifications saved properly.\n"); + + status = zrtp_def_cache_init(&g_zrtp_cfg); + assert_int_equal(status, zrtp_status_ok); + + /* Let's check if all our modifications are in place. */ + + /* Should be deleted. */ + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_a), &rs_my4a_r, 0); + assert_int_not_equal(status, zrtp_status_ok); + + /* Should be deleted. */ + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_b), &rs_my4b_r, 0); + assert_int_not_equal(status, zrtp_status_ok); + + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_c), &rs_my4c_r, 0); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4c_r.value), ZSTR_GV(rs_my4c.value))); + + /* Should be deleted. */ + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), &rs_my4mitm1_r); + assert_int_not_equal(status, zrtp_status_ok); + + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm2), &rs_my4mitm2_r); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4mitm2_r.value), ZSTR_GV(rs_my4mitm2.value))); +} + +void cache_delete_all_rs_test() { + zrtp_status_t status; + + printf("==> Delete few RS secrets and flush the cache.\n"); + + secerets_to_delete_count = 0; + zrtp_cache_create_id(ZSTR_GV(zid_my), ZSTR_GV(zid_b), secerets_to_delete[secerets_to_delete_count++]); + zrtp_cache_create_id(ZSTR_GV(zid_my), ZSTR_GV(zid_a), secerets_to_delete[secerets_to_delete_count++]); + zrtp_cache_create_id(ZSTR_GV(zid_my), ZSTR_GV(zid_c), secerets_to_delete[secerets_to_delete_count++]); + + zrtp_def_cache_foreach(&g_zrtp_cfg, 0, &cache_foreach_del_func, NULL); + + /* Flush the cache and open it again. */ + zrtp_def_cache_down(); + + printf("==> Open the cache and make sure all our prev. Modifications saved properly.\n"); + + status = zrtp_def_cache_init(&g_zrtp_cfg); + assert_int_equal(status, zrtp_status_ok); + + /* Let's check if all our modifications are in place. */ + + /* All RS values should be deleted. */ + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_a), &rs_my4a_r, 0); + assert_int_not_equal(status, zrtp_status_ok); + + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_b), &rs_my4b_r, 0); + assert_int_not_equal(status, zrtp_status_ok); + + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_c), &rs_my4c_r, 0); + assert_int_not_equal(status, zrtp_status_ok); + + /* MiTM secrets should be in place. */ + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), &rs_my4mitm1_r); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4mitm1_r.value), ZSTR_GV(rs_my4mitm1.value))); + + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm2), &rs_my4mitm2_r); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4mitm2_r.value), ZSTR_GV(rs_my4mitm2.value))); +} + +void cache_delete_all_mitm_test() { + zrtp_status_t status; + + printf("==> Delete few MiTM secrets and flush the cache.\n"); + + secerets_to_delete_count = 0; + zrtp_cache_create_id(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), secerets_to_delete[secerets_to_delete_count++]); + zrtp_cache_create_id(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm2), secerets_to_delete[secerets_to_delete_count++]); + + zrtp_def_cache_foreach(&g_zrtp_cfg, 1, &cache_foreach_del_func, NULL); + + /* Flush the cache and open it again. */ + zrtp_def_cache_down(); + + printf("==> Open the cache and make sure all our prev. Modifications saved properly.\n"); + + status = zrtp_def_cache_init(&g_zrtp_cfg); + assert_int_equal(status, zrtp_status_ok); + + /* Let's check if all our modifications are in place. */ + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_a), &rs_my4a_r, 0); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4a_r.value), ZSTR_GV(rs_my4a.value))); + + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_b), &rs_my4b_r, 0); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4b_r.value), ZSTR_GV(rs_my4b.value))); + + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_c), &rs_my4c_r, 0); + assert_int_equal(status, zrtp_status_ok); + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4c_r.value), ZSTR_GV(rs_my4c.value))); + + /* All MiTM secrets should be deleted. */ + status = zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), &rs_my4mitm1_r); + assert_int_not_equal(status, zrtp_status_ok); + + assert_int_not_equal(zrtp_def_cache_get_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm2), &rs_my4mitm2_r), zrtp_status_ok); +} int main(void) { const UnitTest tests[] = { - //unit_test_setup_teardown(cache_init_store_empty_test, cache_setup, cache_teardown), + unit_test_setup_teardown(cache_init_store_empty_test, cache_setup, cache_teardown), unit_test_setup_teardown(cache_add2empty_test, cache_setup, cache_teardown), + unit_test_setup_teardown(cache_save_unchanged_test, cache_setup, cache_teardown), + unit_test_setup_teardown(cache_modify_and_save_test, cache_setup, cache_teardown), + + unit_test_setup_teardown(cache_delete_few_rs_test, cache_setup, cache_teardown), + unit_test_setup_teardown(cache_delete_few_mitm_test, cache_setup, cache_teardown), + unit_test_setup_teardown(cache_delete_few_rs_and_mitm_test, cache_setup, cache_teardown), + unit_test_setup_teardown(cache_delete_all_mitm_test, cache_setup, cache_teardown), }; return run_tests(tests); } + + +/****************************************************************************** + * Helpers + *****************************************************************************/ + +static void init_rs_secret_(zrtp_shared_secret_t *sec, unsigned char val_fill) { + + char val_buff[ZRTP_HASH_SIZE]; + zrtp_memset(val_buff, val_fill, sizeof(val_buff)); + + ZSTR_SET_EMPTY(sec->value); + zrtp_zstrcpyc(ZSTR_GV(sec->value), val_buff); + + sec->_cachedflag = 0; + sec->ttl = 0; + sec->lastused_at = 0; +} diff --git a/test/pc/zrtp_test_core.c b/test/pc/zrtp_test_core.c index f13c5a7f33..ae3a7ec7c1 100644 --- a/test/pc/zrtp_test_core.c +++ b/test/pc/zrtp_test_core.c @@ -424,13 +424,13 @@ static zrtp_status_t init_test_session( zrtp_test_session_t *session, unsigned nstreams) { unsigned i = 0; - zrtp_zid_t zid; + g_zrtp_cfg zid; zrtp_status_t s = zrtp_status_fail; session->streams_count = nstreams; /* Allocate ZRTP session */ - zrtp_randstr(zrtp_global, (unsigned char*)&zid, sizeof(zrtp_zid_t)); + zrtp_randstr(zrtp_global, (unsigned char*)&zid, sizeof(g_zrtp_cfg)); ZRTP_LOG(3, (_ZTU_,"INITIALIZE NEW SESSION ctx=%p:\n", session)); ZRTP_LOG(3, (_ZTU_,"---------------------------------------------------\n"));