static zrtp_status_t zrtp_dh_initialize( zrtp_pk_scheme_t *self, zrtp_dh_crypto_context_t *dh_cc) { unsigned char* buffer = zrtp_sys_alloc(sizeof(zrtp_uchar128_t)); struct BigNum* p = _zrtp_get_p(self); zrtp_time_t start_ts = zrtp_time_now(); ZRTP_LOG(1,(_ZTU_,"\tDH TEST: %.4s zrtp_dh_initialize() START. now=%llums.\n", self->base.type, start_ts)); if (!buffer) { return zrtp_status_alloc_fail; } if (!p) { zrtp_sys_free(buffer); return zrtp_status_bad_param; } if (64 != zrtp_randstr(self->base.zrtp, buffer, 64)) { zrtp_sys_free(buffer); return zrtp_status_rng_fail; } bnBegin(&dh_cc->sv); bnInsertBigBytes(&dh_cc->sv, (const unsigned char *)buffer, 0, self->sv_length); bnBegin(&dh_cc->pv); bnExpMod(&dh_cc->pv, &self->base.zrtp->G, &dh_cc->sv, p); zrtp_sys_free(buffer); ZRTP_LOG(1,(_ZTU_,"\tDH TEST: zrtp_dh_initialize() for %.4s was executed ts=%llums d=%llums.\n", self->base.type, zrtp_time_now(), zrtp_time_now()-start_ts)); return zrtp_status_ok; }
zrtp_status_t zrtp_defaults_atl(zrtp_global_t* global_ctx) { zrtp_auth_tag_length_t* atl32 = zrtp_sys_alloc(sizeof(zrtp_auth_tag_length_t)); zrtp_auth_tag_length_t* atl80 = zrtp_sys_alloc(sizeof(zrtp_auth_tag_length_t)); if (!atl32 || !atl80) { if(atl32) zrtp_sys_free(atl32); if(atl80) zrtp_sys_free(atl80); return zrtp_status_alloc_fail; } zrtp_memset(atl32, 0, sizeof(zrtp_auth_tag_length_t)); zrtp_memcpy(atl32->base.type, ZRTP_HS32, ZRTP_COMP_TYPE_SIZE); atl32->base.id = ZRTP_ATL_HS32; atl32->base.zrtp = global_ctx; atl32->tag_length = 4; zrtp_memset(atl80, 0, sizeof(zrtp_auth_tag_length_t)); zrtp_memcpy(atl80->base.type, ZRTP_HS80, ZRTP_COMP_TYPE_SIZE); atl80->base.id = ZRTP_ATL_HS80; atl80->base.zrtp = global_ctx; atl80->tag_length = 10; zrtp_comp_register(ZRTP_CC_ATL, atl32, global_ctx); zrtp_comp_register(ZRTP_CC_ATL, atl80, global_ctx); return zrtp_status_ok; }
/*----------------------------------------------------------------------------*/ zrtp_status_t zrtp_down(zrtp_global_t* zrtp) { ZRTP_LOG(3, (_ZTU_,"DESTROYING LIBZRTP...\n")); if (!zrtp) { return zrtp_status_bad_param; } zrtp_comp_done(ZRTP_CC_HASH, zrtp); zrtp_comp_done(ZRTP_CC_SAS, zrtp); zrtp_comp_done(ZRTP_CC_CIPHER, zrtp); zrtp_comp_done(ZRTP_CC_PKT, zrtp); zrtp_comp_done(ZRTP_CC_ATL, zrtp); zrtp_done_pkt(zrtp); zrtp_mutex_destroy(zrtp->sessions_protector); zrtp_srtp_down(zrtp); if (zrtp->cb.cache_cb.on_down) { zrtp->cb.cache_cb.on_down(); } if (zrtp->cb.sched_cb.on_down) { zrtp->cb.sched_cb.on_down(); } zrtp_down_rng(zrtp); zrtp_sys_free(zrtp); ZRTP_LOG(3, (_ZTU_,"DESTROYING LIBZRTP - DONE\n")); return zrtp_status_ok; }
/*----------------------------------------------------------------------------*/ static void clear_crypto_sources(zrtp_stream_t* stream) { zrtp_protocol_t* proto = stream->protocol; if (proto && proto->cc) { zrtp_memset(proto->cc, 0, sizeof(zrtp_proto_crypto_t)); zrtp_sys_free(proto->cc); proto->cc = 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); }
void _zrtp_protocol_destroy(zrtp_protocol_t *proto) { /* Clear protocol crypto values, destroy SRTP unit, clear and release memory. */ if (proto) { /* if protocol is being destroyed by exception, ->context may be NULL */ if (proto->context) { _zrtp_cancel_send_packet_later(proto->context, ZRTP_NONE); if (proto->_srtp) { zrtp_srtp_destroy(proto->context->zrtp->srtp_global, proto->_srtp); } } clear_crypto_sources(proto->context); zrtp_memset(proto, 0, sizeof(zrtp_protocol_t)); zrtp_sys_free(proto); } }
void lbnMemFree(void *ptr, unsigned bytes) { lbnMemWipe(ptr, bytes); zrtp_sys_free(ptr); }
/*----------------------------------------------------------------------------*/ 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; }
/*---------------------------------------------------------------------------*/ 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_protocol_init(zrtp_stream_t *stream, uint8_t is_initiator, zrtp_protocol_t **protocol) { zrtp_protocol_t *new_proto = NULL; zrtp_status_t s = zrtp_status_ok; ZRTP_LOG(3,(_ZTU_,"\tInit %s Protocol ID=%u mode=%s...\n", is_initiator ? "INITIATOR's" : "RESPONDER's", stream->id, zrtp_log_mode2str(stream->mode))); /* Destroy previous protocol structure (Responder or Preshared) */ if (*protocol) { _zrtp_protocol_destroy(*protocol); *protocol = NULL; } /* Allocate memory for all branching structures */ do { new_proto = zrtp_sys_alloc(sizeof(zrtp_protocol_t)); if (!new_proto) { s = zrtp_status_alloc_fail; break; } zrtp_memset(new_proto, 0, sizeof(zrtp_protocol_t)); new_proto->cc = zrtp_sys_alloc(sizeof(zrtp_proto_crypto_t)); if (!new_proto->cc) { s = zrtp_status_alloc_fail; break; } zrtp_memset(new_proto->cc, 0, sizeof(zrtp_proto_crypto_t)); /* Create and Initialize DH crypto context (for DH streams only) */ if (ZRTP_IS_STREAM_DH(stream)) { if (stream->dh_cc.initialized_with != stream->pubkeyscheme->base.id) { stream->pubkeyscheme->initialize(stream->pubkeyscheme, &stream->dh_cc); stream->dh_cc.initialized_with = stream->pubkeyscheme->base.id; } } /* Initialize main structure at first: functions pointers and generate nonce */ new_proto->type = is_initiator ? ZRTP_STATEMACHINE_INITIATOR : ZRTP_STATEMACHINE_RESPONDER; new_proto->context = stream; /* Initialize protocol crypto context and prepare it for further usage */ ZSTR_SET_EMPTY(new_proto->cc->kdf_context); ZSTR_SET_EMPTY(new_proto->cc->s0); ZSTR_SET_EMPTY(new_proto->cc->mes_hash); ZSTR_SET_EMPTY(new_proto->cc->hv); ZSTR_SET_EMPTY(new_proto->cc->peer_hv); if (ZRTP_IS_STREAM_DH(stream)) { _attach_secret(stream->session, &new_proto->cc->rs1, stream->session->secrets.rs1, is_initiator); _attach_secret(stream->session, &new_proto->cc->rs2, stream->session->secrets.rs2, is_initiator); _attach_secret(stream->session, &new_proto->cc->auxs, stream->session->secrets.auxs, is_initiator); _attach_secret(stream->session, &new_proto->cc->pbxs, stream->session->secrets.pbxs, is_initiator); } s = zrtp_status_ok; *protocol = new_proto; } while (0); if (s != zrtp_status_ok) { ZRTP_LOG(1,(_ZTU_,"\tERROR! _zrtp_protocol_attach() with code %s.\n", zrtp_log_status2str(s))); if (new_proto && new_proto->cc) { zrtp_sys_free(new_proto->cc); } if (new_proto) { zrtp_sys_free(new_proto); } *protocol = NULL; } return s; }
/*---------------------------------------------------------------------------*/ 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; }
/*----------------------------------------------------------------------------*/ static void zrtp_log(uint8_t is_clean, const char *sender, uint32_t level, const char *format, va_list marker) { #if (defined(ZRTP_USE_STACK_MINIM) && (ZRTP_USE_STACK_MINIM == 1)) char *log_buffer = zrtp_sys_alloc(ZRTP_LOG_BUFFER_SIZE); #else char log_buffer[ZRTP_LOG_BUFFER_SIZE]; #endif char* sline = log_buffer; uint32_t offset = 0; int len = 0; if (!sline) { return; } if (!is_clean) { /* Print sender with left aligment */ uint32_t sender_len = strlen(sender); *sline++ = ' '; *sline++ = '['; if (sender_len <= ZRTP_LOG_SENDER_MAX_LEN) { while (sender_len < ZRTP_LOG_SENDER_MAX_LEN) { *sline++ = ' ', ++sender_len; } while (*sender) { *sline++ = *sender++; } } else { int i = 0; for (i=0; i<ZRTP_LOG_SENDER_MAX_LEN; ++i) { *sline++ = *sender++; } } *sline++ = ']'; *sline++ = ':'; offset += 3 + ZRTP_LOG_SENDER_MAX_LEN; *sline++ = ' '; offset += 1; } /* Print Message itself */ #if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE) # if (_MSC_VER >= 1400) && (ZRTP_PLATFORM != ZP_WINCE) len = _vsnprintf_s(sline, ZRTP_LOG_BUFFER_SIZE-offset-1, ZRTP_LOG_BUFFER_SIZE-offset-1, format, marker); # else len = _vsnprintf(sline, ZRTP_LOG_BUFFER_SIZE-offset, format, marker); # endif #elif (ZRTP_PLATFORM == ZP_WIN32_KERNEL) RtlStringCchVPrintfA(sline, ZRTP_LOG_BUFFER_SIZE-offset, format, marker); #elif (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_BSD) || (ZRTP_PLATFORM == ZP_ANDROID) len = vsnprintf(sline, ZRTP_LOG_BUFFER_SIZE-offset, format, marker); #elif (ZRTP_PLATFORM == ZP_SYMBIAN) len = vsprintf(sline, format, marker); #endif if ((len > 0) && log_writer) { (*log_writer)(level, log_buffer, len+offset, offset); } #if (defined(ZRTP_USE_STACK_MINIM) && (ZRTP_USE_STACK_MINIM == 1)) zrtp_sys_free(log_buffer); #endif }
zrtp_status_t zrtp_defaults_pkt(zrtp_global_t* zrtp) { zrtp_pk_scheme_t* presh = zrtp_sys_alloc(sizeof(zrtp_pk_scheme_t)); zrtp_pk_scheme_t* dh2048 = zrtp_sys_alloc(sizeof(zrtp_pk_scheme_t)); zrtp_pk_scheme_t* dh3072 = zrtp_sys_alloc(sizeof(zrtp_pk_scheme_t)); zrtp_pk_scheme_t* multi = zrtp_sys_alloc(sizeof(zrtp_pk_scheme_t)); uint8_t P_2048_data[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; uint8_t P_3072_data[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; if (!dh2048 || !dh3072 || !presh || !multi) { if (presh) { zrtp_sys_free(presh); } if (dh2048) { zrtp_sys_free(dh2048); } if (dh3072) { zrtp_sys_free(dh3072); } if (multi) { zrtp_sys_free(multi); } return zrtp_status_alloc_fail; } zrtp_memset(dh3072, 0, sizeof(zrtp_pk_scheme_t)); zrtp_memcpy(dh3072->base.type, ZRTP_DH3K, ZRTP_COMP_TYPE_SIZE); dh3072->base.id = ZRTP_PKTYPE_DH3072; dh3072->base.zrtp = zrtp; dh3072->sv_length = 256/8; dh3072->pv_length = 384; dh3072->base.init = zrtp_dh_init; dh3072->base.free = zrtp_dh_free; dh3072->initialize = zrtp_dh_initialize; dh3072->compute = zrtp_dh_compute; dh3072->validate = zrtp_dh_validate; dh3072->self_test = zrtp_dh_self_test; zrtp_memcpy(zrtp->P_3072_data, P_3072_data, sizeof(P_3072_data)); zrtp_comp_register(ZRTP_CC_PKT, dh3072, zrtp); zrtp_memset(dh2048, 0, sizeof(zrtp_pk_scheme_t)); zrtp_memcpy(dh2048->base.type, ZRTP_DH2K, ZRTP_COMP_TYPE_SIZE); dh2048->base.id = ZRTP_PKTYPE_DH2048; dh2048->base.zrtp = zrtp; dh2048->sv_length = 256/8; dh2048->pv_length = 256; dh2048->base.init = zrtp_dh_init; dh2048->base.free = zrtp_dh_free; dh2048->initialize = zrtp_dh_initialize; dh2048->compute = zrtp_dh_compute; dh2048->validate = zrtp_dh_validate; dh2048->self_test = zrtp_dh_self_test; zrtp_memcpy(zrtp->P_2048_data, P_2048_data, sizeof(P_2048_data)); zrtp_comp_register(ZRTP_CC_PKT, dh2048, zrtp); zrtp_memset(multi, 0, sizeof(zrtp_pk_scheme_t)); zrtp_memcpy(multi->base.type, ZRTP_MULT, ZRTP_COMP_TYPE_SIZE); multi->base.id = ZRTP_PKTYPE_MULT; zrtp_comp_register(ZRTP_CC_PKT, multi, zrtp); zrtp_memset(presh, 0, sizeof(zrtp_pk_scheme_t)); zrtp_memcpy(presh->base.type, ZRTP_PRESHARED, ZRTP_COMP_TYPE_SIZE); presh->base.id = ZRTP_PKTYPE_PRESH; zrtp_comp_register(ZRTP_CC_PKT, presh, zrtp); #if (defined(ZRTP_ENABLE_EC) && (ZRTP_ENABLE_EC == 1)) return zrtp_defaults_ec_pkt(zrtp); #else return zrtp_status_ok; #endif }
void *process_outgoing(void *param) #endif { unsigned packets_counter = 0; zrtp_endpoint_t *the_endpoint = (zrtp_endpoint_t *)param; while (the_endpoint->is_running) { zrtp_test_stream_t* stream = NULL; unsigned i; zrtp_status_t s = zrtp_status_fail; zrtp_test_packet_t* packet; zrtp_queue_elem_t* elem; char* word = NULL; zrtp_sleep(K_ZRTP_TEST_RTP_RATE); /* Get random channel to operate with and select random peer */ stream = get_stream_to_process_(the_endpoint); if (!stream) { continue; } elem = zrtp_sys_alloc(sizeof(zrtp_queue_elem_t)); if (!elem) { break; } packet = (zrtp_test_packet_t*) elem->data; packet->is_rtp = (packets_counter++ % 20); /* Every 20-th packet is RTCP */ /* * Construct RTP/RTCP Packet */ if (packet->is_rtp) { ZRTP_UNALIGNED(zrtp_rtp_hdr_t) *rtp_hdr = (zrtp_rtp_hdr_t*)packet->body; /* Fill RTP Header according to the specification */ zrtp_memset(rtp_hdr, 0, sizeof(zrtp_rtp_hdr_t)); rtp_hdr->version = 2; /* Current RTP version 2 */ rtp_hdr->pt = 0; /* PCMU padding type */ rtp_hdr->ssrc = zrtp_hton32(stream->id); /* Use stream Identifier as it's SSRC */ if (stream->seq >= 0xFFFF) { stream->seq = 0; } rtp_hdr->seq = zrtp_hton16(stream->seq++); rtp_hdr->ts = zrtp_hton32((uint32_t)(zrtp_time_now()/1000)); /* Get RTP body from PGP words lists */ word = (char*)(i ? hash_word_list_odd[packets_counter % 256] : hash_word_list_even[packets_counter % 256]); zrtp_memcpy(packet->body + sizeof(zrtp_rtp_hdr_t), word, (uint32_t)strlen(word)); packet->length = sizeof(zrtp_rtp_hdr_t) + (uint32_t)strlen(word); /* Process RTP media with libzrtp */ s = zrtp_process_rtp(stream->zrtp, packet->body, &packet->length); } else { ZRTP_UNALIGNED(zrtp_rtcp_hdr_t) *rtcp_hdr = (zrtp_rtcp_hdr_t*)packet->body; /* Fill RTCP Header according to the specification */ rtcp_hdr->rc = 0; rtcp_hdr->version = 2; rtcp_hdr->ssrc = stream->id; /* Get RTP body from PGP words lists. Put RTCP marker at the beginning */ zrtp_memcpy(packet->body + sizeof(zrtp_rtcp_hdr_t), "RTCP", 4); word = (char*)( i ? hash_word_list_odd[packets_counter % 256] : hash_word_list_even[packets_counter % 256]); zrtp_memcpy(packet->body + sizeof(zrtp_rtcp_hdr_t) + 4, word, (uint32_t)strlen(word)); packet->length = sizeof(zrtp_rtcp_hdr_t) + (uint32_t)strlen(word) + 4; /* RTCP packets sould be 32 byes aligned */ packet->length += (packet->length % 4) ? (4 - packet->length % 4) : 0; /* Process RTCP control with libzrtp */ s = zrtp_process_rtcp(stream->zrtp, packet->body, &packet->length); } elem->size = packet->length; /* Handle zrtp_process_xxx() instructions */ switch (s) { /* Put the packet to the queue ==> send packet to the other side pear */ case zrtp_status_ok: { ZRTP_LOG(3, (_ZTU_,"Outgoing: (%s) [%p:ssrc=%u] OK. <%s%s> encrypted %d bytes.\n", zrtp_log_state2str(stream->zrtp->state), stream->zrtp, stream->id, packet->is_rtp ? "" : "RTCP", word, packet->length)); zrtp_test_queue_push(stream->output, elem); } break; case zrtp_status_drop: { ZRTP_LOG(1, (_ZTU_,"Outgoing: (%s) [%p:ssrc=%u] DROPPED.\n", zrtp_log_state2str(stream->zrtp->state), stream->zrtp, stream->id)); } break; case zrtp_status_fail: { ZRTP_LOG(1, (_ZTU_,"Outgoing: (%s) [%p:ssrc=%u] ENCRYPT FAILED.\n", zrtp_log_state2str(stream->zrtp->state), stream->zrtp, stream->id)); } break; default: break; } if (zrtp_status_ok != s) { zrtp_sys_free(packet); } } #if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE) return 0; #else return NULL; #endif }
void *process_incoming(void *param) #endif { zrtp_endpoint_t *the_endpoint = (zrtp_endpoint_t *)param; while (the_endpoint->is_running) { zrtp_test_packet_t* packet = NULL; zrtp_queue_elem_t* elem = NULL; zrtp_status_t s = zrtp_status_fail; zrtp_test_stream_t *stream; int is_protocol = 0; // TODO: use peak to not to block processing if queue for this stream is empty elem = zrtp_test_queue_pop(the_endpoint->input_queue); if (!elem || elem->size <= 0) { if (elem) zrtp_sys_free(elem); break; } packet = (zrtp_test_packet_t*) elem->data; zrtp_test_id_t stream_id; { if (packet->is_rtp) { ZRTP_UNALIGNED(zrtp_rtp_hdr_t) *rtp_hdr = (zrtp_rtp_hdr_t*)packet->body; stream_id = zrtp_ntoh32(rtp_hdr->ssrc); /* remember, we use stream Id as it's RTP SSRC */ } else { ZRTP_UNALIGNED(zrtp_rtcp_hdr_t) *rtcp_hdr = (zrtp_rtcp_hdr_t*)packet->body; stream_id = zrtp_ntoh32(rtcp_hdr->ssrc); /* remember, we use stream Id as it's RTP SSRC */ } stream = zrtp_test_stream_by_peerid(stream_id); } /* * Process incoming packet by libzrtp. Is this a RTP media packet - copy it to the buffer * to print out later. */ if (packet->is_rtp) { s = zrtp_process_srtp(stream->zrtp, packet->body, &packet->length); } else { s = zrtp_process_srtcp(stream->zrtp, packet->body, &packet->length); } if (!is_protocol) { char *body; if (packet->is_rtp) { body = packet->body + sizeof(zrtp_rtp_hdr_t); body[packet->length - sizeof(zrtp_rtp_hdr_t)] = 0; } else { body = packet->body + sizeof(zrtp_rtcp_hdr_t); body[packet->length - sizeof(zrtp_rtcp_hdr_t)] = 0; } switch (s) { case zrtp_status_ok: { ZRTP_LOG(1, (_ZTU_,"Incoming: (%s) [%p:ssrc=%u] OK. <%s> decrypted %d bytes.\n", zrtp_log_state2str(stream->zrtp->state), stream->zrtp, stream->id, body, packet->length)); } break; case zrtp_status_drop: { ZRTP_LOG(1, (_ZTU_,"Incoming: (%s) [%p:ssrc=%u] DROPPED. <%s>\n", zrtp_log_state2str(stream->zrtp->state), stream->zrtp, stream->id, body)); } break; case zrtp_status_fail: { ZRTP_LOG(1, (_ZTU_,"Incoming: (%s) [%p:ssrc=%u] DECRYPT FAILED. <%s>\n", zrtp_log_state2str(stream->zrtp->state), stream->zrtp, stream->id, body)); } break; default: break; } } zrtp_sys_free(elem); /* * When zrtp_stream is in the pending clear state and other side wants to send plain * traffic. We have to call zrtp_clear_stream(). */ if (stream->zrtp->state == ZRTP_STATE_PENDINGCLEAR) { zrtp_stream_clear(stream->zrtp); } } #if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE) return 0; #else return NULL; #endif }