Esempio n. 1
0
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;
}
Esempio n. 4
0
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
}
Esempio n. 5
0
/*---------------------------------------------------------------------------*/
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;	
}
Esempio n. 6
0
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;
	}
}
Esempio n. 7
0
/*----------------------------------------------------------------------------*/
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;
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
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;
}
Esempio n. 10
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);
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
/*
 * 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)));
}
Esempio n. 14
0
/*----------------------------------------------------------------------------*/
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;
}
Esempio n. 15
0
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);
}
Esempio n. 16
0
/*----------------------------------------------------------------------------*/
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;
}
Esempio n. 17
0
/*---------------------------------------------------------------------------*/
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;
}
Esempio n. 18
0
/*----------------------------------------------------------------------------*/
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;
}
Esempio n. 19
0
/*
 * 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)));
}
Esempio n. 20
0
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");
}
Esempio n. 21
0
/*----------------------------------------------------------------------------*/
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;
}
Esempio n. 22
0
/*----------------------------------------------------------------------------*/
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;
}
Esempio n. 23
0
/*----------------------------------------------------------------------------*/
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;
}
Esempio n. 24
0
/*---------------------------------------------------------------------------*/
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;
}
Esempio n. 25
0
/*----------------------------------------------------------------------------*/
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;
}
Esempio n. 26
0
/*---------------------------------------------------------------------------*/
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;
}
Esempio n. 27
0
/*
 * 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)));
}