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_test_session_create(zrtp_test_id_t endpoint_id, zrtp_test_session_cfg_t* cfg, zrtp_test_id_t* id) { zrtp_status_t s; unsigned i; zrtp_test_session_t *the_session; zrtp_endpoint_t *the_endpoint = zrtp_test_endpoint_by_id(endpoint_id); if (!the_endpoint) return zrtp_status_fail; if (the_endpoint->sessions_count >= K_ZRTP_TEST_MAX_SESSIONS_PER_ENDPOINT) return zrtp_status_fail; the_session = &the_endpoint->sessions[the_endpoint->sessions_count++]; zrtp_memset(the_session, 0, sizeof(zrtp_test_session_t)); zrtp_memcpy(&the_session->cfg, cfg, sizeof(zrtp_test_session_cfg_t)); the_session->id = g_sessions_counter++; the_session->endpoint_id = endpoint_id; s = zrtp_session_init(the_endpoint->zrtp, &cfg->zrtp, the_endpoint->zid, cfg->role, &the_session->zrtp); if (zrtp_status_ok == s) { zrtp_session_set_userdata(the_session->zrtp, &the_session->id); for (i=0; i<cfg->streams_count; i++) { zrtp_test_stream_t *the_stream = &the_session->streams[i]; zrtp_memset(the_stream, 0, sizeof(zrtp_test_stream_t)); the_stream->id = g_streams_counter++; the_stream->session_id = the_session->id; the_stream->endpoint_id = endpoint_id; s = zrtp_stream_attach(the_session->zrtp, &the_stream->zrtp); if (zrtp_status_ok == s) { zrtp_stream_set_userdata(the_stream->zrtp, &the_stream->id); the_session->streams_count++; } else { break; } } } if (zrtp_status_ok == s) { *id = the_session->id; } return s; }
zrtp_status_t zrtp_test_channel_create(zrtp_test_id_t left_id, zrtp_test_id_t right_id, zrtp_test_id_t* id) { zrtp_test_channel_t *the_channel; zrtp_test_stream_t *left = zrtp_test_stream_by_id(left_id); zrtp_test_stream_t *right = zrtp_test_stream_by_id(right_id); if (!left || !right) return zrtp_status_bad_param; if (g_test_channels_count >= K_ZRTP_TEST_MAX_CHANNELS) return zrtp_status_bad_param; zrtp_endpoint_t *left_endpoint = zrtp_test_endpoint_by_id(left->endpoint_id); zrtp_endpoint_t *right_endpoint = zrtp_test_endpoint_by_id(right->endpoint_id); the_channel = &g_test_channels[g_test_channels_count++]; zrtp_memset(the_channel, 0, sizeof(zrtp_test_channel_t)); the_channel->id = g_channels_counter++; the_channel->left = left; the_channel->right = right; left->output = right_endpoint->input_queue; left->input = left_endpoint->input_queue; right->output = left_endpoint->input_queue; right->input = right_endpoint->input_queue; right->channel_id = the_channel->id; left->channel_id = the_channel->id; the_channel->is_attached = 1; *id = the_channel->id; return zrtp_status_ok; }
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 }
/*----------------------------------------------------------------------------*/ void zrtp_profile_defaults(zrtp_profile_t* profile, zrtp_global_t* zrtp) { zrtp_memset(profile, 0, sizeof(zrtp_profile_t)); profile->autosecure = 1; profile->allowclear = 0; profile->discovery_optimization = 1; profile->cache_ttl = ZRTP_CACHE_DEFAULT_TTL; profile->sas_schemes[0] = ZRTP_SAS_BASE256; profile->sas_schemes[1] = ZRTP_SAS_BASE32; profile->cipher_types[0] = ZRTP_CIPHER_AES256; profile->cipher_types[1] = ZRTP_CIPHER_AES128; profile->auth_tag_lens[0] = ZRTP_ATL_HS32; profile->hash_schemes[0] = ZRTP_HASH_SHA256; if (zrtp && (ZRTP_LICENSE_MODE_PASSIVE == zrtp->lic_mode)) { profile->pk_schemes[0] = ZRTP_PKTYPE_DH2048; profile->pk_schemes[1] = ZRTP_PKTYPE_EC256P; profile->pk_schemes[2] = ZRTP_PKTYPE_DH3072; } else { profile->pk_schemes[0] = ZRTP_PKTYPE_EC256P; profile->pk_schemes[1] = ZRTP_PKTYPE_DH3072; profile->pk_schemes[2] = ZRTP_PKTYPE_DH2048; } profile->pk_schemes[3] = ZRTP_PKTYPE_MULT; }
void zrtp_wipe_zstring(zrtp_stringn_t *zstr) { if (zstr && zstr->length) { zrtp_memset(zstr->buffer, 0, zstr->max_length); zstr->length = 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; }
zrtp_status_t zrtp_test_endpoint_create(zrtp_test_endpoint_cfg_t* cfg, const char *name, zrtp_test_id_t* id) { zrtp_status_t s; unsigned i; char cache_file_path[ZRTP_TEST_STR_LEN]; zrtp_endpoint_t *new_endpoint; if (g_test_endpoints_count >= K_ZRTP_TEST_MAX_ENDPOINTS) return zrtp_status_alloc_fail; new_endpoint = &g_test_endpoints[g_test_endpoints_count++]; zrtp_memset(new_endpoint, 0, sizeof(zrtp_endpoint_t)); /* Copy configuration, we will use it later to clean up after ourselves */ zrtp_memcpy(&new_endpoint->cfg, cfg, sizeof(zrtp_test_endpoint_cfg_t)); /* Remember endpoint name */ strcpy(new_endpoint->name, name); new_endpoint->id = g_endpoints_counter++; /* Adjust cache file path so each endpoint will use it's own file. */ sprintf(cache_file_path, "./%s_cache.dat", name); zrtp_zstrcpyc(ZSTR_GV(new_endpoint->cfg.zrtp.def_cache_path), cache_file_path); /* Initialize libzrtp engine for this endpoint */ s = zrtp_init(&new_endpoint->cfg.zrtp, &new_endpoint->zrtp); if (zrtp_status_ok == s) { *id = new_endpoint->id; /* Generate random ZID */ zrtp_randstr(new_endpoint->zrtp, new_endpoint->zid, sizeof(new_endpoint->zid)); } /* Create Input queue*/ s = zrtp_test_queue_create(&new_endpoint->input_queue); if (zrtp_status_ok != s) { return s; } /* Start processing loop */ new_endpoint->is_running = 1; for (i = 0; i<K_ZRTP_TEST_PROCESSORS_COUNT; i++) { if (0 != zrtp_thread_create(process_incoming, new_endpoint)) { return zrtp_status_fail; } if (cfg->generate_traffic) { if (0 != zrtp_thread_create(process_outgoing, new_endpoint)) { return zrtp_status_fail; } } } return s; }
/*----------------------------------------------------------------------------*/ static void 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; } }
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; }
zrtp_status_t zrtp_test_stream_get(zrtp_test_id_t id, zrtp_test_stream_info_t* info) { zrtp_test_stream_t *stream = zrtp_test_stream_by_id(id); if (stream) { zrtp_status_t s; zrtp_memset(info, 0, sizeof(zrtp_test_stream_info_t)); zrtp_memcpy(info->zrtp_events_queueu, stream->zrtp_events_queueu, sizeof(info->zrtp_events_queueu)); info->zrtp_events_count = stream->zrtp_events_count; s = zrtp_stream_get(stream->zrtp, &info->zrtp); return s; } else { return zrtp_status_bad_param; } }
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 zrtp_test_endpoint_config_defaults(zrtp_test_endpoint_cfg_t* cfg) { zrtp_memset(cfg, 0, sizeof(zrtp_test_endpoint_cfg_t)); cfg->generate_traffic = 0; /* It's always a good idea to start with default values */ zrtp_config_defaults(&cfg->zrtp); /* Set ZRTP client id */ strcpy(cfg->zrtp.client_id, "zrtp-test-engine"); cfg->zrtp.is_mitm = 0; cfg->zrtp.lic_mode = ZRTP_LICENSE_MODE_ACTIVE; cfg->zrtp.cb.event_cb.on_zrtp_secure = &on_zrtp_secure; cfg->zrtp.cb.event_cb.on_zrtp_security_event = &on_zrtp_event; cfg->zrtp.cb.event_cb.on_zrtp_protocol_event = &on_zrtp_event; cfg->zrtp.cb.misc_cb.on_send_packet = &on_send_packet; }
zrtp_status_t zrtp_test_channel_get(zrtp_test_id_t id, zrtp_test_channel_info_t* info) { zrtp_test_channel_t *channel = zrtp_test_channel_by_id(id); if (channel) { zrtp_status_t s; zrtp_memset(info, 0, sizeof(zrtp_test_channel_info_t)); s = zrtp_test_stream_get(channel->left->id, &info->left); if (zrtp_status_ok == s) { s = zrtp_test_stream_get(channel->right->id, &info->right); if (zrtp_status_ok == s) { info->is_secure = channel->is_secure; } } return s; } else { return zrtp_status_bad_param; } }
zrtp_status_t zrtp_stream_get(zrtp_stream_t *stream, zrtp_stream_info_t *info) { if (!stream || !info) { return zrtp_status_bad_param; } zrtp_memset(info, 0, sizeof(zrtp_stream_info_t)); info->id = stream->id; info->state = stream->state; info->mode = stream->mode; info->mitm_mode = stream->mitm_mode; if (stream->state > ZRTP_STATE_ACTIVE) { info->last_error = stream->last_error; info->peer_passive = stream->peer_passive; info->res_allowclear= stream->allowclear; info->peer_disclose = stream->peer_disclose_bit; info->peer_mitm = stream->peer_mitm_flag; } return zrtp_status_ok; }
/*----------------------------------------------------------------------------*/ int zrtp_add_system_state(zrtp_global_t* zrtp, MD_CTX *ctx) { uint8_t buffer[64]; size_t bytes_read = 0; static size_t length= sizeof(buffer); FILE *fp = NULL; fp = fopen("/dev/urandom", "rb"); if (!fp) { ZRTP_LOG(1,(_ZTU_,"\tERROR! can't get access to /dev/urandom - trying /dev/random.\n")); fp = fopen("/dev/random", "rb"); } if (fp) { int number_of_retries = 1024; while ((bytes_read < length) && (number_of_retries-- > 0)) { setbuf(fp, NULL); /* Otherwise fread() tries to read() 4096 bytes or other default value */ bytes_read += fread(buffer+bytes_read, 1, length-bytes_read, fp); } if (0 != fclose(fp)) { ZRTP_LOG(1,(_ZTU_,"\tERROR! unable to cloas /dev/random\n")); } } else { ZRTP_LOG(1,(_ZTU_,"\tERROR! RNG Can't open /dev/random\n")); } if (bytes_read < length) { ZRTP_LOG(1,(_ZTU_,"\tERROR! can't read random string! Current session have to be closed.\n")); return -1; } MD_Update(ctx, buffer, length); zrtp_memset(buffer, 0, sizeof(buffer)); return bytes_read; }
/*----------------------------------------------------------------------------*/ zrtp_status_t _zrtp_machine_process_sasrelay(zrtp_stream_t *stream, zrtp_rtp_info_t *packet) { zrtp_session_t *session = stream->session; zrtp_packet_SASRelay_t *sasrelay = (zrtp_packet_SASRelay_t*) packet->message; void* cipher_ctx = NULL; zrtp_sas_id_t rendering_id = ZRTP_COMP_UNKN; zrtp_status_t s = zrtp_status_fail; zrtp_string128_t hmac = ZSTR_INIT_EMPTY(hmac); char zerosashash[32]; unsigned sas_scheme_did_change = 0; unsigned sas_hash_did_change = 0; /* (padding + sig_len + flags) + SAS scheme and SAS hash */ const uint8_t encrypted_body_size = (2 + 1 + 1) + 4 + 32; zrtp_memset(zerosashash, 0, sizeof(zerosashash)); /* Check if the remote endpoint is assigned to relay the SAS values */ if (!stream->peer_mitm_flag) { ZRTP_LOG(2,(_ZTU_, ZRTP_RELAYED_SAS_FROM_NONMITM_STR)); return zrtp_status_fail; } /* Check the HMAC */ s = session->hash->hmac_c( session->hash, stream->cc.peer_hmackey.buffer, stream->cc.peer_hmackey.length, (const char*)&sasrelay->pad, encrypted_body_size, ZSTR_GV(hmac) ); if (zrtp_status_ok != s ) { ZRTP_LOG(1,(_ZTU_,"\tERROR! Failed to compute CONFIRM hmac. status=%d ID=%u\n", s, stream->id)); return zrtp_status_fail; } if (0 != zrtp_memcmp(sasrelay->hmac, hmac.buffer, ZRTP_HMAC_SIZE)) { ZRTP_LOG(2,(_ZTU_, ZRTP_VERIFIED_RESP_WARNING_STR)); return zrtp_status_fail; } ZRTP_LOG(3,(_ZTU_, "\tHMAC value for the SASRELAY is correct - decrypting...\n")); /* Then we need to decrypt Confirm body */ do { cipher_ctx = session->blockcipher->start( session->blockcipher, (uint8_t*)stream->cc.peer_zrtp_key.buffer, NULL, ZRTP_CIPHER_MODE_CFB ); if (!cipher_ctx) { break; } s = session->blockcipher->set_iv(session->blockcipher, cipher_ctx, (zrtp_v128_t*)sasrelay->iv); if (zrtp_status_ok != s) { break; } s = session->blockcipher->encrypt( session->blockcipher, cipher_ctx, (uint8_t*)&sasrelay->pad, encrypted_body_size); } while(0); if (cipher_ctx) { session->blockcipher->stop(session->blockcipher, cipher_ctx); } if (zrtp_status_ok != s) { ZRTP_LOG(1,(_ZTU_,"\tERROR! Failed to decrypt Confirm. status=%d ID=%u\n", s, stream->id)); return s; } ZRTP_LOG(2,(_ZTU_,"\tSasRelay FLAGS old/new A=%d/%d, D=%d/%d.\n", stream->allowclear, (uint8_t)(sasrelay->flags & 0x02), stream->peer_disclose_bit, (uint8_t)(sasrelay->flags & 0x01))); /* Set evil bit if other-side disclosed session key */ stream->peer_disclose_bit = (sasrelay->flags & 0x01); /* Enable ALLOWCLEAR option only if both sides support it */ stream->allowclear = (sasrelay->flags & 0x02) && session->profile.allowclear; /* * We don't handle verified flag in SASRelaying because it makes no * sense in implementation of the ZRTP Internet Draft. */ /* * Only enrolled users can do SAS transferring. (Non-enrolled users can * only change the SAS rendering scheme). */ rendering_id = zrtp_comp_type2id(ZRTP_CC_SAS, (char*)sasrelay->sas_scheme); if (-1 == zrtp_profile_find(&session->profile, ZRTP_CC_SAS, rendering_id)) { ZRTP_LOG(1,(_ZTU_,"\tERROR! PBX Confirm packet with transferred SAS have unknown or" " unsupported rendering scheme %.4s.ID=%u\n", sasrelay->sas_scheme, stream->id)); _zrtp_machine_enter_initiatingerror(stream, zrtp_error_invalid_packet, 1); return zrtp_status_fail; } /* Check is SAS rendering did change */ if (rendering_id != session->sasscheme->base.id) { session->sasscheme = zrtp_comp_find(ZRTP_CC_SAS, rendering_id, session->zrtp ); sas_scheme_did_change = 1; ZRTP_LOG(3,(_ZTU_,"\tSasrelay: Rendering scheme was updated to %.4s.\n", session->sasscheme->base.type)); } if (session->secrets.matches & ZRTP_BIT_PBX) { if ( ( ((uint32_t) *sasrelay->sas_scheme) != (uint32_t)0x0L ) && (0 != zrtp_memcmp(sasrelay->sashash, zerosashash, sizeof(sasrelay->sashash))) ) { char buff[256]; session->sasbin.length = ZRTP_MITM_SAS_SIZE; /* First 32 bits if sashash includes sasvalue */ zrtp_memcpy(session->sasbin.buffer, sasrelay->sashash, session->sasbin.length); stream->mitm_mode = ZRTP_MITM_MODE_RECONFIRM_CLIENT; sas_hash_did_change = 1; ZRTP_LOG(3,(_ZTU_,"\tSasRelay: SAS value was updated to bin=%s.\n", hex2str(buff, sizeof(buff), session->sasbin.buffer, session->sasbin.length))); } } else if (0 != zrtp_memcmp(sasrelay->sashash, zerosashash, sizeof(sasrelay->sashash))) { ZRTP_LOG(1,(_ZTU_,"\tWARNING! SAS Value was received from NOT Trusted MiTM. ID=%u\n", stream->id)); _zrtp_machine_enter_initiatingerror(stream, zrtp_error_possible_mitm3, 1); return zrtp_status_fail; } else { ZRTP_LOG(1,(_ZTU_, "\rERROR! For SasRelay Other secret doesn't match. ID=%u\n", stream->id)); } /* Generate new SAS if hash or rendering scheme did change. * Note: latest libzrtp may send "empty" SasRelay with the same SAS rendering * scheme and empty Hello hash for consistency reasons, we should ignore * such packets. */ if (sas_scheme_did_change || sas_hash_did_change) { s = session->sasscheme->compute(session->sasscheme, stream, session->hash, 1); if (zrtp_status_ok != s) { _zrtp_machine_enter_initiatingerror(stream, zrtp_error_software, 1); return s; } ZRTP_LOG(3,(_ZTU_,"\tSasRelay: Updated SAS is <%s> <%s>.\n", session->sas1.buffer, session->sas2.buffer)); if (session->zrtp->cb.event_cb.on_zrtp_protocol_event) { session->zrtp->cb.event_cb.on_zrtp_protocol_event(stream, ZRTP_EVENT_LOCAL_SAS_UPDATED); } } return zrtp_status_ok; }
zrtp_status_t zrtp_session_get(zrtp_session_t *session, zrtp_session_info_t *info) { int i=0; if (!session || !info) { return zrtp_status_bad_param; } zrtp_memset(info, 0, sizeof(zrtp_session_info_t)); ZSTR_SET_EMPTY(info->peer_clientid); ZSTR_SET_EMPTY(info->peer_version); ZSTR_SET_EMPTY(info->zid); ZSTR_SET_EMPTY(info->peer_zid); ZSTR_SET_EMPTY(info->sas1); ZSTR_SET_EMPTY(info->sasbin); ZSTR_SET_EMPTY(info->sas2); ZSTR_SET_EMPTY(info->auth_name); ZSTR_SET_EMPTY(info->cipher_name); ZSTR_SET_EMPTY(info->hash_name); ZSTR_SET_EMPTY(info->sas_name); ZSTR_SET_EMPTY(info->pk_name); info->id = session->id; zrtp_zstrcpy(ZSTR_GV(info->zid), ZSTR_GV(session->zid)); zrtp_zstrcpy(ZSTR_GV(info->peer_zid), ZSTR_GV(session->peer_zid)); for (i=0; i<ZRTP_MAX_STREAMS_PER_SESSION; i++) { zrtp_stream_t* full_stream = &session->streams[i]; if ((full_stream->state > ZRTP_STATE_ACTIVE) && !ZRTP_IS_STREAM_FAST(full_stream)) { zrtp_zstrcpyc(ZSTR_GV(info->pk_name), zrtp_pkt2str[full_stream->pubkeyscheme->base.id-1]); zrtp_zstrncpyc( ZSTR_GV(info->peer_clientid), (const char*)full_stream->messages.peer_hello.cliend_id, 16); zrtp_zstrncpyc( ZSTR_GV(info->peer_version), (const char*)full_stream->messages.peer_hello.version, 4); info->secrets_ttl = full_stream->cache_ttl; } } info->sas_is_ready = (session->zrtpsess.length > 0) ? 1 : 0; if (info->sas_is_ready) { zrtp_zstrcpy(ZSTR_GV(info->sas1), ZSTR_GV(session->sas1)); zrtp_zstrcpy(ZSTR_GV(info->sas2), ZSTR_GV(session->sas2)); zrtp_zstrcpy(ZSTR_GV(info->sasbin), ZSTR_GV(session->sasbin)); info->sas_is_base256 = (ZRTP_SAS_BASE256 == session->sasscheme->base.id); info->sas_is_verified = 0; if (session->zrtp->cb.cache_cb.on_get_verified) { session->zrtp->cb.cache_cb.on_get_verified( ZSTR_GV(session->zid), ZSTR_GV(session->peer_zid), &info->sas_is_verified); } zrtp_zstrcpyc(ZSTR_GV(info->hash_name), zrtp_hash2str[session->hash->base.id-1]); zrtp_zstrcpyc(ZSTR_GV(info->cipher_name), zrtp_cipher2str[session->blockcipher->base.id-1]); zrtp_zstrcpyc(ZSTR_GV(info->auth_name), zrtp_atl2str[session->authtaglength->base.id-1]); zrtp_zstrcpyc(ZSTR_GV(info->sas_name), zrtp_sas2str[session->sasscheme->base.id-1]); info->cached_flags = session->secrets.cached_curr; info->matches_flags= session->secrets.matches_curr; info->wrongs_flags = session->secrets.wrongs_curr; } return zrtp_status_ok; }
zrtp_status_t zrtp_init(zrtp_config_t* config, zrtp_global_t** zrtp) { zrtp_global_t* new_zrtp; zrtp_status_t s = zrtp_status_ok; ZRTP_LOG(3, (_ZTU_,"INITIALIZING LIBZRTP...\n")); /* Print out configuration setting */ zrtp_print_env_settings(config); new_zrtp = zrtp_sys_alloc(sizeof(zrtp_global_t)); if (!new_zrtp) { return zrtp_status_alloc_fail; } zrtp_memset(new_zrtp, 0, sizeof(zrtp_global_t)); /* * Apply configuration according to the config */ new_zrtp->lic_mode = config->lic_mode; new_zrtp->is_mitm = config->is_mitm; ZSTR_SET_EMPTY(new_zrtp->def_cache_path); zrtp_zstrcpy(ZSTR_GV(new_zrtp->def_cache_path), ZSTR_GV(config->def_cache_path)); zrtp_memcpy(&new_zrtp->cb, &config->cb, sizeof(zrtp_callback_t)); new_zrtp->cache_auto_store = config->cache_auto_store; ZSTR_SET_EMPTY(new_zrtp->client_id); zrtp_memset(new_zrtp->client_id.buffer, ' ', sizeof(zrtp_client_id_t)); zrtp_zstrncpyc( ZSTR_GV(new_zrtp->client_id), (const char*)config->client_id, sizeof(zrtp_client_id_t)); /* * General Initialization */ init_mlist(&new_zrtp->sessions_head); zrtp_mutex_init(&new_zrtp->sessions_protector); init_mlist(&new_zrtp->hash_head); init_mlist(&new_zrtp->cipher_head); init_mlist(&new_zrtp->atl_head); init_mlist(&new_zrtp->pktype_head); init_mlist(&new_zrtp->sas_head); /* Init RNG context */ s = zrtp_init_rng(new_zrtp); if (zrtp_status_ok != s) { ZRTP_LOG(1, (_ZTU_,"ERROR! zrtp_init_rng() failed:%s.\n", zrtp_log_status2str(s))); return zrtp_status_rng_fail; } /* Initialize SRTP engine */ s = zrtp_srtp_init(new_zrtp); if (zrtp_status_ok != s) { ZRTP_LOG(1, (_ZTU_,"ERROR! zrtp_srtp_init() failed:<%s>\n", zrtp_log_status2str(s))); return zrtp_status_fail; } if (new_zrtp->cb.cache_cb.on_init) { s = new_zrtp->cb.cache_cb.on_init(new_zrtp); if (zrtp_status_ok != s) { ZRTP_LOG(1, (_ZTU_,"ERROR! cache on_init() callback failed <%s>\n", zrtp_log_status2str(s))); zrtp_srtp_down(new_zrtp); return zrtp_status_fail; } } if (new_zrtp->cb.sched_cb.on_init) { s = new_zrtp->cb.sched_cb.on_init(new_zrtp); if (zrtp_status_ok != s) { ZRTP_LOG(1, (_ZTU_,"ERROR! scheduler on_init() callback failed <%s>\n", zrtp_log_status2str(s))); zrtp_srtp_down(new_zrtp); return zrtp_status_fail; } } /* Load default crypto-components */ zrtp_prepare_pkt(new_zrtp); zrtp_defaults_sas(new_zrtp); zrtp_defaults_pkt(new_zrtp); zrtp_defaults_atl(new_zrtp); zrtp_defaults_aes_cipher(new_zrtp); zrtp_defaults_hash(new_zrtp); *zrtp = new_zrtp; ZRTP_LOG(3, (_ZTU_,"INITIALIZING LIBZRTP - DONE\n")); return s; }
/*----------------------------------------------------------------------------*/ 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; }
/*----------------------------------------------------------------------------*/ static zrtp_status_t _create_sasrelay( zrtp_stream_t *stream, zrtp_sas_id_t transf_sas_scheme, zrtp_string32_t* transf_sas_value, uint8_t transf_ac_flag, uint8_t transf_d_flag, zrtp_packet_SASRelay_t* sasrelay ) { zrtp_session_t *session = stream->session; zrtp_status_t s = zrtp_status_fail; void* cipher_ctx = NULL; /* (padding + sig_len + flags) + SAS scheme and SASHash */ const uint8_t encrypted_body_size = (2 + 1 + 1) + 4 + 32; zrtp_memset(sasrelay, 0, sizeof(zrtp_packet_SASRelay_t)); /* generate a random initialization vector for CFB cipher */ if (ZRTP_CFBIV_SIZE != zrtp_randstr(session->zrtp, sasrelay->iv, ZRTP_CFBIV_SIZE)) { return zrtp_status_rp_fail; } sasrelay->flags |= (session->profile.disclose_bit || transf_d_flag) ? 0x01 : 0x00; sasrelay->flags |= (session->profile.allowclear && transf_ac_flag) ? 0x02 : 0x00; sasrelay->flags |= 0x04; zrtp_memcpy( sasrelay->sas_scheme, zrtp_comp_id2type(ZRTP_CC_SAS, transf_sas_scheme), ZRTP_COMP_TYPE_SIZE ); if (transf_sas_value) zrtp_memcpy(sasrelay->sashash, transf_sas_value->buffer, transf_sas_value->length); /* Then we need to encrypt Confirm before computing Hmac. Use AES CFB */ do { cipher_ctx = session->blockcipher->start( session->blockcipher, (uint8_t*)stream->cc.zrtp_key.buffer, NULL, ZRTP_CIPHER_MODE_CFB ); if (!cipher_ctx) { break; } s = session->blockcipher->set_iv( session->blockcipher, cipher_ctx, (zrtp_v128_t*)sasrelay->iv); if (zrtp_status_ok != s) { break; } s = session->blockcipher->encrypt( session->blockcipher, cipher_ctx, (uint8_t*)&sasrelay->pad, encrypted_body_size ); } while(0); if (cipher_ctx) { session->blockcipher->stop(session->blockcipher, cipher_ctx); } if (zrtp_status_ok != s) { ZRTP_LOG(1,(_ZTU_,"\tERROR! Failed to encrypt SASRELAY Message status=%d. ID=%u\n", s, stream->id)); return s; } /* Compute Hmac over encrypted part of Confirm */ { zrtp_string128_t hmac = ZSTR_INIT_EMPTY(hmac); s = session->hash->hmac_c( session->hash, stream->cc.hmackey.buffer, stream->cc.hmackey.length, (const char*)&sasrelay->pad, encrypted_body_size, ZSTR_GV(hmac) ); if (zrtp_status_ok != s) { ZRTP_LOG(1,(_ZTU_,"\tERROR! Failed to compute CONFIRM hmac status=%d. ID=%u\n", s, stream->id)); return s; } zrtp_memcpy(sasrelay->hmac, hmac.buffer, ZRTP_HMAC_SIZE); } return s; }
zrtp_status_t zrtp_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 lbnMemWipe(void *ptr, unsigned bytes) { zrtp_memset(ptr, 0, bytes); }
/*----------------------------------------------------------------------------*/ 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; }
/*----------------------------------------------------------------------------*/ int zrtp_randstr(zrtp_global_t* zrtp, unsigned char *buffer, uint32_t length) { //TODO: replace bg_aes_xxx() with our own block cipher component. //TODO: Do the same with the hash functions. aes_encrypt_ctx aes_ctx; MD_CTX rand_ctx2; unsigned char md[MD_DIGEST_LENGTH]; unsigned char ctr[AES_BLOCK_SIZE]; unsigned char rdata[AES_BLOCK_SIZE]; uint32_t generated = length; /* * In few cases we need to gerate random value before initializing libzrtp engine. * Following trick makes it possible. */ if (!zrtp->rand_initialized) { if (zrtp_status_ok != zrtp_init_rng(zrtp)) { return -1; } } zrtp_mutex_lock(zrtp->rng_protector); /* * Add entropy from system state * We will include whatever happens to be in the buffer, it can't hurt */ if ( 0 > zrtp_entropy_add(zrtp, buffer, length) ) { zrtp_mutex_unlock(zrtp->rng_protector); return -1; } /* Copy the zrtp->rand_ctx and finalize it into the md buffer */ rand_ctx2 = zrtp->rand_ctx; MD_Final(&rand_ctx2, md); zrtp_mutex_unlock(zrtp->rng_protector); /* Key an AES context from this buffer */ zrtp_bg_aes_encrypt_key256(md, &aes_ctx); /* Initialize counter, using excess from md if available */ zrtp_memset (ctr, 0, sizeof(ctr)); if (MD_DIGEST_LENGTH > (256/8)) { uint32_t ctrbytes = MD_DIGEST_LENGTH - (256/8); if (ctrbytes > AES_BLOCK_SIZE) ctrbytes = AES_BLOCK_SIZE; zrtp_memcpy(ctr + sizeof(ctr) - ctrbytes, md + (256/8), ctrbytes); } /* Encrypt counter, copy to destination buffer, increment counter */ while (length) { unsigned char *ctrptr; uint32_t copied; zrtp_bg_aes_encrypt(ctr, rdata, &aes_ctx); copied = (sizeof(rdata) < length) ? sizeof(rdata) : length; zrtp_memcpy (buffer, rdata, copied); buffer += copied; length -= copied; /* Increment counter */ ctrptr = ctr + sizeof(ctr) - 1; while (ctrptr >= ctr) { if ((*ctrptr-- += 1) != 0) { break; } } } /* Done! Cleanup and exit */ MD_Cleanup (&rand_ctx2); MD_Cleanup (md); MD_Cleanup (&aes_ctx); MD_Cleanup (ctr); MD_Cleanup (rdata); return generated; }
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; }
/*----------------------------------------------------------------------------*/ 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; }
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 }