/*----------------------------------------------------------------------------*/ zrtp_status_t _zrtp_protocol_decrypt( zrtp_protocol_t *proto, zrtp_rtp_info_t *packet, uint8_t is_rtp) { zrtp_status_t s = zrtp_status_ok; if (is_rtp) { s = zrtp_srtp_unprotect(proto->context->zrtp->srtp_global, proto->_srtp, packet); } else { s = zrtp_srtp_unprotect_rtcp(proto->context->zrtp->srtp_global, proto->_srtp, packet); } if (zrtp_status_ok != s) { ZRTP_UNALIGNED(zrtp_rtp_hdr_t) *hdr = (zrtp_rtp_hdr_t*) packet->packet; ZRTP_LOG(2,(_ZTU_,"ERROR! Decrypt failed. ID=%u:%s s=%s (%s size=%d ssrc=%u seq=%u/%u pt=%d)\n", proto->context->id, zrtp_log_mode2str(proto->context->mode), zrtp_log_status2str(s), is_rtp ? "RTP" : "RTCP", *packet->length, zrtp_ntoh32(hdr->ssrc), zrtp_ntoh16(hdr->seq), packet->seq, hdr->pt)); } return s; }
/*----------------------------------------------------------------------------*/ zrtp_status_t _zrtp_machine_process_confirm( zrtp_stream_t *stream, zrtp_packet_Confirm_t *confirm) { /* Compute Hmac over encrypted part of Confirm and reject malformed packets */ void* cipher_ctx = NULL; zrtp_status_t s = zrtp_status_fail; zrtp_session_t *session = stream->session; zrtp_string128_t hmac = ZSTR_INIT_EMPTY(hmac); /* hash + (padding + sig_len + flags) + ttl */ const uint8_t encrypted_body_size = ZRTP_MESSAGE_HASH_SIZE + (2 + 1 + 1) + 4; s = session->hash->hmac_c( session->hash, stream->cc.peer_hmackey.buffer, stream->cc.peer_hmackey.length, (const char*)&confirm->hash, encrypted_body_size, ZSTR_GV(hmac) ); if (zrtp_status_ok != s) { ZRTP_LOG(1,(_ZTU_,"\tERROR! failed to compute Incoming Confirm hmac. s=%d ID=%u\n", s, stream->id)); return zrtp_status_fail; } // MARK: TRACE CONFIRM HMAC ERROR #if 0 { char buff[512]; ZRTP_LOG(3,(_ZTU_,"HMAC TRACE. VERIFY\n")); ZRTP_LOG(3,(_ZTU_,"\tcipher text:%s. size=%u\n", hex2str((const char*)&confirm->hash, encrypted_body_size, buff, sizeof(buff)), encrypted_body_size)); ZRTP_LOG(3,(_ZTU_,"\t key:%s.\n", hex2str(stream->cc.peer_hmackey.buffer, stream->cc.peer_hmackey.length, buff, sizeof(buff)))); ZRTP_LOG(3,(_ZTU_,"\t comp hmac:%s.\n", hex2str(hmac.buffer, hmac.length, buff, sizeof(buff)))); ZRTP_LOG(3,(_ZTU_,"\t hmac:%s.\n", hex2str((const char*)confirm->hmac, ZRTP_HMAC_SIZE, buff, sizeof(buff)))); } #endif if (0 != zrtp_memcmp(confirm->hmac, hmac.buffer, ZRTP_HMAC_SIZE)) { /* * Weird. Perhaps a bug in our code or our peer's code. Or it could be an attacker * who doesn't realize that Man-In-The-Middling the Diffie-Hellman key generation * but allowing the correct rsIds to pass through accomplishes nothing more than * forcing us to fallback to cleartext mode. If this attacker had gone ahead and deleted * or replaced the rsIds, then he would have been able to stay in the middle (although * he would of course still face the threat of a Voice Authentication Check). On the * other hand if this attacker wanted to force us to fallback to cleartext mode, he could * have done that more simply, for example by intercepting our ZRTP HELLO packet and * replacing it with a normal non-ZRTP comfort noise packet. In any case, we'll do our * "switch to cleartext fallback" behavior. */ ZRTP_LOG(2,(_ZTU_,"\tWARNING!" ZRTP_VERIFIED_RESP_WARNING_STR "ID=%u\n", stream->id)); _zrtp_machine_enter_initiatingerror(stream, zrtp_error_auth_decrypt, 1); return zrtp_status_fail; } /* Then we need to decrypt Confirm body */ do { cipher_ctx = session->blockcipher->start( session->blockcipher, (uint8_t*)stream->cc.peer_zrtp_key.buffer, NULL, ZRTP_CIPHER_MODE_CFB); if (!cipher_ctx) { break; } s = session->blockcipher->set_iv( session->blockcipher, cipher_ctx, (zrtp_v128_t*)confirm->iv); if (zrtp_status_ok != s) { break; } s = session->blockcipher->decrypt( session->blockcipher, cipher_ctx, (uint8_t*)&confirm->hash, encrypted_body_size); } while(0); if (cipher_ctx) { session->blockcipher->stop(session->blockcipher, cipher_ctx); } if (zrtp_status_ok != s) { ZRTP_LOG(3,(_ZTU_,"\tERROR! failed to decrypt incoming Confirm. s=%d ID=%u\n", s, stream->id)); return s; } /* We have access to hash field and can check hmac of the previous message */ { zrtp_msg_hdr_t *hdr = NULL; char *key=NULL; zrtp_string32_t tmphash_str = ZSTR_INIT_EMPTY(tmphash_str); zrtp_hash_t *hash = zrtp_comp_find( ZRTP_CC_HASH, ZRTP_HASH_SHA256, stream->zrtp); if (ZRTP_IS_STREAM_DH(stream)) { hdr = &stream->messages.peer_dhpart.hdr; key = (char*)confirm->hash; } else { hash->hash_c(hash, (char*)confirm->hash, ZRTP_MESSAGE_HASH_SIZE, ZSTR_GV(tmphash_str)); if (ZRTP_STATEMACHINE_INITIATOR == stream->protocol->type) { hdr = &stream->messages.peer_hello.hdr; hash->hash_c( hash, tmphash_str.buffer, ZRTP_MESSAGE_HASH_SIZE, ZSTR_GV(tmphash_str) ); } else { hdr = &stream->messages.peer_commit.hdr; } key = tmphash_str.buffer; } if (0 != _zrtp_validate_message_hmac(stream, hdr, key)) { return zrtp_status_fail; } } /* Set evil bit if other-side shared session key */ stream->peer_disclose_bit = (confirm->flags & 0x01); /* Enable ALLOWCLEAR option if only both sides support it */ stream->allowclear = (confirm->flags & 0x02) && session->profile.allowclear; /* Drop RS1 VERIFIED flag if other side didn't verified key exchange */ if (0 == (confirm->flags & 0x04)) { ZRTP_LOG(2,(_ZTU_,"\tINFO: Other side Confirm V=0 - set verified to 0! ID=%u\n", stream->id)); zrtp_verified_set(session->zrtp, &session->zrtp->zid, &session->peer_zid, 0); } /* Look for Enrollment replay flag */ if (confirm->flags & 0x08) { ZRTP_LOG(2,(_ZTU_,"\tINFO: Confirm PBX Enrolled flag is set - it is a Registration call! ID=%u\n", stream->id)); if (stream->mitm_mode != ZRTP_MITM_MODE_CLIENT) { ZRTP_LOG(2,(_ZTU_,"\tERROR: PBX enrollment flag was received in wrong MiTM mode %s." " ID=%u\n", zrtp_log_mode2str(stream->mode), stream->id)); _zrtp_machine_enter_initiatingerror(stream, zrtp_error_invalid_packet, 1); return zrtp_status_fail; } /* Passive endpoint should ignore PBX Enrollment. */ if (ZRTP_LICENSE_MODE_PASSIVE != stream->zrtp->lic_mode) { stream->mitm_mode = ZRTP_MITM_MODE_REG_CLIENT; } else { ZRTP_LOG(2,(_ZTU_,"\tINFO: Ignore PBX Enrollment flag as we are Passive ID=%u\n", stream->id)); } } stream->cache_ttl = ZRTP_MIN(session->profile.cache_ttl, zrtp_ntoh32(confirm->expired_interval)); /* Copy packet for future hashing */ zrtp_memcpy(&stream->messages.peer_confirm, confirm, zrtp_ntoh16(confirm->hdr.length)*4); return zrtp_status_ok; }
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 }