static int verify_sas(struct re_printf *pf, void *arg) { const struct cmd_arg *carg = arg; (void)pf; if (str_isset(carg->prm)) { char rzid[ZRTP_STRING16] = ""; zrtp_status_t s; zrtp_string16_t remote_zid = ZSTR_INIT_EMPTY(remote_zid); if (str_len(carg->prm) != 24) { warning("zrtp: invalid remote ZID (%s)\n", carg->prm); return EINVAL; } (void) str2hex(carg->prm, (int) str_len(carg->prm), rzid, sizeof(rzid)); zrtp_zstrncpyc(ZSTR_GV(remote_zid), (const char*)rzid, sizeof(zrtp_zid_t)); s = zrtp_cache_set_verified(zrtp_global->cache, ZSTR_GV(remote_zid), true); if (s == zrtp_status_ok) info("zrtp: SAS for peer %s verified\n", carg->prm); else { warning("zrtp: zrtp_cache_set_verified" " failed (status = %d)\n", s); return EINVAL; } } return 0; }
/*---------------------------------------------------------------------------*/ zrtp_status_t _zrtp_machine_process_commit(zrtp_stream_t* stream, zrtp_rtp_info_t* packet) { zrtp_packet_Commit_t *commit = (zrtp_packet_Commit_t*) packet->message; switch (stream->mode) { case ZRTP_STREAM_MODE_DH: zrtp_zstrncpyc( ZSTR_GV(stream->protocol->cc->peer_hv), (const char*)commit->hv, ZRTP_HV_SIZE); break; case ZRTP_STREAM_MODE_PRESHARED: zrtp_zstrncpyc( ZSTR_GV(stream->protocol->cc->peer_hv), (const char*)commit->hv + ZRTP_HV_NONCE_SIZE, ZRTP_HV_NONCE_SIZE); case ZRTP_STREAM_MODE_MULT: zrtp_zstrncpyc( ZSTR_GV(stream->protocol->cc->peer_hv), (const char*)commit->hv, ZRTP_HV_NONCE_SIZE); break; default: break; } /* Copy Commit packet for further hashing */ zrtp_memcpy(&stream->messages.peer_commit, commit, zrtp_ntoh16(commit->hdr.length)*4); return zrtp_status_ok; }
/*----------------------------------------------------------------------------*/ static zrtp_status_t _zrtp_machine_process_dhpart2( zrtp_stream_t *stream, zrtp_rtp_info_t *packet) { zrtp_status_t s = zrtp_status_ok; zrtp_proto_crypto_t* cc = stream->protocol->cc; zrtp_packet_DHPart_t *dhpart2 = (zrtp_packet_DHPart_t*) packet->message; void *hash_ctx = NULL; /* * Verify hash commitment. (Compare hvi calculated from DH with peer hvi from COMMIT) * According to the last version of the internet draft 04a. Hvi should be * computed as: hvi=hash(initiator's DHPart2 message | responder's Hello message) */ hash_ctx = stream->session->hash->hash_begin(stream->session->hash); if (!hash_ctx) { return zrtp_status_fail; } stream->session->hash->hash_update( stream->session->hash, hash_ctx, (const int8_t*)dhpart2, zrtp_ntoh16(dhpart2->hdr.length)*4); stream->session->hash->hash_update( stream->session->hash, hash_ctx, (const int8_t*)&stream->messages.hello, zrtp_ntoh16(stream->messages.hello.hdr.length)*4); stream->session->hash->hash_end( stream->session->hash, hash_ctx, ZSTR_GV(cc->hv)); /* Truncate comuted hvi to 256 bit. The same length as transferred in Commit message.*/ cc->hv.length = ZRTP_HASH_SIZE; if (0 != zrtp_zstrcmp(ZSTR_GV(cc->hv), ZSTR_GV(cc->peer_hv))) { ZRTP_LOG(1,(_ZTU_,"\tERROR!" ZRTP_MIM2_WARNING_STR " ID=%u\n", stream->id)); _zrtp_machine_enter_initiatingerror(stream, zrtp_error_possible_mitm2, 1); return zrtp_status_fail; } /* Validate DH exchange (pvi is 1 or p-1). For DH streams only */ bnInsertBigBytes(&stream->dh_cc.peer_pv, dhpart2->pv, 0, stream->pubkeyscheme->pv_length); s = stream->pubkeyscheme->validate(stream->pubkeyscheme, &stream->dh_cc.peer_pv); if (zrtp_status_ok != s) { ZRTP_LOG(1,(_ZTU_,"\tERROR!" ZRTP_MITM1_WARNING_STR " ID=%u\n", stream->id)); _zrtp_machine_enter_initiatingerror(stream, zrtp_error_possible_mitm1, 1); return s; } /* Copy DH Part2 packet for future hashing */ zrtp_memcpy(&stream->messages.peer_dhpart, dhpart2, zrtp_ntoh16(dhpart2->hdr.length)*4); return s; }
void zrtp_config_defaults(zrtp_config_t* config) { zrtp_memset(config, 0, sizeof(zrtp_config_t)); zrtp_memcpy(config->client_id, "ZRTP def. peer", 15); config->lic_mode = ZRTP_LICENSE_MODE_PASSIVE; ZSTR_SET_EMPTY(config->def_cache_path); zrtp_zstrncpyc(ZSTR_GV(config->def_cache_path), "./zrtp_def_cache_path.dat", 25); config->cache_auto_store = 1; /* cache auto flushing should be enabled by default */ #if (defined(ZRTP_USE_BUILTIN_CACHE) && (ZRTP_USE_BUILTIN_CACHE == 1)) config->cb.cache_cb.on_init = zrtp_def_cache_init; config->cb.cache_cb.on_down = zrtp_def_cache_down; config->cb.cache_cb.on_put = zrtp_def_cache_put; config->cb.cache_cb.on_put_mitm = zrtp_def_cache_put_mitm; config->cb.cache_cb.on_get = zrtp_def_cache_get; config->cb.cache_cb.on_get_mitm = zrtp_def_cache_get_mitm; config->cb.cache_cb.on_set_verified = zrtp_def_cache_set_verified; config->cb.cache_cb.on_get_verified = zrtp_def_cache_get_verified; config->cb.cache_cb.on_reset_since = zrtp_def_cache_reset_since; config->cb.cache_cb.on_presh_counter_set = zrtp_def_cache_set_presh_counter; config->cb.cache_cb.on_presh_counter_get = zrtp_def_cache_get_presh_counter; #endif #if (defined(ZRTP_USE_BUILTIN_SCEHDULER) && (ZRTP_USE_BUILTIN_SCEHDULER == 1)) config->cb.sched_cb.on_init = zrtp_def_scheduler_init; config->cb.sched_cb.on_down = zrtp_def_scheduler_down; config->cb.sched_cb.on_call_later = zrtp_def_scheduler_call_later; config->cb.sched_cb.on_cancel_call_later = zrtp_def_scheduler_cancel_call_later; config->cb.sched_cb.on_wait_call_later = zrtp_def_scheduler_wait_call_later; #endif }
/*---------------------------------------------------------------------------*/ zrtp_status_t zrtp_signaling_hash_get( zrtp_stream_t* stream, char *hash_buff, uint32_t hash_buff_length) { zrtp_string32_t hash_str = ZSTR_INIT_EMPTY(hash_str); zrtp_hash_t *hash = NULL; if (!stream || !hash_buff) { return zrtp_status_bad_param; } if (ZRTP_SIGN_ZRTP_HASH_LENGTH > hash_buff_length) { return zrtp_status_buffer_size; } if (stream->state < ZRTP_STATE_ACTIVE) { return zrtp_status_wrong_state; } hash = zrtp_comp_find(ZRTP_CC_HASH, ZRTP_HASH_SHA256, stream->zrtp); hash->hash_c( hash, (const char*)&stream->messages.hello.hdr, zrtp_ntoh16(stream->messages.hello.hdr.length) * 4, ZSTR_GV(hash_str) ); hex2str(hash_str.buffer, ZRTP_MESSAGE_HASH_SIZE, hash_buff, hash_buff_length); return zrtp_status_ok; }
zrtp_status_t zrtp_cache_put_name2(zrtp_session_t *session, const zrtp_stringn_t* name) { if (session && session->zrtp && session->zrtp->cache) { return zrtp_cache_put_name(session->zrtp->cache, ZSTR_GV(session->peer_zid), name); } else { return zrtp_status_bad_param; } }
/*----------------------------------------------------------------------------*/ static zrtp_status_t _attach_secret( zrtp_session_t *session, zrtp_proto_secret_t* psec, zrtp_shared_secret_t* sec, uint8_t is_initiator) { zrtp_uchar32_t buff; static const zrtp_string16_t initiator = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_ROLE_INITIATOR); static const zrtp_string16_t responder = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_ROLE_RESPONDER); const zrtp_string16_t* role = is_initiator ? &initiator : &responder; const zrtp_string16_t* his_role = is_initiator ? &responder : &initiator; ZSTR_SET_EMPTY(psec->id); ZSTR_SET_EMPTY(psec->peer_id); psec->secret = sec; /* * If secret's value is available (from the cache or from SIP) - use hmac; * use zero-strings in other case. */ if (psec->secret) { session->hash->hmac_truncated( session->hash, ZSTR_GV(sec->value), ZSTR_GVP(role), ZRTP_RSID_SIZE, ZSTR_GV(psec->id)); session->hash->hmac_truncated( session->hash, ZSTR_GV(sec->value), ZSTR_GVP(his_role), ZRTP_RSID_SIZE, ZSTR_GV(psec->peer_id)); } else { psec->id.length = ZRTP_RSID_SIZE; zrtp_memset(psec->id.buffer, 0, psec->id.length); psec->peer_id.length = ZRTP_RSID_SIZE; zrtp_memset(psec->peer_id.buffer, 0, psec->peer_id.length); } ZRTP_LOG(3,(_ZTU_,"\tAttach RS id=%s.\n", hex2str((const char*)psec->id.buffer, psec->id.length, (char*)buff, sizeof(buff)))); ZRTP_LOG(3,(_ZTU_,"\tAttach RS peer_id=%s.\n", hex2str((const char*)psec->peer_id.buffer, psec->peer_id.length, (char*)buff, sizeof(buff)))); return zrtp_status_ok; }
zrtp_status_t zrtp_test_endpoint_create(zrtp_test_endpoint_cfg_t* cfg, const char *name, zrtp_test_id_t* id) { zrtp_status_t s; unsigned i; char cache_file_path[ZRTP_TEST_STR_LEN]; zrtp_endpoint_t *new_endpoint; if (g_test_endpoints_count >= K_ZRTP_TEST_MAX_ENDPOINTS) return zrtp_status_alloc_fail; new_endpoint = &g_test_endpoints[g_test_endpoints_count++]; zrtp_memset(new_endpoint, 0, sizeof(zrtp_endpoint_t)); /* Copy configuration, we will use it later to clean up after ourselves */ zrtp_memcpy(&new_endpoint->cfg, cfg, sizeof(zrtp_test_endpoint_cfg_t)); /* Remember endpoint name */ strcpy(new_endpoint->name, name); new_endpoint->id = g_endpoints_counter++; /* Adjust cache file path so each endpoint will use it's own file. */ sprintf(cache_file_path, "./%s_cache.dat", name); zrtp_zstrcpyc(ZSTR_GV(new_endpoint->cfg.zrtp.def_cache_path), cache_file_path); /* Initialize libzrtp engine for this endpoint */ s = zrtp_init(&new_endpoint->cfg.zrtp, &new_endpoint->zrtp); if (zrtp_status_ok == s) { *id = new_endpoint->id; /* Generate random ZID */ zrtp_randstr(new_endpoint->zrtp, new_endpoint->zid, sizeof(new_endpoint->zid)); } /* Create Input queue*/ s = zrtp_test_queue_create(&new_endpoint->input_queue); if (zrtp_status_ok != s) { return s; } /* Start processing loop */ new_endpoint->is_running = 1; for (i = 0; i<K_ZRTP_TEST_PROCESSORS_COUNT; i++) { if (0 != zrtp_thread_create(process_incoming, new_endpoint)) { return zrtp_status_fail; } if (cfg->generate_traffic) { if (0 != zrtp_thread_create(process_outgoing, new_endpoint)) { return zrtp_status_fail; } } } return s; }
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; }
/*----------------------------------------------------------------------------*/ void zrtp_session_down(zrtp_session_t *session) { int i =0; if (!session) { return; } /* Stop ZRTP engine and clear all crypto sources for every stream in the session. */ zrtp_mutex_lock(session->streams_protector); for(i=0; i<ZRTP_MAX_STREAMS_PER_SESSION; i++) { zrtp_stream_t *the_stream = &session->streams[i]; zrtp_stream_stop(the_stream); } zrtp_mutex_unlock(session->streams_protector); /* Release memory allocated on initialization */ if (session->secrets.rs1) { zrtp_sys_free(session->secrets.rs1); } if (session->secrets.rs2) { zrtp_sys_free(session->secrets.rs2); } if (session->secrets.auxs) { zrtp_sys_free(session->secrets.auxs); } if (session->secrets.pbxs) { zrtp_sys_free(session->secrets.pbxs); } /* We don't need the session key anymore - clear it */ zrtp_wipe_zstring(ZSTR_GV(session->zrtpsess)); /* Removing session from the global list */ zrtp_mutex_lock(session->zrtp->sessions_protector); mlist_del(&session->_mlist); zrtp_mutex_unlock(session->zrtp->sessions_protector); zrtp_mutex_destroy(session->streams_protector); zrtp_mutex_destroy(session->init_protector); zrtp_sys_free(session); }
zrtp_status_t zrtp_session_get(zrtp_session_t *session, zrtp_session_info_t *info) { int i=0; if (!session || !info) { return zrtp_status_bad_param; } zrtp_memset(info, 0, sizeof(zrtp_session_info_t)); ZSTR_SET_EMPTY(info->peer_clientid); ZSTR_SET_EMPTY(info->peer_version); ZSTR_SET_EMPTY(info->zid); ZSTR_SET_EMPTY(info->peer_zid); ZSTR_SET_EMPTY(info->sas1); ZSTR_SET_EMPTY(info->sasbin); ZSTR_SET_EMPTY(info->sas2); ZSTR_SET_EMPTY(info->auth_name); ZSTR_SET_EMPTY(info->cipher_name); ZSTR_SET_EMPTY(info->hash_name); ZSTR_SET_EMPTY(info->sas_name); ZSTR_SET_EMPTY(info->pk_name); info->id = session->id; zrtp_zstrcpy(ZSTR_GV(info->zid), ZSTR_GV(session->zid)); zrtp_zstrcpy(ZSTR_GV(info->peer_zid), ZSTR_GV(session->peer_zid)); for (i=0; i<ZRTP_MAX_STREAMS_PER_SESSION; i++) { zrtp_stream_t* full_stream = &session->streams[i]; if ((full_stream->state > ZRTP_STATE_ACTIVE) && !ZRTP_IS_STREAM_FAST(full_stream)) { zrtp_zstrcpyc(ZSTR_GV(info->pk_name), zrtp_pkt2str[full_stream->pubkeyscheme->base.id-1]); zrtp_zstrncpyc( ZSTR_GV(info->peer_clientid), (const char*)full_stream->messages.peer_hello.cliend_id, 16); zrtp_zstrncpyc( ZSTR_GV(info->peer_version), (const char*)full_stream->messages.peer_hello.version, 4); info->secrets_ttl = full_stream->cache_ttl; } } info->sas_is_ready = (session->zrtpsess.length > 0) ? 1 : 0; if (info->sas_is_ready) { zrtp_zstrcpy(ZSTR_GV(info->sas1), ZSTR_GV(session->sas1)); zrtp_zstrcpy(ZSTR_GV(info->sas2), ZSTR_GV(session->sas2)); zrtp_zstrcpy(ZSTR_GV(info->sasbin), ZSTR_GV(session->sasbin)); info->sas_is_base256 = (ZRTP_SAS_BASE256 == session->sasscheme->base.id); info->sas_is_verified = 0; if (session->zrtp->cb.cache_cb.on_get_verified) { session->zrtp->cb.cache_cb.on_get_verified( ZSTR_GV(session->zid), ZSTR_GV(session->peer_zid), &info->sas_is_verified); } zrtp_zstrcpyc(ZSTR_GV(info->hash_name), zrtp_hash2str[session->hash->base.id-1]); zrtp_zstrcpyc(ZSTR_GV(info->cipher_name), zrtp_cipher2str[session->blockcipher->base.id-1]); zrtp_zstrcpyc(ZSTR_GV(info->auth_name), zrtp_atl2str[session->authtaglength->base.id-1]); zrtp_zstrcpyc(ZSTR_GV(info->sas_name), zrtp_sas2str[session->sasscheme->base.id-1]); info->cached_flags = session->secrets.cached_curr; info->matches_flags= session->secrets.matches_curr; info->wrongs_flags = session->secrets.wrongs_curr; } return zrtp_status_ok; }
zrtp_status_t zrtp_init(zrtp_config_t* config, zrtp_global_t** zrtp) { zrtp_global_t* new_zrtp; zrtp_status_t s = zrtp_status_ok; ZRTP_LOG(3, (_ZTU_,"INITIALIZING LIBZRTP...\n")); /* Print out configuration setting */ zrtp_print_env_settings(config); new_zrtp = zrtp_sys_alloc(sizeof(zrtp_global_t)); if (!new_zrtp) { return zrtp_status_alloc_fail; } zrtp_memset(new_zrtp, 0, sizeof(zrtp_global_t)); /* * Apply configuration according to the config */ new_zrtp->lic_mode = config->lic_mode; new_zrtp->is_mitm = config->is_mitm; ZSTR_SET_EMPTY(new_zrtp->def_cache_path); zrtp_zstrcpy(ZSTR_GV(new_zrtp->def_cache_path), ZSTR_GV(config->def_cache_path)); zrtp_memcpy(&new_zrtp->cb, &config->cb, sizeof(zrtp_callback_t)); new_zrtp->cache_auto_store = config->cache_auto_store; ZSTR_SET_EMPTY(new_zrtp->client_id); zrtp_memset(new_zrtp->client_id.buffer, ' ', sizeof(zrtp_client_id_t)); zrtp_zstrncpyc( ZSTR_GV(new_zrtp->client_id), (const char*)config->client_id, sizeof(zrtp_client_id_t)); /* * General Initialization */ init_mlist(&new_zrtp->sessions_head); zrtp_mutex_init(&new_zrtp->sessions_protector); init_mlist(&new_zrtp->hash_head); init_mlist(&new_zrtp->cipher_head); init_mlist(&new_zrtp->atl_head); init_mlist(&new_zrtp->pktype_head); init_mlist(&new_zrtp->sas_head); /* Init RNG context */ s = zrtp_init_rng(new_zrtp); if (zrtp_status_ok != s) { ZRTP_LOG(1, (_ZTU_,"ERROR! zrtp_init_rng() failed:%s.\n", zrtp_log_status2str(s))); return zrtp_status_rng_fail; } /* Initialize SRTP engine */ s = zrtp_srtp_init(new_zrtp); if (zrtp_status_ok != s) { ZRTP_LOG(1, (_ZTU_,"ERROR! zrtp_srtp_init() failed:<%s>\n", zrtp_log_status2str(s))); return zrtp_status_fail; } if (new_zrtp->cb.cache_cb.on_init) { s = new_zrtp->cb.cache_cb.on_init(new_zrtp); if (zrtp_status_ok != s) { ZRTP_LOG(1, (_ZTU_,"ERROR! cache on_init() callback failed <%s>\n", zrtp_log_status2str(s))); zrtp_srtp_down(new_zrtp); return zrtp_status_fail; } } if (new_zrtp->cb.sched_cb.on_init) { s = new_zrtp->cb.sched_cb.on_init(new_zrtp); if (zrtp_status_ok != s) { ZRTP_LOG(1, (_ZTU_,"ERROR! scheduler on_init() callback failed <%s>\n", zrtp_log_status2str(s))); zrtp_srtp_down(new_zrtp); return zrtp_status_fail; } } /* Load default crypto-components */ zrtp_prepare_pkt(new_zrtp); zrtp_defaults_sas(new_zrtp); zrtp_defaults_pkt(new_zrtp); zrtp_defaults_atl(new_zrtp); zrtp_defaults_aes_cipher(new_zrtp); zrtp_defaults_hash(new_zrtp); *zrtp = new_zrtp; ZRTP_LOG(3, (_ZTU_,"INITIALIZING LIBZRTP - DONE\n")); return s; }
/* * 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("==> 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))); 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))); }
/*----------------------------------------------------------------------------*/ zrtp_status_t zrtp_stream_attach(zrtp_session_t *session, zrtp_stream_t** stream) { uint32_t i = 0; zrtp_status_t s = zrtp_status_fail; zrtp_stream_t* new_stream = NULL; ZRTP_LOG(3, (_ZTU_,"ATTACH NEW STREAM to sID=%d:\n", session->id)); /* * Initialize first unused stream. If there are no available streams return error. */ zrtp_mutex_lock(session->streams_protector); for (i=0; i<ZRTP_MAX_STREAMS_PER_SESSION; i++) { if (ZRTP_STATE_NONE == session->streams[i].state) { new_stream = &session->streams[i]; zrtp_memset(new_stream, 0, sizeof(zrtp_stream_t)); break; } } zrtp_mutex_unlock(session->streams_protector); if (!new_stream) { ZRTP_LOG(1, (_ZTU_,"\tWARNING! Can't attach one more stream. Limit is reached." " Use #ZRTP_MAX_STREAMS_PER_SESSION. sID=%u\n", session->id)); return zrtp_status_alloc_fail; } /* * Initialize the private data stream with default initial values */ zrtp_mutex_init(&new_stream->stream_protector); _zrtp_change_state(new_stream, ZRTP_STATE_ACTIVE); new_stream->mode = ZRTP_STREAM_MODE_CLEAR; new_stream->id = session->zrtp->streams_count++; new_stream->session = session; new_stream->zrtp = session->zrtp; new_stream->mitm_mode = ZRTP_MITM_MODE_UNKN; new_stream->is_hello_received = 0; ZSTR_SET_EMPTY(new_stream->cc.hmackey); ZSTR_SET_EMPTY(new_stream->cc.peer_hmackey); ZSTR_SET_EMPTY(new_stream->cc.zrtp_key); ZSTR_SET_EMPTY(new_stream->cc.peer_zrtp_key); new_stream->dh_cc.initialized_with = ZRTP_COMP_UNKN; bnBegin(&new_stream->dh_cc.peer_pv); ZSTR_SET_EMPTY(new_stream->dh_cc.dhss); ZRTP_LOG(3, (_ZTU_,"\tEmpty slot was found - initializing new stream with ID=%u.\n", new_stream->id)); do { zrtp_string32_t hash_buff = ZSTR_INIT_EMPTY(hash_buff); zrtp_hash_t *hash = zrtp_comp_find(ZRTP_CC_HASH, ZRTP_HASH_SHA256, new_stream->zrtp); s = zrtp_status_algo_fail; if (sizeof(uint16_t) != zrtp_randstr( new_stream->zrtp, (uint8_t*)&new_stream->media_ctx.high_out_zrtp_seq, sizeof(uint16_t))) { break; } /* * Compute and store message hashes to prevent DoS attacks. * Generate H0 as a random nonce and compute H1, H2 and H3 * using the leftmost 128 bits from every hash. * Then insert these directly into the message structures. */ zrtp_memset(&new_stream->messages, 0, sizeof(new_stream->messages)); ZSTR_SET_EMPTY(new_stream->messages.h0); ZSTR_SET_EMPTY(new_stream->messages.signaling_hash); /* Generate Random nonce, compute H1 and store in the DH packet */ new_stream->messages.h0.length = (uint16_t)zrtp_randstr( new_stream->zrtp, (unsigned char*)new_stream->messages.h0.buffer, ZRTP_MESSAGE_HASH_SIZE); if (ZRTP_MESSAGE_HASH_SIZE != new_stream->messages.h0.length) { break; } s = hash->hash(hash, ZSTR_GV(new_stream->messages.h0), ZSTR_GV(hash_buff)); if (zrtp_status_ok != s) { break; } zrtp_memcpy(new_stream->messages.dhpart.hash, hash_buff.buffer, ZRTP_MESSAGE_HASH_SIZE); /* Compute H2 for the Commit */ s = hash->hash_c(hash, (char*)new_stream->messages.dhpart.hash, ZRTP_MESSAGE_HASH_SIZE, ZSTR_GV(hash_buff)); if (zrtp_status_ok != s) { break; } zrtp_memcpy(new_stream->messages.commit.hash, hash_buff.buffer, ZRTP_MESSAGE_HASH_SIZE); /* Compute H3 for the Hello message */ s = hash->hash_c(hash, (char*)new_stream->messages.commit.hash, ZRTP_MESSAGE_HASH_SIZE, ZSTR_GV(hash_buff)); if (zrtp_status_ok != s) { break; } zrtp_memcpy(new_stream->messages.hello.hash, hash_buff.buffer, ZRTP_MESSAGE_HASH_SIZE); s = zrtp_status_ok; } while (0); if (zrtp_status_ok != s) { ZRTP_LOG(1, (_ZTU_,"\tERROR! Fail to compute messages hashes <%s>.\n", zrtp_log_status2str(s))); return s; } /* * Preparing HELLO based on user's profile */ ZRTP_LOG(3, (_ZTU_,"\tPreparing ZRTP Hello according to the Session profile.\n")); { zrtp_packet_Hello_t* hello = &new_stream->messages.hello; uint8_t i = 0; int8_t* comp_ptr = NULL; /* Set Protocol Version and ClientID */ zrtp_memcpy(hello->version, ZRTP_PROTOCOL_VERSION, ZRTP_VERSION_SIZE); zrtp_memcpy(hello->cliend_id, session->zrtp->client_id.buffer, session->zrtp->client_id.length); /* Set flags. */ hello->pasive = (ZRTP_LICENSE_MODE_PASSIVE == session->zrtp->lic_mode) ? 1 : 0; hello->uflag = (ZRTP_LICENSE_MODE_UNLIMITED == session->zrtp->lic_mode) ? 1 : 0; hello->mitmflag = session->zrtp->is_mitm; hello->sigflag = 0; zrtp_memcpy(hello->zid, session->zid.buffer, session->zid.length); comp_ptr = (int8_t*)hello->comp; i = 0; while ( session->profile.hash_schemes[i]) { zrtp_memcpy( comp_ptr, zrtp_comp_id2type(ZRTP_CC_HASH, session->profile.hash_schemes[i++]), ZRTP_COMP_TYPE_SIZE ); comp_ptr += ZRTP_COMP_TYPE_SIZE; } hello->hc = i; i = 0; while (session->profile.cipher_types[i]) { zrtp_memcpy( comp_ptr, zrtp_comp_id2type(ZRTP_CC_CIPHER, session->profile.cipher_types[i++]), ZRTP_COMP_TYPE_SIZE ); comp_ptr += ZRTP_COMP_TYPE_SIZE; } hello->cc = i; i = 0; while (session->profile.auth_tag_lens[i] ) { zrtp_memcpy( comp_ptr, zrtp_comp_id2type(ZRTP_CC_ATL, session->profile.auth_tag_lens[i++]), ZRTP_COMP_TYPE_SIZE ); comp_ptr += ZRTP_COMP_TYPE_SIZE; } hello->ac = i; i = 0; while (session->profile.pk_schemes[i] ) { zrtp_memcpy( comp_ptr, zrtp_comp_id2type(ZRTP_CC_PKT, session->profile.pk_schemes[i++]), ZRTP_COMP_TYPE_SIZE ); comp_ptr += ZRTP_COMP_TYPE_SIZE; } hello->kc = i; i = 0; while (session->profile.sas_schemes[i]) { zrtp_memcpy( comp_ptr, zrtp_comp_id2type(ZRTP_CC_SAS, session->profile.sas_schemes[i++]), ZRTP_COMP_TYPE_SIZE ); comp_ptr += ZRTP_COMP_TYPE_SIZE; } hello->sc = i; /* * Hmac will appear at the end of the message, after the dynamic portion. * i is the length of the dynamic part. */ i = (hello->hc + hello->cc + hello->ac + hello->kc + hello->sc) * ZRTP_COMP_TYPE_SIZE; _zrtp_packet_fill_msg_hdr( new_stream, ZRTP_HELLO, ZRTP_HELLO_STATIC_SIZE + i + ZRTP_HMAC_SIZE, &hello->hdr); } *stream = new_stream; ZRTP_LOG(3, (_ZTU_,"ATTACH NEW STREAM - DONE.\n")); return zrtp_status_ok; }
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); }
/*----------------------------------------------------------------------------*/ static zrtp_status_t _create_sasrelay( zrtp_stream_t *stream, zrtp_sas_id_t transf_sas_scheme, zrtp_string32_t* transf_sas_value, uint8_t transf_ac_flag, uint8_t transf_d_flag, zrtp_packet_SASRelay_t* sasrelay ) { zrtp_session_t *session = stream->session; zrtp_status_t s = zrtp_status_fail; void* cipher_ctx = NULL; /* (padding + sig_len + flags) + SAS scheme and SASHash */ const uint8_t encrypted_body_size = (2 + 1 + 1) + 4 + 32; zrtp_memset(sasrelay, 0, sizeof(zrtp_packet_SASRelay_t)); /* generate a random initialization vector for CFB cipher */ if (ZRTP_CFBIV_SIZE != zrtp_randstr(session->zrtp, sasrelay->iv, ZRTP_CFBIV_SIZE)) { return zrtp_status_rp_fail; } sasrelay->flags |= (session->profile.disclose_bit || transf_d_flag) ? 0x01 : 0x00; sasrelay->flags |= (session->profile.allowclear && transf_ac_flag) ? 0x02 : 0x00; sasrelay->flags |= 0x04; zrtp_memcpy( sasrelay->sas_scheme, zrtp_comp_id2type(ZRTP_CC_SAS, transf_sas_scheme), ZRTP_COMP_TYPE_SIZE ); if (transf_sas_value) zrtp_memcpy(sasrelay->sashash, transf_sas_value->buffer, transf_sas_value->length); /* Then we need to encrypt Confirm before computing Hmac. Use AES CFB */ do { cipher_ctx = session->blockcipher->start( session->blockcipher, (uint8_t*)stream->cc.zrtp_key.buffer, NULL, ZRTP_CIPHER_MODE_CFB ); if (!cipher_ctx) { break; } s = session->blockcipher->set_iv( session->blockcipher, cipher_ctx, (zrtp_v128_t*)sasrelay->iv); if (zrtp_status_ok != s) { break; } s = session->blockcipher->encrypt( session->blockcipher, cipher_ctx, (uint8_t*)&sasrelay->pad, encrypted_body_size ); } while(0); if (cipher_ctx) { session->blockcipher->stop(session->blockcipher, cipher_ctx); } if (zrtp_status_ok != s) { ZRTP_LOG(1,(_ZTU_,"\tERROR! Failed to encrypt SASRELAY Message status=%d. ID=%u\n", s, stream->id)); return s; } /* Compute Hmac over encrypted part of Confirm */ { zrtp_string128_t hmac = ZSTR_INIT_EMPTY(hmac); s = session->hash->hmac_c( session->hash, stream->cc.hmackey.buffer, stream->cc.hmackey.length, (const char*)&sasrelay->pad, encrypted_body_size, ZSTR_GV(hmac) ); if (zrtp_status_ok != s) { ZRTP_LOG(1,(_ZTU_,"\tERROR! Failed to compute CONFIRM hmac status=%d. ID=%u\n", s, stream->id)); return s; } zrtp_memcpy(sasrelay->hmac, hmac.buffer, ZRTP_HMAC_SIZE); } return s; }
/*---------------------------------------------------------------------------*/ zrtp_status_t _zrtp_machine_enter_secure(zrtp_stream_t* stream) { /* * When switching to SECURE all ZRTP crypto values were already computed by * state-machine. Then we need to have logic to manage SAS value and shared * secrets only. So: we compute SAS, refresh secrets flags and save the * secrets to the cache after RS2 and RS1 swapping. We don't need any * crypto sources any longer - destroy them. */ zrtp_status_t s = zrtp_status_ok; zrtp_proto_crypto_t* cc = stream->protocol->cc; zrtp_session_t *session = stream->session; zrtp_secrets_t *secrets = &stream->session->secrets; uint8_t was_exp = 0; uint64_t exp_date = 0; ZRTP_LOG(3,(_ZTU_,"\tEnter state SECURE (%s).\n", zrtp_log_mode2str(stream->mode))); _zrtp_cancel_send_packet_later(stream, ZRTP_NONE); /* * Compute the SAS value if it isn't computed yet. If there are several * streams running in parallel - stream with the biggest hvi should * generate the SAS. */ if (!session->sas1.length) { s = session->sasscheme->compute(session->sasscheme, stream, session->hash, 0); if (zrtp_status_ok != s) { _zrtp_machine_enter_initiatingerror(stream, zrtp_error_software, 1); return s; } ZRTP_LOG(3,(_ZTU_,"\tThis is the very first stream in sID GENERATING SAS value.\n", session->id)); ZRTP_LOG(3,(_ZTU_,"\tSAS computed: <%.16s> <%.16s>.\n", session->sas1.buffer, session->sas2.buffer)); } /* * Compute a new value for RS1 and store the prevoious one. * Compute result secrets' flags. */ if (ZRTP_IS_STREAM_DH(stream)) { ZRTP_LOG(3,(_ZTU_,"\tCheck expiration interval: last_use=%u ttl=%u new_ttl=%u exp=%u now=%u\n", secrets->rs1->lastused_at, secrets->rs1->ttl, stream->cache_ttl, (secrets->rs1->lastused_at + secrets->rs1->ttl), zrtp_time_now()/1000)); if (secrets->rs1->ttl != 0xFFFFFFFF) { exp_date = secrets->rs1->lastused_at; exp_date += secrets->rs1->ttl; if (ZRTP_IS_STREAM_DH(stream) && (exp_date < zrtp_time_now()/1000)) { ZRTP_LOG(3,(_ZTU_,"\tUsing EXPIRED secrets: last_use=%u ttl=%u exp=%u now=%u\n", secrets->rs1->lastused_at, secrets->rs1->ttl, (secrets->rs1->lastused_at + secrets->rs1->ttl), zrtp_time_now()/1000)); was_exp = 1; } } if (!was_exp) { secrets->wrongs = secrets->matches ^ secrets->cached; secrets->wrongs &= ~ZRTP_BIT_RS2; secrets->wrongs &= ~ZRTP_BIT_PBX; } } /* * We going to update RS1 and change appropriate secrets flags. Let's back-up current values. * Back-upped values could be used in debug purposes and in the GUI to reflect current state of the call */ if (!ZRTP_IS_STREAM_MULT(stream)) { secrets->cached_curr = secrets->cached; secrets->matches_curr = secrets->matches; secrets->wrongs_curr = secrets->wrongs; } ZRTP_LOG(3,(_ZTU_,"\tFlags C=%x M=%x W=%x ID=%u\n", secrets->cached, secrets->matches, secrets->wrongs, stream->id)); _zrtp_change_state(stream, ZRTP_STATE_SECURE); /* * Alarm user if the following condition is TRUE for both RS1 and RS2: * "secret is wrong if it has been restored from the cache but hasn't matched * with the remote one". */ if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { session->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_SECURE); } if (session->zrtp->cb.event_cb.on_zrtp_secure) { session->zrtp->cb.event_cb.on_zrtp_secure(stream); } /* Alarm user if possible MiTM attack detected */ if (secrets->wrongs) { session->mitm_alert_detected = 1; if (session->zrtp->cb.event_cb.on_zrtp_security_event) { session->zrtp->cb.event_cb.on_zrtp_security_event(stream, ZRTP_EVENT_MITM_WARNING); } } /* Check for unenrollemnt first */ if ((secrets->cached & ZRTP_BIT_PBX) && !(secrets->matches & ZRTP_BIT_PBX)) { ZRTP_LOG(2,(_ZTU_,"\tINFO! The user requires new un-enrolment - the nedpint may clear" " the cache or perform other action. ID=%u\n", stream->id)); if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { session->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_USER_UNENROLLED); } } /* * Handle PBX registration, if required: If PBX already had a shared secret * for the ZID it leaves the cache entry unmodified. Else, it computes a new * one. If the PBX detects cache entry for the static shared secret, but the * phone does not have a matching cache entry - the PBX generates a new one. */ if (ZRTP_MITM_MODE_REG_SERVER == stream->mitm_mode) { if (secrets->matches & ZRTP_BIT_PBX) { ZRTP_LOG(2,(_ZTU_,"\tINFO! User have been already registered - skip enrollment ritual. ID=%u\n", stream->id)); if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { session->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_USER_ALREADY_ENROLLED); } } else { ZRTP_LOG(2,(_ZTU_,"\tINFO! The user requires new enrolment - generate new MiTM secret. ID=%u\n", stream->id)); zrtp_register_with_trusted_mitm(stream); if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { stream->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_NEW_USER_ENROLLED); } } } else if (ZRTP_MITM_MODE_REG_CLIENT == stream->mitm_mode) { if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { session->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_CLIENT_ENROLLMENT); } } /* * Compute new RS for FULL DH streams only. Don't update RS1 if cache TTL is 0 */ if (ZRTP_IS_STREAM_DH(stream)) { static const zrtp_string32_t rss_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_RS_STR); if (stream->cache_ttl > 0) { /* Replace RS2 with RS1 */ zrtp_sys_free(secrets->rs2); secrets->rs2 = secrets->rs1; secrets->rs1 = _zrtp_alloc_shared_secret(session); if (!secrets->rs1) { _zrtp_machine_enter_initiatingerror(stream, zrtp_error_software, 1); return zrtp_status_fail; } /* * Compute new RS1 based on previous one and S0: * rs1 = KDF(s0, "retained secret", KDF_Context, negotiated hash length) */ _zrtp_kdf( stream, ZSTR_GV(cc->s0), ZSTR_GV(rss_label), ZSTR_GV(cc->kdf_context), ZRTP_HASH_SIZE, ZSTR_GV(secrets->rs1->value)); /* * Mark secrets as cached: RS1 have been just generated and cached; * RS2 is cached if previous secret was cached as well. */ secrets->rs1->_cachedflag = 1; secrets->cached |= ZRTP_BIT_RS1; secrets->matches |= ZRTP_BIT_RS1; if (secrets->rs2->_cachedflag) { secrets->cached |= ZRTP_BIT_RS2; } /* Let's update the TTL interval for the new secret */ secrets->rs1->ttl = stream->cache_ttl; secrets->rs1->lastused_at = (uint32_t)(zrtp_time_now()/1000); /* If possible MiTM attach detected - postpone storing the cache until after the user verify the SAS */ if (!session->mitm_alert_detected) { zrtp_cache_put(session->zrtp->cache, ZSTR_GV(session->peer_zid), secrets->rs1); } { uint32_t verifiedflag = 0; char buff[128]; zrtp_cache_get_verified(session->zrtp->cache, ZSTR_GV(session->peer_zid), &verifiedflag); ZRTP_LOG(3,(_ZTU_,"\tNew secret was generated:\n")); ZRTP_LOG(3,(_ZTU_,"\t\tRS1 value:<%s>\n", hex2str(secrets->rs1->value.buffer, secrets->rs1->value.length, buff, sizeof(buff)))); ZRTP_LOG(3,(_ZTU_,"\t\tTTL=%u, flags C=%x M=%x W=%x V=%d\n", secrets->rs1->ttl, secrets->cached, secrets->matches, secrets->wrongs, verifiedflag)); } } /* for TTL > 0 only */ else { secrets->rs1->ttl = 0; zrtp_cache_put(session->zrtp->cache, ZSTR_GV(session->peer_zid), secrets->rs1); } } /* For DH mode only */ if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { session->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_IS_SECURE_DONE); } /* We have computed all subkeys from S0 and don't need it any longer. */ zrtp_wipe_zstring(ZSTR_GV(cc->s0)); /* Clear DH crypto context */ if (ZRTP_IS_STREAM_DH(stream)) { bnEnd(&stream->dh_cc.peer_pv); bnEnd(&stream->dh_cc.pv); bnEnd(&stream->dh_cc.sv); zrtp_wipe_zstring(ZSTR_GV(stream->dh_cc.dhss)); } /* * Now, let's check if the transition to CLEAR was caused by Active/Passive rules. * If local endpoint is a MitM and peer MiTM linked stream is Unlimited, we * could break the rules and send commit to Passive endpoint. */ if (stream->zrtp->is_mitm && stream->peer_super_flag) { if (stream->linked_mitm && stream->linked_mitm->peer_passive) { if (stream->linked_mitm->state == ZRTP_STATE_CLEAR) { ZRTP_LOG(2,(_ZTU_,"INFO: Linked Peer stream id=%u suspended in CLEAR-state due to" " Active/Passive restrictions, but we are running in MiTM mode and " "current peer endpoint is Super-Active. Let's Go Secure for the linked stream.\n", stream->id)); /* @note: don't use zrtp_secure_stream() wrapper as it checks for Active/Passive stuff. */ _zrtp_machine_start_initiating_secure(stream->linked_mitm); } } } /* * Increase calls counter for Preshared mode and reset it on DH */ uint32_t calls_counter = 0; zrtp_cache_get_presh_counter(session->zrtp->cache, ZSTR_GV(session->peer_zid), &calls_counter); if (ZRTP_IS_STREAM_DH(stream)) { zrtp_cache_set_presh_counter(session->zrtp->cache, ZSTR_GV(session->peer_zid), 0); } else if ZRTP_IS_STREAM_PRESH(stream) { zrtp_cache_set_presh_counter(session->zrtp->cache, ZSTR_GV(session->peer_zid), ++calls_counter); } clear_crypto_sources(stream); return zrtp_status_ok; }
/*----------------------------------------------------------------------------*/ zrtp_status_t _zrtp_set_public_value( zrtp_stream_t *stream, int is_initiator) { /* * This function performs the following actions according to ZRTP draft 5.6 * a) Computes total hash; * b) Calculates DHResult; * c) Computes final stream key S0, based on DHSS and retained secrets; * d) Computes HMAC Key and ZRTP key; * e) Computes srtp keys and salts and creates srtp session. */ zrtp_session_t *session = stream->session; zrtp_proto_crypto_t* cc = stream->protocol->cc; void* hash_ctx = NULL; static const zrtp_string32_t hmac_keyi_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_INITIATOR_HMAKKEY_STR); static const zrtp_string32_t hmac_keyr_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_RESPONDER_HMAKKEY_STR); static const zrtp_string32_t srtp_mki_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_INITIATOR_KEY_STR); static const zrtp_string32_t srtp_msi_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_INITIATOR_SALT_STR); static const zrtp_string32_t srtp_mkr_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_RESPONDER_KEY_STR); static const zrtp_string32_t srtp_msr_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_RESPONDER_SALT_STR); static const zrtp_string32_t zrtp_keyi_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_INITIATOR_ZRTPKEY_STR); static const zrtp_string32_t zrtp_keyr_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_RESPONDER_ZRTPKEY_STR); uint32_t cipher_key_length = (ZRTP_CIPHER_AES128 == session->blockcipher->base.id) ? 16 : 32; const zrtp_string32_t *output_mk_label; const zrtp_string32_t *output_ms_label; const zrtp_string32_t *input_mk_label; const zrtp_string32_t *input_ms_label; const zrtp_string32_t *hmac_key_label; const zrtp_string32_t *peer_hmac_key_label; const zrtp_string32_t *zrtp_key_label; const zrtp_string32_t *peer_zrtp_key_label; /* Define roles and prepare structures */ if (is_initiator) { output_mk_label = &srtp_mki_label; output_ms_label = &srtp_msi_label; input_mk_label = &srtp_mkr_label; input_ms_label = &srtp_msr_label; hmac_key_label = &hmac_keyi_label; peer_hmac_key_label = &hmac_keyr_label; zrtp_key_label = &zrtp_keyi_label; peer_zrtp_key_label = &zrtp_keyr_label; } else { output_mk_label = &srtp_mkr_label; output_ms_label = &srtp_msr_label; input_mk_label = &srtp_mki_label; input_ms_label = &srtp_msi_label; hmac_key_label = &hmac_keyr_label; peer_hmac_key_label = &hmac_keyi_label; zrtp_key_label = &zrtp_keyr_label; peer_zrtp_key_label = &zrtp_keyi_label; } ZRTP_LOG(3, (_ZTU_,"---------------------------------------------------\n")); ZRTP_LOG(3,(_ZTU_,"\tSWITCHING TO SRTP. ID=%u\n", zrtp_log_mode2str(stream->mode), stream->id)); ZRTP_LOG(3,(_ZTU_,"\tI %s\n", is_initiator ? "Initiator" : "Responder")); /* * Compute total messages hash: * total_hash = hash(Hello of responder | Commit | DHPart1 | DHPart2) for DH streams * total_hash = hash(Hello of responder | Commit ) for Fast modes. */ { uint8_t* tok = NULL; uint16_t tok_len = 0; hash_ctx = session->hash->hash_begin(session->hash); if (0 == hash_ctx) { return zrtp_status_fail; } tok = is_initiator ? (uint8_t*)&stream->messages.peer_hello : (uint8_t*) &stream->messages.hello; tok_len = is_initiator ? stream->messages.peer_hello.hdr.length : stream->messages.hello.hdr.length; tok_len = zrtp_ntoh16(tok_len)*4; session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)tok, tok_len); tok = is_initiator ? (uint8_t*)&stream->messages.commit : (uint8_t*)&stream->messages.peer_commit; tok_len = is_initiator ? stream->messages.commit.hdr.length : stream->messages.peer_commit.hdr.length; tok_len = zrtp_ntoh16(tok_len)*4; session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)tok, tok_len); if (ZRTP_IS_STREAM_DH(stream)) { tok = (uint8_t*) (is_initiator ? &stream->messages.peer_dhpart : &stream->messages.dhpart); tok_len = is_initiator ? stream->messages.peer_dhpart.hdr.length : stream->messages.dhpart.hdr.length; tok_len = zrtp_ntoh16(tok_len)*4; session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)tok, tok_len); tok = (uint8_t*)(is_initiator ? &stream->messages.dhpart : &stream->messages.peer_dhpart); tok_len = is_initiator ? stream->messages.dhpart.hdr.length : stream->messages.peer_dhpart.hdr.length; tok_len = zrtp_ntoh16(tok_len)*4; session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)tok, tok_len); } session->hash->hash_end(session->hash, hash_ctx, ZSTR_GV(cc->mes_hash)); hash_ctx = NULL; } /* total hash computing */ /* Total Hash is ready and we can create KDF_Context */ zrtp_zstrcat(ZSTR_GV(cc->kdf_context), is_initiator ? ZSTR_GV(session->zrtp->zid) : ZSTR_GV(session->peer_zid)); zrtp_zstrcat(ZSTR_GV(cc->kdf_context), is_initiator ? ZSTR_GV(session->peer_zid) : ZSTR_GV(session->zrtp->zid)); zrtp_zstrcat(ZSTR_GV(cc->kdf_context), ZSTR_GV(cc->mes_hash)); /* Derive stream key S0 according to key exchange scheme */ if (zrtp_status_ok != _derive_s0(stream, is_initiator)) { return zrtp_status_fail; } /* * Compute HMAC keys. These values will be used after confirmation: * hmackeyi = KDF(s0, "Initiator HMAC key", KDF_Context, negotiated hash length) * hmackeyr = KDF(s0, "Responder HMAC key", KDF_Context, negotiated hash length) */ _zrtp_kdf( stream, ZSTR_GV(cc->s0), ZSTR_GVP(hmac_key_label), ZSTR_GV(stream->protocol->cc->kdf_context), session->hash->digest_length, ZSTR_GV(stream->cc.hmackey)); _zrtp_kdf( stream, ZSTR_GV(cc->s0), ZSTR_GVP(peer_hmac_key_label), ZSTR_GV(stream->protocol->cc->kdf_context), session->hash->digest_length, ZSTR_GV(stream->cc.peer_hmackey)); /* * Computing ZRTP keys for protection of the Confirm packet: * zrtpkeyi = KDF(s0, "Initiator ZRTP key", KDF_Context, negotiated AES key length) * zrtpkeyr = KDF(s0, "Responder ZRTP key", KDF_Context, negotiated AES key length) */ _zrtp_kdf( stream, ZSTR_GV(cc->s0), ZSTR_GVP(zrtp_key_label), ZSTR_GV(stream->protocol->cc->kdf_context), cipher_key_length, ZSTR_GV(stream->cc.zrtp_key)); _zrtp_kdf( stream, ZSTR_GV(cc->s0), ZSTR_GVP(peer_zrtp_key_label), ZSTR_GV(stream->protocol->cc->kdf_context), cipher_key_length, ZSTR_GV(stream->cc.peer_zrtp_key)); #if (defined(ZRTP_DEBUG_ZRTP_KEYS) && ZRTP_DEBUG_ZRTP_KEYS == 1) { char print_buff[256]; ZRTP_LOG(3,(_ZTU_,"\t Messages hash:%s\n", hex2str(cc->mes_hash.buffer, cc->mes_hash.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t S0:%s\n", hex2str(cc->s0.buffer, cc->s0.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t ZRTP Sess:%s\n", hex2str(session->zrtpsess.buffer, session->zrtpsess.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t hmackey:%s\n", hex2str(stream->cc.hmackey.buffer, stream->cc.hmackey.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t peer_hmackeyr:%s\n", hex2str(stream->cc.peer_hmackey.buffer, stream->cc.peer_hmackey.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t ZRTP key:%s\n", hex2str(stream->cc.zrtp_key.buffer, stream->cc.zrtp_key.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t Peer ZRTP key:%s\n", hex2str(stream->cc.peer_zrtp_key.buffer, stream->cc.peer_zrtp_key.length, print_buff, sizeof(print_buff)))); } #endif /* * Preparing SRTP crypto engine: * srtpkeyi = KDF(s0, "Initiator SRTP master key", KDF_Context, negotiated AES key length) * srtpsalti = KDF(s0, "Initiator SRTP master salt", KDF_Context, 112) * srtpkeyr = KDF(s0, "Responder SRTP master key", KDF_Context, negotiated AES key length) * srtpsaltr = KDF(s0, "Responder SRTP master salt", KDF_Context, 112) */ { zrtp_srtp_profile_t iprof; zrtp_srtp_profile_t oprof; ZSTR_SET_EMPTY(iprof.salt); ZSTR_SET_EMPTY(iprof.key); iprof.rtp_policy.cipher = session->blockcipher; iprof.rtp_policy.auth_tag_len = session->authtaglength; iprof.rtp_policy.hash = zrtp_comp_find(ZRTP_CC_HASH, ZRTP_SRTP_HASH_HMAC_SHA1, session->zrtp); iprof.rtp_policy.auth_key_len = 20; iprof.rtp_policy.cipher_key_len = cipher_key_length; zrtp_memcpy(&iprof.rtcp_policy, &iprof.rtp_policy, sizeof(iprof.rtcp_policy)); iprof.dk_cipher = session->blockcipher; zrtp_memcpy(&oprof, &iprof, sizeof(iprof)); _zrtp_kdf( stream, ZSTR_GV(cc->s0), ZSTR_GVP(input_mk_label), ZSTR_GV(stream->protocol->cc->kdf_context), cipher_key_length, ZSTR_GV(iprof.key)); _zrtp_kdf( stream, ZSTR_GV(cc->s0), ZSTR_GVP(input_ms_label), ZSTR_GV(stream->protocol->cc->kdf_context), 14, ZSTR_GV(iprof.salt)); _zrtp_kdf( stream, ZSTR_GV(cc->s0), ZSTR_GVP(output_mk_label), ZSTR_GV(stream->protocol->cc->kdf_context), cipher_key_length, ZSTR_GV(oprof.key)); _zrtp_kdf( stream, ZSTR_GV(cc->s0), ZSTR_GVP(output_ms_label), ZSTR_GV(stream->protocol->cc->kdf_context), 14, ZSTR_GV(oprof.salt)); stream->protocol->_srtp = zrtp_srtp_create(session->zrtp->srtp_global, &iprof, &oprof); /* Profiles and keys in them are not needed anymore - clear them */ zrtp_memset(&iprof, 0, sizeof(iprof)); zrtp_memset(&oprof, 0, sizeof(oprof)); if (!stream->protocol->_srtp) { ZRTP_LOG(1,(_ZTU_,"\tERROR! Can't initialize SRTP engine. ID=%u\n", stream->id)); return zrtp_status_fail; } } /* SRTP initialization */ return zrtp_status_ok; }
/* * Add few entries to the empty cache, flush it and then load again. Check if * all the entries were restored successfully. */ void cache_add2empty_test() { zrtp_status_t status; int intres; /* 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"); 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_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_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"); }
/*----------------------------------------------------------------------------*/ zrtp_status_t _zrtp_machine_process_confirm( zrtp_stream_t *stream, zrtp_packet_Confirm_t *confirm) { /* Compute Hmac over encrypted part of Confirm and reject malformed packets */ void* cipher_ctx = NULL; zrtp_status_t s = zrtp_status_fail; zrtp_session_t *session = stream->session; zrtp_string128_t hmac = ZSTR_INIT_EMPTY(hmac); /* hash + (padding + sig_len + flags) + ttl */ const uint8_t encrypted_body_size = ZRTP_MESSAGE_HASH_SIZE + (2 + 1 + 1) + 4; s = session->hash->hmac_c( session->hash, stream->cc.peer_hmackey.buffer, stream->cc.peer_hmackey.length, (const char*)&confirm->hash, encrypted_body_size, ZSTR_GV(hmac) ); if (zrtp_status_ok != s) { ZRTP_LOG(1,(_ZTU_,"\tERROR! failed to compute Incoming Confirm hmac. s=%d ID=%u\n", s, stream->id)); return zrtp_status_fail; } // MARK: TRACE CONFIRM HMAC ERROR #if 0 { char buff[512]; ZRTP_LOG(3,(_ZTU_,"HMAC TRACE. VERIFY\n")); ZRTP_LOG(3,(_ZTU_,"\tcipher text:%s. size=%u\n", hex2str((const char*)&confirm->hash, encrypted_body_size, buff, sizeof(buff)), encrypted_body_size)); ZRTP_LOG(3,(_ZTU_,"\t key:%s.\n", hex2str(stream->cc.peer_hmackey.buffer, stream->cc.peer_hmackey.length, buff, sizeof(buff)))); ZRTP_LOG(3,(_ZTU_,"\t comp hmac:%s.\n", hex2str(hmac.buffer, hmac.length, buff, sizeof(buff)))); ZRTP_LOG(3,(_ZTU_,"\t hmac:%s.\n", hex2str((const char*)confirm->hmac, ZRTP_HMAC_SIZE, buff, sizeof(buff)))); } #endif if (0 != zrtp_memcmp(confirm->hmac, hmac.buffer, ZRTP_HMAC_SIZE)) { /* * Weird. Perhaps a bug in our code or our peer's code. Or it could be an attacker * who doesn't realize that Man-In-The-Middling the Diffie-Hellman key generation * but allowing the correct rsIds to pass through accomplishes nothing more than * forcing us to fallback to cleartext mode. If this attacker had gone ahead and deleted * or replaced the rsIds, then he would have been able to stay in the middle (although * he would of course still face the threat of a Voice Authentication Check). On the * other hand if this attacker wanted to force us to fallback to cleartext mode, he could * have done that more simply, for example by intercepting our ZRTP HELLO packet and * replacing it with a normal non-ZRTP comfort noise packet. In any case, we'll do our * "switch to cleartext fallback" behavior. */ ZRTP_LOG(2,(_ZTU_,"\tWARNING!" ZRTP_VERIFIED_RESP_WARNING_STR "ID=%u\n", stream->id)); _zrtp_machine_enter_initiatingerror(stream, zrtp_error_auth_decrypt, 1); return zrtp_status_fail; } /* Then we need to decrypt Confirm body */ do { cipher_ctx = session->blockcipher->start( session->blockcipher, (uint8_t*)stream->cc.peer_zrtp_key.buffer, NULL, ZRTP_CIPHER_MODE_CFB); if (!cipher_ctx) { break; } s = session->blockcipher->set_iv( session->blockcipher, cipher_ctx, (zrtp_v128_t*)confirm->iv); if (zrtp_status_ok != s) { break; } s = session->blockcipher->decrypt( session->blockcipher, cipher_ctx, (uint8_t*)&confirm->hash, encrypted_body_size); } while(0); if (cipher_ctx) { session->blockcipher->stop(session->blockcipher, cipher_ctx); } if (zrtp_status_ok != s) { ZRTP_LOG(3,(_ZTU_,"\tERROR! failed to decrypt incoming Confirm. s=%d ID=%u\n", s, stream->id)); return s; } /* We have access to hash field and can check hmac of the previous message */ { zrtp_msg_hdr_t *hdr = NULL; char *key=NULL; zrtp_string32_t tmphash_str = ZSTR_INIT_EMPTY(tmphash_str); zrtp_hash_t *hash = zrtp_comp_find( ZRTP_CC_HASH, ZRTP_HASH_SHA256, stream->zrtp); if (ZRTP_IS_STREAM_DH(stream)) { hdr = &stream->messages.peer_dhpart.hdr; key = (char*)confirm->hash; } else { hash->hash_c(hash, (char*)confirm->hash, ZRTP_MESSAGE_HASH_SIZE, ZSTR_GV(tmphash_str)); if (ZRTP_STATEMACHINE_INITIATOR == stream->protocol->type) { hdr = &stream->messages.peer_hello.hdr; hash->hash_c( hash, tmphash_str.buffer, ZRTP_MESSAGE_HASH_SIZE, ZSTR_GV(tmphash_str) ); } else { hdr = &stream->messages.peer_commit.hdr; } key = tmphash_str.buffer; } if (0 != _zrtp_validate_message_hmac(stream, hdr, key)) { return zrtp_status_fail; } } /* Set evil bit if other-side shared session key */ stream->peer_disclose_bit = (confirm->flags & 0x01); /* Enable ALLOWCLEAR option if only both sides support it */ stream->allowclear = (confirm->flags & 0x02) && session->profile.allowclear; /* Drop RS1 VERIFIED flag if other side didn't verified key exchange */ if (0 == (confirm->flags & 0x04)) { ZRTP_LOG(2,(_ZTU_,"\tINFO: Other side Confirm V=0 - set verified to 0! ID=%u\n", stream->id)); zrtp_verified_set(session->zrtp, &session->zrtp->zid, &session->peer_zid, 0); } /* Look for Enrollment replay flag */ if (confirm->flags & 0x08) { ZRTP_LOG(2,(_ZTU_,"\tINFO: Confirm PBX Enrolled flag is set - it is a Registration call! ID=%u\n", stream->id)); if (stream->mitm_mode != ZRTP_MITM_MODE_CLIENT) { ZRTP_LOG(2,(_ZTU_,"\tERROR: PBX enrollment flag was received in wrong MiTM mode %s." " ID=%u\n", zrtp_log_mode2str(stream->mode), stream->id)); _zrtp_machine_enter_initiatingerror(stream, zrtp_error_invalid_packet, 1); return zrtp_status_fail; } /* Passive endpoint should ignore PBX Enrollment. */ if (ZRTP_LICENSE_MODE_PASSIVE != stream->zrtp->lic_mode) { stream->mitm_mode = ZRTP_MITM_MODE_REG_CLIENT; } else { ZRTP_LOG(2,(_ZTU_,"\tINFO: Ignore PBX Enrollment flag as we are Passive ID=%u\n", stream->id)); } } stream->cache_ttl = ZRTP_MIN(session->profile.cache_ttl, zrtp_ntoh32(confirm->expired_interval)); /* Copy packet for future hashing */ zrtp_memcpy(&stream->messages.peer_confirm, confirm, zrtp_ntoh16(confirm->hdr.length)*4); return zrtp_status_ok; }
/*----------------------------------------------------------------------------*/ zrtp_status_t _zrtp_machine_create_confirm( zrtp_stream_t *stream, zrtp_packet_Confirm_t* confirm) { void* cipher_ctx = NULL; zrtp_status_t s = zrtp_status_fail; zrtp_session_t *session = stream->session; uint32_t verifiedflag = 0; /* hash + (padding + sig_len + flags) + ttl */ const uint8_t encrypted_body_size = ZRTP_MESSAGE_HASH_SIZE + (2 + 1 + 1) + 4; /* * Create the Confirm packet according to draft 6.7 * AES CFB vector at first, SIG length and flags octet and cache TTL at the end * This version doesn't support signatures so sig_length=0 */ if (ZRTP_CFBIV_SIZE != zrtp_randstr(session->zrtp, confirm->iv, ZRTP_CFBIV_SIZE)) { return zrtp_status_fail; } zrtp_memcpy(confirm->hash, stream->messages.h0.buffer, ZRTP_MESSAGE_HASH_SIZE); zrtp_cache_get_verified(session->zrtp->cache, ZSTR_GV(session->peer_zid), &verifiedflag); confirm->expired_interval = zrtp_hton32(session->profile.cache_ttl); confirm->flags = 0; confirm->flags |= session->profile.disclose_bit ? 0x01 : 0x00; confirm->flags |= session->profile.allowclear ? 0x02 : 0x00; confirm->flags |= verifiedflag ? 0x04 : 0x00; confirm->flags |= (ZRTP_MITM_MODE_REG_SERVER == stream->mitm_mode) ? 0x08 : 0x00; /* Then we need to encrypt Confirm before Hmac computing. Use AES CFB */ do { cipher_ctx = session->blockcipher->start( session->blockcipher, (uint8_t*)stream->cc.zrtp_key.buffer, NULL, ZRTP_CIPHER_MODE_CFB); if (!cipher_ctx) { break; } s = session->blockcipher->set_iv(session->blockcipher, cipher_ctx, (zrtp_v128_t*)confirm->iv); if (zrtp_status_ok != s) { break; } s = session->blockcipher->encrypt( session->blockcipher, cipher_ctx, (uint8_t*)&confirm->hash, encrypted_body_size ); } while(0); if (cipher_ctx) { session->blockcipher->stop(session->blockcipher, cipher_ctx); } if (zrtp_status_ok != s) { ZRTP_LOG(1,(_ZTU_,"ERROR! failed to encrypt Confirm. s=%d ID=%u\n", s, stream->id)); return s; } /* Compute Hmac over encrypted part of Confirm */ { zrtp_string128_t hmac = ZSTR_INIT_EMPTY(hmac); s = session->hash->hmac_c( session->hash, stream->cc.hmackey.buffer, stream->cc.hmackey.length, (const char*)&confirm->hash, encrypted_body_size, ZSTR_GV(hmac) ); if (zrtp_status_ok != s) { ZRTP_LOG(1,(_ZTU_,"ERROR! failed to compute Confirm hmac. s=%d ID=%u\n", s, stream->id)); return s; } zrtp_memcpy(confirm->hmac, hmac.buffer, ZRTP_HMAC_SIZE); { char buff[512]; ZRTP_LOG(3,(_ZTU_,"HMAC TRACE. COMPUTE.\n")); ZRTP_LOG(3,(_ZTU_,"\tcipher text:%s. size=%u\n", hex2str((const char*)&confirm->hash, encrypted_body_size, buff, sizeof(buff)), encrypted_body_size)); ZRTP_LOG(3,(_ZTU_,"\t key:%s.\n", hex2str(stream->cc.hmackey.buffer, stream->cc.hmackey.length, buff, sizeof(buff)))); ZRTP_LOG(3,(_ZTU_,"\t comp hmac:%s.\n", hex2str(hmac.buffer, hmac.length, buff, sizeof(buff)))); ZRTP_LOG(3,(_ZTU_,"\t hmac:%s.\n", hex2str((const char*)confirm->hmac, ZRTP_HMAC_SIZE, buff, sizeof(buff)))); } } return zrtp_status_ok; }
/*----------------------------------------------------------------------------*/ zrtp_status_t _zrtp_machine_process_sasrelay(zrtp_stream_t *stream, zrtp_rtp_info_t *packet) { zrtp_session_t *session = stream->session; zrtp_packet_SASRelay_t *sasrelay = (zrtp_packet_SASRelay_t*) packet->message; void* cipher_ctx = NULL; zrtp_sas_id_t rendering_id = ZRTP_COMP_UNKN; zrtp_status_t s = zrtp_status_fail; zrtp_string128_t hmac = ZSTR_INIT_EMPTY(hmac); char zerosashash[32]; unsigned sas_scheme_did_change = 0; unsigned sas_hash_did_change = 0; /* (padding + sig_len + flags) + SAS scheme and SAS hash */ const uint8_t encrypted_body_size = (2 + 1 + 1) + 4 + 32; zrtp_memset(zerosashash, 0, sizeof(zerosashash)); /* Check if the remote endpoint is assigned to relay the SAS values */ if (!stream->peer_mitm_flag) { ZRTP_LOG(2,(_ZTU_, ZRTP_RELAYED_SAS_FROM_NONMITM_STR)); return zrtp_status_fail; } /* Check the HMAC */ s = session->hash->hmac_c( session->hash, stream->cc.peer_hmackey.buffer, stream->cc.peer_hmackey.length, (const char*)&sasrelay->pad, encrypted_body_size, ZSTR_GV(hmac) ); if (zrtp_status_ok != s ) { ZRTP_LOG(1,(_ZTU_,"\tERROR! Failed to compute CONFIRM hmac. status=%d ID=%u\n", s, stream->id)); return zrtp_status_fail; } if (0 != zrtp_memcmp(sasrelay->hmac, hmac.buffer, ZRTP_HMAC_SIZE)) { ZRTP_LOG(2,(_ZTU_, ZRTP_VERIFIED_RESP_WARNING_STR)); return zrtp_status_fail; } ZRTP_LOG(3,(_ZTU_, "\tHMAC value for the SASRELAY is correct - decrypting...\n")); /* Then we need to decrypt Confirm body */ do { cipher_ctx = session->blockcipher->start( session->blockcipher, (uint8_t*)stream->cc.peer_zrtp_key.buffer, NULL, ZRTP_CIPHER_MODE_CFB ); if (!cipher_ctx) { break; } s = session->blockcipher->set_iv(session->blockcipher, cipher_ctx, (zrtp_v128_t*)sasrelay->iv); if (zrtp_status_ok != s) { break; } s = session->blockcipher->encrypt( session->blockcipher, cipher_ctx, (uint8_t*)&sasrelay->pad, encrypted_body_size); } while(0); if (cipher_ctx) { session->blockcipher->stop(session->blockcipher, cipher_ctx); } if (zrtp_status_ok != s) { ZRTP_LOG(1,(_ZTU_,"\tERROR! Failed to decrypt Confirm. status=%d ID=%u\n", s, stream->id)); return s; } ZRTP_LOG(2,(_ZTU_,"\tSasRelay FLAGS old/new A=%d/%d, D=%d/%d.\n", stream->allowclear, (uint8_t)(sasrelay->flags & 0x02), stream->peer_disclose_bit, (uint8_t)(sasrelay->flags & 0x01))); /* Set evil bit if other-side disclosed session key */ stream->peer_disclose_bit = (sasrelay->flags & 0x01); /* Enable ALLOWCLEAR option only if both sides support it */ stream->allowclear = (sasrelay->flags & 0x02) && session->profile.allowclear; /* * We don't handle verified flag in SASRelaying because it makes no * sense in implementation of the ZRTP Internet Draft. */ /* * Only enrolled users can do SAS transferring. (Non-enrolled users can * only change the SAS rendering scheme). */ rendering_id = zrtp_comp_type2id(ZRTP_CC_SAS, (char*)sasrelay->sas_scheme); if (-1 == zrtp_profile_find(&session->profile, ZRTP_CC_SAS, rendering_id)) { ZRTP_LOG(1,(_ZTU_,"\tERROR! PBX Confirm packet with transferred SAS have unknown or" " unsupported rendering scheme %.4s.ID=%u\n", sasrelay->sas_scheme, stream->id)); _zrtp_machine_enter_initiatingerror(stream, zrtp_error_invalid_packet, 1); return zrtp_status_fail; } /* Check is SAS rendering did change */ if (rendering_id != session->sasscheme->base.id) { session->sasscheme = zrtp_comp_find(ZRTP_CC_SAS, rendering_id, session->zrtp ); sas_scheme_did_change = 1; ZRTP_LOG(3,(_ZTU_,"\tSasrelay: Rendering scheme was updated to %.4s.\n", session->sasscheme->base.type)); } if (session->secrets.matches & ZRTP_BIT_PBX) { if ( ( ((uint32_t) *sasrelay->sas_scheme) != (uint32_t)0x0L ) && (0 != zrtp_memcmp(sasrelay->sashash, zerosashash, sizeof(sasrelay->sashash))) ) { char buff[256]; session->sasbin.length = ZRTP_MITM_SAS_SIZE; /* First 32 bits if sashash includes sasvalue */ zrtp_memcpy(session->sasbin.buffer, sasrelay->sashash, session->sasbin.length); stream->mitm_mode = ZRTP_MITM_MODE_RECONFIRM_CLIENT; sas_hash_did_change = 1; ZRTP_LOG(3,(_ZTU_,"\tSasRelay: SAS value was updated to bin=%s.\n", hex2str(buff, sizeof(buff), session->sasbin.buffer, session->sasbin.length))); } } else if (0 != zrtp_memcmp(sasrelay->sashash, zerosashash, sizeof(sasrelay->sashash))) { ZRTP_LOG(1,(_ZTU_,"\tWARNING! SAS Value was received from NOT Trusted MiTM. ID=%u\n", stream->id)); _zrtp_machine_enter_initiatingerror(stream, zrtp_error_possible_mitm3, 1); return zrtp_status_fail; } else { ZRTP_LOG(1,(_ZTU_, "\rERROR! For SasRelay Other secret doesn't match. ID=%u\n", stream->id)); } /* Generate new SAS if hash or rendering scheme did change. * Note: latest libzrtp may send "empty" SasRelay with the same SAS rendering * scheme and empty Hello hash for consistency reasons, we should ignore * such packets. */ if (sas_scheme_did_change || sas_hash_did_change) { s = session->sasscheme->compute(session->sasscheme, stream, session->hash, 1); if (zrtp_status_ok != s) { _zrtp_machine_enter_initiatingerror(stream, zrtp_error_software, 1); return s; } ZRTP_LOG(3,(_ZTU_,"\tSasRelay: Updated SAS is <%s> <%s>.\n", session->sas1.buffer, session->sas2.buffer)); if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { session->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_LOCAL_SAS_UPDATED); } } return zrtp_status_ok; }
/*---------------------------------------------------------------------------*/ zrtp_status_t zrtp_register_with_trusted_mitm(zrtp_stream_t* stream) { zrtp_session_t *session = stream->session; zrtp_status_t s = zrtp_status_bad_param; if (!stream) { return zrtp_status_bad_param; } ZRTP_LOG(3,(_ZTU_,"MARKING this call as REGISTRATION ID=%u\n", stream->id)); if (NULL == stream->zrtp->cb.cache_cb.on_get_mitm) { ZRTP_LOG(2,(_ZTU_,"WARNING: Can't use MiTM Functions with no ZRTP Cache.\n")); return zrtp_status_notavailable; } if (!stream->protocol) { return zrtp_status_bad_param; } /* Passive Client endpoint should NOT generate PBX Secret. */ if ((stream->mitm_mode == ZRTP_MITM_MODE_REG_CLIENT) && (ZRTP_LICENSE_MODE_PASSIVE == stream->zrtp->lic_mode)) { ZRTP_LOG(2,(_ZTU_,"WARNING: Passive Client endpoint should NOT generate PBX Secret.\n")); return zrtp_status_bad_param; } /* * Generate new MitM cache: * pbxsecret = KDF(ZRTPSess, "Trusted MiTM key", (ZIDi | ZIDr), negotiated hash length) */ if ( (stream->state == ZRTP_STATE_SECURE) && ((stream->mitm_mode == ZRTP_MITM_MODE_REG_CLIENT) || (stream->mitm_mode == ZRTP_MITM_MODE_REG_SERVER)) ) { zrtp_string32_t kdf_context = ZSTR_INIT_EMPTY(kdf_context); static const zrtp_string32_t trusted_mitm_key_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_TRUSTMITMKEY_STR); zrtp_string16_t *zidi, *zidr; if (stream->protocol->type == ZRTP_STATEMACHINE_INITIATOR) { zidi = &session->zid; zidr = &session->peer_zid; } else { zidi = &session->peer_zid; zidr = &session->zid; } zrtp_zstrcat(ZSTR_GV(kdf_context), ZSTR_GVP(zidi)); zrtp_zstrcat(ZSTR_GV(kdf_context), ZSTR_GVP(zidr)); _zrtp_kdf( stream, ZSTR_GV(session->zrtpsess), ZSTR_GV(trusted_mitm_key_label), ZSTR_GV(kdf_context), ZRTP_HASH_SIZE, ZSTR_GV(session->secrets.pbxs->value)); session->secrets.pbxs->_cachedflag = 1; session->secrets.pbxs->lastused_at = (uint32_t)(zrtp_time_now()/1000); session->secrets.cached |= ZRTP_BIT_PBX; session->secrets.matches |= ZRTP_BIT_PBX; s = zrtp_status_ok; if (session->zrtp->cb.cache_cb.on_put_mitm) { s = session->zrtp->cb.cache_cb.on_put_mitm( ZSTR_GV(session->zid), ZSTR_GV(session->peer_zid), session->secrets.pbxs); } ZRTP_LOG(3,(_ZTU_,"Makring this call as REGISTRATION - DONE\n")); } return s; }
/*----------------------------------------------------------------------------*/ zrtp_status_t zrtp_session_init( zrtp_global_t* zrtp, zrtp_profile_t* profile, zrtp_zid_t zid, zrtp_signaling_role_t role, zrtp_session_t **session) { uint32_t i = 0; zrtp_status_t s = zrtp_status_fail; zrtp_session_t* new_session = NULL; if (!zrtp) { return zrtp_status_bad_param; } new_session = zrtp_sys_alloc(sizeof(zrtp_session_t)); if (!new_session) { return zrtp_status_alloc_fail; } zrtp_memset(new_session, 0, sizeof(zrtp_session_t)); new_session->id = zrtp->sessions_count++; { zrtp_uchar32_t buff; ZRTP_LOG(3, (_ZTU_,"START SESSION INITIALIZATION. sID=%u.\n", new_session->id)); ZRTP_LOG(3, (_ZTU_,"ZID=%s.\n", hex2str((const char*)zid, sizeof(zrtp_uchar12_t), (char*)buff, sizeof(buff)) )); } do { /* * Apply profile for the stream context: set flags and prepare Hello packet. * If profile structure isn't provided, generate default. */ if (!profile) { ZRTP_LOG(1, (_ZTU_,"Profile in NULL - loading default one.\n")); zrtp_profile_defaults(&new_session->profile, zrtp); } else { ZRTP_LOG(1, (_ZTU_,"Loading User's profile:\n")); if (zrtp_status_ok != zrtp_profile_check(profile, zrtp)) { ZRTP_LOG(1, (_ZTU_,"ERROR! Can't apply wrong profile to the session sID=%u.\n", new_session->id)); break; } /* Adjust user's settings: force SHA-384 hash for ECDH-384P */ if (zrtp_profile_find(profile, ZRTP_CC_PKT, ZRTP_PKTYPE_EC384P) > 0) { ZRTP_LOG(3, (_ZTU_,"User wants ECDH384 - auto-adjust profile to use SHA-384.\n")); profile->hash_schemes[0] = ZRTP_HASH_SHA384; profile->hash_schemes[1] = ZRTP_HASH_SHA256; profile->hash_schemes[2] = 0; } zrtp_memcpy(&new_session->profile, profile, sizeof(zrtp_profile_t)); { int i; ZRTP_LOG(3, (_ZTU_," allowclear: %s\n", profile->allowclear?"ON":"OFF")); ZRTP_LOG(3, (_ZTU_," autosecure: %s\n", profile->autosecure?"ON":"OFF")); ZRTP_LOG(3, (_ZTU_," disclose_bit: %s\n", profile->disclose_bit?"ON":"OFF")); ZRTP_LOG(3, (_ZTU_," signal. role: %s\n", zrtp_log_sign_role2str(role))); ZRTP_LOG(3, (_ZTU_," TTL: %u\n", profile->cache_ttl)); ZRTP_LOG(3, (_ZTU_," SAS schemes: ")); i=0; while (profile->sas_schemes[i]) { ZRTP_LOGC(3, ("%.4s ", zrtp_comp_id2type(ZRTP_CC_SAS, profile->sas_schemes[i++]))); } ZRTP_LOGC(3, ("\n")); ZRTP_LOG(1, (_ZTU_," Ciphers: ")); i=0; while (profile->cipher_types[i]) { ZRTP_LOGC(3, ("%.4s ", zrtp_comp_id2type(ZRTP_CC_CIPHER, profile->cipher_types[i++]))); } ZRTP_LOGC(3, ("\n")); ZRTP_LOG(1, (_ZTU_," PK schemes: ")); i=0; while (profile->pk_schemes[i]) { ZRTP_LOGC(3, ("%.4s ", zrtp_comp_id2type(ZRTP_CC_PKT, profile->pk_schemes[i++]))); } ZRTP_LOGC(3, ("\n")); ZRTP_LOG(1, (_ZTU_," ATL: ")); i=0; while (profile->auth_tag_lens[i]) { ZRTP_LOGC(3, ("%.4s ", zrtp_comp_id2type(ZRTP_CC_ATL, profile->auth_tag_lens[i++]))); } ZRTP_LOGC(3, ("\n")); ZRTP_LOG(1, (_ZTU_," Hashes: ")); i=0; while (profile->hash_schemes[i]) { ZRTP_LOGC(3, ("%.4s ", zrtp_comp_id2type(ZRTP_CC_HASH, profile->hash_schemes[i++]))); } ZRTP_LOGC(3, ("\n")); } } /* Set ZIDs */ ZSTR_SET_EMPTY(new_session->zid); ZSTR_SET_EMPTY(new_session->peer_zid); zrtp_zstrncpyc(ZSTR_GV(new_session->zid), (const char*)zid, sizeof(zrtp_zid_t)); new_session->zrtp = zrtp; new_session->signaling_role = role; new_session->mitm_alert_detected = 0; /* * Allocate memory for holding secrets and initialize with random values. * Actual values will be written from the cache at the beginning of the protocol. */ new_session->secrets.rs1 = _zrtp_alloc_shared_secret(new_session); new_session->secrets.rs2 = _zrtp_alloc_shared_secret(new_session); new_session->secrets.auxs = _zrtp_alloc_shared_secret(new_session); new_session->secrets.pbxs = _zrtp_alloc_shared_secret(new_session); if ( !new_session->secrets.rs1 || !new_session->secrets.rs2 || !new_session->secrets.auxs || !new_session->secrets.pbxs) { ZRTP_LOG(1, (_ZTU_,"ERROR! Can't allocate shared secrets sID=%u\n.", new_session->id)); s = zrtp_status_alloc_fail; break; } /* Initialize SAS values */ ZSTR_SET_EMPTY(new_session->sas1); ZSTR_SET_EMPTY(new_session->sas2); ZSTR_SET_EMPTY(new_session->sasbin); ZSTR_SET_EMPTY(new_session->zrtpsess); /* Clear all stream structures */ for (i=0; i<ZRTP_MAX_STREAMS_PER_SESSION ; i++) { new_session->streams[i].state = ZRTP_STATE_NONE; new_session->streams[i].prev_state = ZRTP_STATE_NONE; new_session->streams[i].mode = ZRTP_STREAM_MODE_UNKN; } /* Initialize synchronization objects */ s = zrtp_mutex_init(&new_session->streams_protector); if (zrtp_status_ok != s) { ZRTP_LOG(1, (_ZTU_,"ERROR! can't initialize Stream protector. sID=%u.\n", new_session->id)); break; } s = zrtp_mutex_init(&new_session->init_protector); if (zrtp_status_ok != s) { ZRTP_LOG(1, (_ZTU_,"ERROR! can't initialize Init protector. sID=%u.\n", new_session->id)); break; } s = zrtp_status_ok; } while (0); if (zrtp_status_ok != s) { zrtp_sys_free(new_session); return s; } /* Add new session to the global list */ zrtp_mutex_lock(zrtp->sessions_protector); mlist_add(&zrtp->sessions_head, &new_session->_mlist); zrtp_mutex_unlock(zrtp->sessions_protector); *session = new_session; ZRTP_LOG(3, (_ZTU_,"Session initialization - DONE. sID=%u.\n\n", new_session->id)); return zrtp_status_ok; }
/*---------------------------------------------------------------------------*/ static zrtp_status_t _derive_s0(zrtp_stream_t* stream, int is_initiator) { static const zrtp_string32_t zrtp_kdf_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_KDF_STR); static const zrtp_string32_t zrtp_sess_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_SESS_STR); static const zrtp_string32_t zrtp_multi_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_MULTI_STR); static const zrtp_string32_t zrtp_presh_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_PRESH_STR); zrtp_session_t *session = stream->session; zrtp_secrets_t* secrets = &session->secrets; zrtp_proto_crypto_t* cc = stream->protocol->cc; void* hash_ctx = NULL; char print_buff[256]; switch (stream->mode) { /* * S0 computing for FULL DH exchange * S0 computing. s0 is the master shared secret used for all * cryptographic operations. In particular, note the inclusion * of "total_hash", a hash of all packets exchanged up to this * point. This belatedly detects any tampering with earlier * packets, e.g. bid-down attacks. * * s0 = hash( 1 | DHResult | "ZRTP-HMAC-KDF" | ZIDi | ZIDr | * total_hash | len(s1) | s1 | len(s2) | s2 | len(s3) | s3 ) * The constant 1 and all lengths are 32 bits big-endian values. * The fields without length prefixes are fixed-witdh: * - DHresult is fixed to the width of the DH prime. * - The hash type string and ZIDs are fixed width. * - total_hash is fixed by the hash negotiation. * The constant 1 is per NIST SP 800-56A section 5.8.1, and is * a counter which can be incremented to generate more than 256 * bits of key material. * ======================================================================== */ case ZRTP_STREAM_MODE_DH: { zrtp_proto_secret_t *C[3] = { 0, 0, 0}; int i = 0; uint32_t comp_length = 0; zrtp_stringn_t *zidi = NULL, *zidr = NULL; struct BigNum dhresult; #if (defined(ZRTP_USE_STACK_MINIM) && (ZRTP_USE_STACK_MINIM == 1)) zrtp_uchar1024_t* buffer = zrtp_sys_alloc( sizeof(zrtp_uchar1024_t) ); if (!buffer) { return zrtp_status_alloc_fail; } #else zrtp_uchar1024_t holder; zrtp_uchar1024_t* buffer = &holder; #endif ZRTP_LOG(3,(_ZTU_,"\tDERIVE S0 from DH exchange and RS secrets...\n")); ZRTP_LOG(3,(_ZTU_,"\t my rs1ID:%s\n", hex2str(cc->rs1.id.buffer, cc->rs1.id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his rs1ID:%s\n", hex2str((const char*)stream->messages.peer_dhpart.rs1ID, ZRTP_RSID_SIZE, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his rs1ID comp:%s\n", hex2str(cc->rs1.peer_id.buffer, cc->rs1.peer_id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t my rs2ID:%s\n", hex2str(cc->rs2.id.buffer, cc->rs2.id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his rs2ID:%s\n", hex2str((const char*)stream->messages.peer_dhpart.rs2ID, ZRTP_RSID_SIZE, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his rs2ID comp:%s\n", hex2str(cc->rs2.peer_id.buffer, cc->rs2.peer_id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t my pbxsID:%s\n", hex2str(cc->pbxs.id.buffer, cc->pbxs.id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his pbxsID:%s\n", hex2str((const char*)stream->messages.peer_dhpart.pbxsID, ZRTP_RSID_SIZE, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\this pbxsID comp:%s\n", hex2str(cc->pbxs.peer_id.buffer, cc->pbxs.peer_id.length, print_buff, sizeof(print_buff)))); hash_ctx = session->hash->hash_begin(session->hash); if (0 == hash_ctx) { ZRTP_LOG(1,(_ZTU_, "\tERROR! can't start hash calculation for S0 computing. ID=%u.\n", stream->id)); return zrtp_status_fail; } /* * NIST requires a 32-bit big-endian integer counter to be included * in the hash each time the hash is computed, which we have set to * the fixed value of 1, because we only compute the hash once. */ comp_length = zrtp_hton32(1L); session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&comp_length, 4); switch (stream->pubkeyscheme->base.id) { case ZRTP_PKTYPE_DH2048: case ZRTP_PKTYPE_DH3072: case ZRTP_PKTYPE_DH4096: comp_length = stream->pubkeyscheme->pv_length; ZRTP_LOG(3,(_ZTU_,"DH comp_length=%u\n", comp_length)); break; case ZRTP_PKTYPE_EC256P: case ZRTP_PKTYPE_EC384P: case ZRTP_PKTYPE_EC521P: comp_length = stream->pubkeyscheme->pv_length/2; ZRTP_LOG(3,(_ZTU_,"ECDH comp_length=%u\n", comp_length)); break; default: break; } bnBegin(&dhresult); stream->pubkeyscheme->compute(stream->pubkeyscheme, &stream->dh_cc, &dhresult, &stream->dh_cc.peer_pv); bnExtractBigBytes(&dhresult, (uint8_t *)buffer, 0, comp_length); session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)buffer, comp_length); bnEnd(&dhresult); #if (defined(ZRTP_USE_STACK_MINIM) && (ZRTP_USE_STACK_MINIM == 1)) zrtp_sys_free(buffer); #endif /* Add "ZRTP-HMAC-KDF" to the S0 hash */ session->hash->hash_update( session->hash, hash_ctx, (const int8_t*)&zrtp_kdf_label.buffer, zrtp_kdf_label.length); /* Then Initiator's and Responder's ZIDs */ if (stream->protocol->type == ZRTP_STATEMACHINE_INITIATOR) { zidi = ZSTR_GV(stream->session->zrtp->zid); zidr = ZSTR_GV(stream->session->peer_zid); } else { zidr = ZSTR_GV(stream->session->zrtp->zid); zidi = ZSTR_GV(stream->session->peer_zid); } session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&zidi->buffer, zidi->length); session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&zidr->buffer, zidr->length); session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&cc->mes_hash.buffer, cc->mes_hash.length); /* If everything is OK - RS1 should much */ if (!zrtp_memcmp(cc->rs1.peer_id.buffer, stream->messages.peer_dhpart.rs1ID, ZRTP_RSID_SIZE)) { C[0] = &cc->rs1; secrets->matches |= ZRTP_BIT_RS1; } /* If we have lost our RS1 - remote party should use backup (RS2) instead */ else if (!zrtp_memcmp(cc->rs1.peer_id.buffer, stream->messages.peer_dhpart.rs2ID, ZRTP_RSID_SIZE)) { C[0] = &cc->rs1; secrets->matches |= ZRTP_BIT_RS1; ZRTP_LOG(2,(_ZTU_,"\tINFO! We have lost our RS1 from previous broken exchange" " - remote party will use RS2 backup. ID=%u\n", stream->id)); } /* If remote party lost it's secret - we will use backup */ else if (!zrtp_memcmp(cc->rs2.peer_id.buffer, stream->messages.peer_dhpart.rs1ID, ZRTP_RSID_SIZE)) { C[0] = &cc->rs2; cc->rs1 = cc->rs2; secrets->matches |= ZRTP_BIT_RS1; secrets->cached |= ZRTP_BIT_RS1; ZRTP_LOG(2,(_ZTU_,"\tINFO! Remote party has lost it's RS1 - use RS2 backup. ID=%u\n", stream->id)); } else { secrets->matches &= ~ZRTP_BIT_RS1; zrtp_cache_set_verified(session->zrtp->cache, ZSTR_GV(session->peer_zid), 0); zrtp_cache_reset_secure_since(session->zrtp->cache, ZSTR_GV(session->peer_zid)); ZRTP_LOG(2,(_ZTU_,"\tINFO! Our RS1 doesn't equal to other-side's one %s. ID=%u\n", cc->rs1.secret->_cachedflag ? " - drop verified!" : "", stream->id)); } if (!zrtp_memcmp(cc->rs2.peer_id.buffer, stream->messages.peer_dhpart.rs2ID, ZRTP_RSID_SIZE)) { secrets->matches |= ZRTP_BIT_RS2; if (0 == C[0]) { C[0] = &cc->rs2; } } if (secrets->auxs && (!zrtp_memcmp(stream->messages.peer_dhpart.auxsID, cc->auxs.peer_id.buffer, ZRTP_RSID_SIZE)) ) { C[1] =&cc->auxs; secrets->matches |= ZRTP_BIT_AUX; } if ( secrets->pbxs && (!zrtp_memcmp(stream->messages.peer_dhpart.pbxsID, cc->pbxs.peer_id.buffer, ZRTP_RSID_SIZE)) ) { C[2] = &cc->pbxs; secrets->matches |= ZRTP_BIT_PBX; } /* Finally hashing matched shared secrets */ for (i=0; i<3; i++) { /* * Some of the shared secrets s1 through s5 may have lengths of zero * if they are null (not shared), and are each preceded by a 4-octet * length field. For example, if s4 is null, len(s4) is 00 00 00 00, * and s4 itself would be absent from the hash calculation, which * means len(s5) would immediately follow len(s4). */ comp_length = C[i] ? zrtp_hton32(ZRTP_RS_SIZE) : 0; session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&comp_length, 4); if (C[i]) { session->hash->hash_update( session->hash, hash_ctx, (const int8_t*)C[i]->secret->value.buffer, C[i]->secret->value.length ); ZRTP_LOG(3,(_ZTU_,"\tUse S%d in calculations.\n", i+1)); } } session->hash->hash_end(session->hash, hash_ctx, ZSTR_GV(cc->s0)); } break; /* S0 for for DH and Preshared streams */ /* * Compute all possible combinations of preshared_key: * hash(len(rs1) | rs1 | len(auxsecret) | auxsecret | len(pbxsecret) | pbxsecret) * Find matched preshared_key and derive S0 from it: * s0 = KDF(preshared_key, "ZRTP Stream Key", KDF_Context, negotiated hash length) * * INFO: Take into account that RS1 and RS2 may be swapped. * If no matched were found - generate DH commit. * ======================================================================== */ case ZRTP_STREAM_MODE_PRESHARED: { zrtp_status_t s = zrtp_status_ok; zrtp_string32_t presh_key = ZSTR_INIT_EMPTY(presh_key); ZRTP_LOG(3,(_ZTU_,"\tDERIVE S0 for PRESHARED from cached secret. ID=%u\n", stream->id)); /* Use the same hash as we used for Commitment */ if (is_initiator) { s = _zrtp_compute_preshared_key( session, ZSTR_GV(session->secrets.rs1->value), (session->secrets.auxs->_cachedflag) ? ZSTR_GV(session->secrets.auxs->value) : NULL, (session->secrets.pbxs->_cachedflag) ? ZSTR_GV(session->secrets.pbxs->value) : NULL, ZSTR_GV(presh_key), NULL); if (zrtp_status_ok != s) { return s; } secrets->matches |= ZRTP_BIT_RS1; if (session->secrets.auxs->_cachedflag) { secrets->matches |= ZRTP_BIT_AUX; } if (session->secrets.pbxs->_cachedflag) { secrets->matches |= ZRTP_BIT_PBX; } } /* * Let's find appropriate hv key for Responder: * <RS1, 0, 0>, <RS1, AUX, 0>, <RS1, 0, PBX>, <RS1, AUX, PBX>. */ else { int res=-1; char* peer_key_id = (char*)stream->messages.peer_commit.hv+ZRTP_HV_NONCE_SIZE; zrtp_string8_t key_id = ZSTR_INIT_EMPTY(key_id); do { /* RS1 MUST be available at this stage.*/ s = _zrtp_compute_preshared_key( session, ZSTR_GV(secrets->rs1->value), NULL, NULL, ZSTR_GV(presh_key), ZSTR_GV(key_id)); if (zrtp_status_ok == s) { res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); if (0 == res) { secrets->matches |= ZRTP_BIT_RS1; break; } } if (session->secrets.pbxs->_cachedflag) { s = _zrtp_compute_preshared_key( session, ZSTR_GV(secrets->rs1->value), NULL, ZSTR_GV(secrets->pbxs->value), ZSTR_GV(presh_key), ZSTR_GV(key_id)); if (zrtp_status_ok == s) { res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); if (0 == res) { secrets->matches |= ZRTP_BIT_PBX; break; } } } if (session->secrets.auxs->_cachedflag) { s = _zrtp_compute_preshared_key( session, ZSTR_GV(secrets->rs1->value), ZSTR_GV(secrets->auxs->value), NULL, ZSTR_GV(presh_key), ZSTR_GV(key_id)); if (zrtp_status_ok == s) { res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); if (0 == res) { secrets->matches |= ZRTP_BIT_AUX; break; } } } if ((session->secrets.pbxs->_cachedflag) && (session->secrets.auxs->_cachedflag)) { s = _zrtp_compute_preshared_key( session, ZSTR_GV(secrets->rs1->value), ZSTR_GV(secrets->auxs->value), ZSTR_GV(secrets->pbxs->value), ZSTR_GV(presh_key), ZSTR_GV(key_id)); if (zrtp_status_ok == s) { res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); if (0 == res) { secrets->matches |= ZRTP_BIT_AUX; secrets->matches |= ZRTP_BIT_PBX; break; } } } } while (0); if (0 != res) { ZRTP_LOG(3,(_ZTU_,"\tINFO! Matched Key wasn't found - initate DH exchange.\n")); secrets->cached = 0; secrets->rs1->_cachedflag = 0; _zrtp_machine_start_initiating_secure(stream); return zrtp_status_ok; } } ZRTP_LOG(3,(_ZTU_,"\tUse RS1, %s, %s in calculations.\n", (session->secrets.matches & ZRTP_BIT_AUX) ? "AUX" : "NULL", (session->secrets.matches & ZRTP_BIT_PBX) ? "PBX" : "NULL")); _zrtp_kdf( stream, ZSTR_GV(presh_key), ZSTR_GV(zrtp_presh_label), ZSTR_GV(stream->protocol->cc->kdf_context), session->hash->digest_length, ZSTR_GV(cc->s0)); } break; /* * For FAST Multistream: * s0n = KDF(ZRTPSess, "ZRTP Multistream Key", KDF_Context, negotiated hash length) * ======================================================================== */ case ZRTP_STREAM_MODE_MULT: { ZRTP_LOG(3,(_ZTU_,"\tDERIVE S0 for MULTISTREAM from ZRTP Session key... ID=%u\n", stream->id)); _zrtp_kdf( stream, ZSTR_GV(session->zrtpsess), ZSTR_GV(zrtp_multi_label), ZSTR_GV(stream->protocol->cc->kdf_context), session->hash->digest_length, ZSTR_GV(cc->s0)); } break; default: break; } /* * Compute ZRTP session key for FULL streams only: * ZRTPSess = KDF(s0, "ZRTP Session Key", KDF_Context, negotiated hash length) */ if (!ZRTP_IS_STREAM_MULT(stream)) { if (session->zrtpsess.length == 0) { _zrtp_kdf( stream, ZSTR_GV(cc->s0), ZSTR_GV(zrtp_sess_label), ZSTR_GV(stream->protocol->cc->kdf_context), session->hash->digest_length, ZSTR_GV(session->zrtpsess)); } } return zrtp_status_ok; }
/* * 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))); }