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_test_endpoint_create(zrtp_test_endpoint_cfg_t* cfg, const char *name, zrtp_test_id_t* id) { zrtp_status_t s; unsigned i; char cache_file_path[ZRTP_TEST_STR_LEN]; zrtp_endpoint_t *new_endpoint; if (g_test_endpoints_count >= K_ZRTP_TEST_MAX_ENDPOINTS) return zrtp_status_alloc_fail; new_endpoint = &g_test_endpoints[g_test_endpoints_count++]; zrtp_memset(new_endpoint, 0, sizeof(zrtp_endpoint_t)); /* Copy configuration, we will use it later to clean up after ourselves */ zrtp_memcpy(&new_endpoint->cfg, cfg, sizeof(zrtp_test_endpoint_cfg_t)); /* Remember endpoint name */ strcpy(new_endpoint->name, name); new_endpoint->id = g_endpoints_counter++; /* Adjust cache file path so each endpoint will use it's own file. */ sprintf(cache_file_path, "./%s_cache.dat", name); zrtp_zstrcpyc(ZSTR_GV(new_endpoint->cfg.zrtp.def_cache_path), cache_file_path); /* Initialize libzrtp engine for this endpoint */ s = zrtp_init(&new_endpoint->cfg.zrtp, &new_endpoint->zrtp); if (zrtp_status_ok == s) { *id = new_endpoint->id; /* Generate random ZID */ zrtp_randstr(new_endpoint->zrtp, new_endpoint->zid, sizeof(new_endpoint->zid)); } /* Create Input queue*/ s = zrtp_test_queue_create(&new_endpoint->input_queue); if (zrtp_status_ok != s) { return s; } /* Start processing loop */ new_endpoint->is_running = 1; for (i = 0; i<K_ZRTP_TEST_PROCESSORS_COUNT; i++) { if (0 != zrtp_thread_create(process_incoming, new_endpoint)) { return zrtp_status_fail; } if (cfg->generate_traffic) { if (0 != zrtp_thread_create(process_outgoing, new_endpoint)) { return zrtp_status_fail; } } } return s; }
static void init_random_map(uint8_t *map, int width, zrtp_global_t *zrtp) { int i; for(i=0; i<width; i++) { uint32_t rnd = 0; zrtp_randstr(zrtp, (uint8_t*)&rnd, sizeof(rnd)); if(rnd%10 < 5) { zrtp_bitmap_set_bit(map, i); } else { zrtp_bitmap_clear_bit(map, i); } } }
static zrtp_test_stream_t *get_stream_to_process_(zrtp_endpoint_t *endpoint) { zrtp_test_id_t all_streams[K_ZRTP_TEST_MAX_SESSIONS_PER_ENDPOINT*ZRTP_MAX_STREAMS_PER_SESSION]; unsigned streams_count = 0; unsigned i, j; for (i=0; i<endpoint->sessions_count; i++) { for (j=0; j<endpoint->sessions[i].streams_count; j++) { zrtp_test_stream_t *stream = &endpoint->sessions[i].streams[j]; if (stream->input && stream->output) all_streams[streams_count++] = stream->id; } } if (0 == streams_count) return NULL; zrtp_randstr(endpoint->zrtp, (unsigned char*)&i, sizeof(i)); j = (unsigned)i; j = j % streams_count; //printf("trace>>> CHOOSE stream Endpoint=%u IDX=%u ID=%u\n", endpoint->id, j, all_streams[j]); return zrtp_test_stream_by_id(all_streams[j]); }
/*----------------------------------------------------------------------------*/ 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_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; }
/*----------------------------------------------------------------------------*/ zrtp_status_t _zrtp_machine_create_confirm( zrtp_stream_t *stream, zrtp_packet_Confirm_t* confirm) { void* cipher_ctx = NULL; zrtp_status_t s = zrtp_status_fail; zrtp_session_t *session = stream->session; uint32_t verifiedflag = 0; /* hash + (padding + sig_len + flags) + ttl */ const uint8_t encrypted_body_size = ZRTP_MESSAGE_HASH_SIZE + (2 + 1 + 1) + 4; /* * Create the Confirm packet according to draft 6.7 * AES CFB vector at first, SIG length and flags octet and cache TTL at the end * This version doesn't support signatures so sig_length=0 */ if (ZRTP_CFBIV_SIZE != zrtp_randstr(session->zrtp, confirm->iv, ZRTP_CFBIV_SIZE)) { return zrtp_status_fail; } zrtp_memcpy(confirm->hash, stream->messages.h0.buffer, ZRTP_MESSAGE_HASH_SIZE); zrtp_cache_get_verified(session->zrtp->cache, ZSTR_GV(session->peer_zid), &verifiedflag); confirm->expired_interval = zrtp_hton32(session->profile.cache_ttl); confirm->flags = 0; confirm->flags |= session->profile.disclose_bit ? 0x01 : 0x00; confirm->flags |= session->profile.allowclear ? 0x02 : 0x00; confirm->flags |= verifiedflag ? 0x04 : 0x00; confirm->flags |= (ZRTP_MITM_MODE_REG_SERVER == stream->mitm_mode) ? 0x08 : 0x00; /* Then we need to encrypt Confirm before Hmac computing. Use AES CFB */ do { cipher_ctx = session->blockcipher->start( session->blockcipher, (uint8_t*)stream->cc.zrtp_key.buffer, NULL, ZRTP_CIPHER_MODE_CFB); if (!cipher_ctx) { break; } s = session->blockcipher->set_iv(session->blockcipher, cipher_ctx, (zrtp_v128_t*)confirm->iv); if (zrtp_status_ok != s) { break; } s = session->blockcipher->encrypt( session->blockcipher, cipher_ctx, (uint8_t*)&confirm->hash, encrypted_body_size ); } while(0); if (cipher_ctx) { session->blockcipher->stop(session->blockcipher, cipher_ctx); } if (zrtp_status_ok != s) { ZRTP_LOG(1,(_ZTU_,"ERROR! failed to encrypt Confirm. s=%d ID=%u\n", s, stream->id)); return s; } /* Compute Hmac over encrypted part of Confirm */ { zrtp_string128_t hmac = ZSTR_INIT_EMPTY(hmac); s = session->hash->hmac_c( session->hash, stream->cc.hmackey.buffer, stream->cc.hmackey.length, (const char*)&confirm->hash, encrypted_body_size, ZSTR_GV(hmac) ); if (zrtp_status_ok != s) { ZRTP_LOG(1,(_ZTU_,"ERROR! failed to compute Confirm hmac. s=%d ID=%u\n", s, stream->id)); return s; } zrtp_memcpy(confirm->hmac, hmac.buffer, ZRTP_HMAC_SIZE); { char buff[512]; ZRTP_LOG(3,(_ZTU_,"HMAC TRACE. COMPUTE.\n")); ZRTP_LOG(3,(_ZTU_,"\tcipher text:%s. size=%u\n", hex2str((const char*)&confirm->hash, encrypted_body_size, buff, sizeof(buff)), encrypted_body_size)); ZRTP_LOG(3,(_ZTU_,"\t key:%s.\n", hex2str(stream->cc.hmackey.buffer, stream->cc.hmackey.length, buff, sizeof(buff)))); ZRTP_LOG(3,(_ZTU_,"\t comp hmac:%s.\n", hex2str(hmac.buffer, hmac.length, buff, sizeof(buff)))); ZRTP_LOG(3,(_ZTU_,"\t hmac:%s.\n", hex2str((const char*)confirm->hmac, ZRTP_HMAC_SIZE, buff, sizeof(buff)))); } } return zrtp_status_ok; }