multiplex: Rewrite ZRTP initialization to use new packet handler

This commit is contained in:
Heikki Tampio 2023-06-21 15:32:20 +03:00
parent 81499a5c6d
commit ac4f883d3f
5 changed files with 550 additions and 321 deletions

View File

@ -388,6 +388,8 @@ namespace uvgrtp {
rtp_error_t start_components(); rtp_error_t start_components();
rtp_error_t install_packet_handlers();
uint32_t get_default_bandwidth_kbps(rtp_format_t fmt); uint32_t get_default_bandwidth_kbps(rtp_format_t fmt);
bool check_pull_preconditions(); bool check_pull_preconditions();

View File

@ -302,6 +302,36 @@ rtp_error_t uvgrtp::media_stream::free_resources(rtp_error_t ret)
return ret; return ret;
} }
rtp_error_t uvgrtp::media_stream::install_packet_handlers()
{
reception_flow_->new_install_handler(
1, remote_ssrc_,
std::bind(&uvgrtp::rtp::new_packet_handler, rtp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4, std::placeholders::_5),
nullptr);
if (rce_flags_ & RCE_RTCP) {
reception_flow_->new_install_handler(
6, remote_ssrc_,
std::bind(&uvgrtp::rtcp::new_recv_packet_handler_common, rtcp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4, std::placeholders::_5), rtcp_.get());
}
if (rce_flags_ & RCE_RTCP_MUX) {
rtcp_->set_socket(socket_);
reception_flow_->new_install_handler(
2, remote_ssrc_,
std::bind(&uvgrtp::rtcp::new_recv_packet_handler, rtcp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4, std::placeholders::_5), nullptr);
}
if (rce_flags_ & RCE_SRTP) {
socket_->install_handler(srtp_.get(), srtp_->send_packet_handler);
reception_flow_->new_install_handler(
4, remote_ssrc_,
std::bind(&uvgrtp::srtp::new_recv_packet_handler, srtp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4, std::placeholders::_5), srtp_.get());
}
return RTP_OK;
}
rtp_error_t uvgrtp::media_stream::init() rtp_error_t uvgrtp::media_stream::init()
{ {
if (init_connection() != RTP_OK) { if (init_connection() != RTP_OK) {
@ -313,47 +343,27 @@ rtp_error_t uvgrtp::media_stream::init()
rtp_ = std::shared_ptr<uvgrtp::rtp>(new uvgrtp::rtp(fmt_, ssrc_, ipv6_)); rtp_ = std::shared_ptr<uvgrtp::rtp>(new uvgrtp::rtp(fmt_, ssrc_, ipv6_));
rtcp_ = std::shared_ptr<uvgrtp::rtcp>(new uvgrtp::rtcp(rtp_, ssrc_, remote_ssrc_, cname_, sfp_, rce_flags_)); rtcp_ = std::shared_ptr<uvgrtp::rtcp>(new uvgrtp::rtcp(rtp_, ssrc_, remote_ssrc_, cname_, sfp_, rce_flags_));
srtp_ = std::shared_ptr<uvgrtp::srtp>(new uvgrtp::srtp(rce_flags_));
srtcp_ = std::shared_ptr<uvgrtp::srtcp>(new uvgrtp::srtcp());
socket_->install_handler(rtcp_.get(), rtcp_->send_packet_handler_vec); socket_->install_handler(rtcp_.get(), rtcp_->send_packet_handler_vec);
reception_flow_->new_install_handler( /* If we are using ZRTP, we only install the ZRTP handler first. Rest of the handlers are installed after ZRTP is
1, remote_ssrc_, finished. If ZRTP is not enabled, we can install all the required handlers now */
std::bind(&uvgrtp::rtp::new_packet_handler, rtp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, if ((rce_flags_ & RCE_SRTP_KMNGMNT_ZRTP) && zrtp_) {
std::placeholders::_4, std::placeholders::_5),
nullptr);
if (rce_flags_ & RCE_RTCP) {
reception_flow_->new_install_handler( reception_flow_->new_install_handler(
6, remote_ssrc_, 3, remote_ssrc_,
std::bind(&uvgrtp::rtcp::new_recv_packet_handler_common, rtcp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::bind(&uvgrtp::zrtp::packet_handler, zrtp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4, std::placeholders::_5), rtcp_.get()); std::placeholders::_4, std::placeholders::_5),
nullptr);
} }
if (rce_flags_ & RCE_RTCP_MUX) { else {
rtcp_->set_socket(socket_); install_packet_handlers();
reception_flow_->new_install_handler(
2, remote_ssrc_,
std::bind(&uvgrtp::rtcp::new_recv_packet_handler, rtcp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4, std::placeholders::_5), nullptr);
} }
if (rce_flags_ & RCE_SRTP) { /* If we are using SRTP user keys, reception is started after SRTP is initalised in add_srtp_ctx() */
srtp_ = std::shared_ptr<uvgrtp::srtp>(new uvgrtp::srtp(rce_flags_)); if (rce_flags_ & RCE_SRTP_KMNGMNT_USER) {
srtcp_ = std::shared_ptr<uvgrtp::srtcp>(new uvgrtp::srtcp()); return RTP_OK;
socket_->install_handler(srtp_.get(), srtp_->send_packet_handler);
reception_flow_->new_install_handler(
4, remote_ssrc_,
std::bind(&uvgrtp::srtp::new_recv_packet_handler, srtp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4, std::placeholders::_5), srtp_.get());
if ((rce_flags_ & RCE_SRTP_KMNGMNT_ZRTP) && zrtp_) {
reception_flow_->new_install_handler(
3, remote_ssrc_,
std::bind(&uvgrtp::zrtp::new_packet_handler, zrtp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4, std::placeholders::_5),
nullptr);
}
} }
return start_components(); return start_components();
} }
@ -377,6 +387,8 @@ rtp_error_t uvgrtp::media_stream::init(std::shared_ptr<uvgrtp::zrtp> zrtp)
return free_resources(RTP_TIMEOUT); return free_resources(RTP_TIMEOUT);
} }
} }
UVG_LOG_DEBUG("Starting multistream negotiation ----------");
} }
ret = RTP_OK; ret = RTP_OK;
@ -385,16 +397,19 @@ rtp_error_t uvgrtp::media_stream::init(std::shared_ptr<uvgrtp::zrtp> zrtp)
return free_resources(ret); return free_resources(ret);
} }
srtp_ = std::shared_ptr<uvgrtp::srtp>(new uvgrtp::srtp(rce_flags_));
if ((ret = init_srtp_with_zrtp(rce_flags_, SRTP, srtp_, zrtp)) != RTP_OK) if ((ret = init_srtp_with_zrtp(rce_flags_, SRTP, srtp_, zrtp)) != RTP_OK)
return free_resources(ret); return free_resources(ret);
srtcp_ = std::shared_ptr<uvgrtp::srtcp>(new uvgrtp::srtcp());
if ((ret = init_srtp_with_zrtp(rce_flags_, SRTCP, srtcp_, zrtp)) != RTP_OK) if ((ret = init_srtp_with_zrtp(rce_flags_, SRTCP, srtcp_, zrtp)) != RTP_OK)
return free_resources(ret); return free_resources(ret);
zrtp->dh_has_finished(); // only after the DH stream has gotten its keys, do we let non-DH stream perform ZRTP zrtp->dh_has_finished(); // only after the DH stream has gotten its keys, do we let non-DH stream perform ZRTP
UVG_LOG_ERROR("ZRTP finished --------------");
install_packet_handlers();
// Sleep is there to make sure that our last ZRTP messages get to their destination before any of our sent media
// packets do. This can happen if the media packets are routed via a faster route.
//std::this_thread::sleep_for(std::chrono::milliseconds(50));
return RTP_OK; return RTP_OK;
} }
@ -410,65 +425,23 @@ rtp_error_t uvgrtp::media_stream::add_srtp_ctx(uint8_t *key, uint8_t *salt)
unsigned int srtp_rce_flags = RCE_SRTP | RCE_SRTP_KMNGMNT_USER; unsigned int srtp_rce_flags = RCE_SRTP | RCE_SRTP_KMNGMNT_USER;
rtp_error_t ret = RTP_OK; rtp_error_t ret = RTP_OK;
/*
if (init_connection() != RTP_OK) {
UVG_LOG_ERROR("Failed to initialize the underlying socket");
return free_resources(RTP_GENERIC_ERROR);
}
reception_flow_ = sfp_->get_reception_flow_ptr(socket_);*/
if ((rce_flags_ & srtp_rce_flags) != srtp_rce_flags) if ((rce_flags_ & srtp_rce_flags) != srtp_rce_flags)
return free_resources(RTP_NOT_SUPPORTED); return free_resources(RTP_NOT_SUPPORTED);
//rtp_ = std::shared_ptr<uvgrtp::rtp> (new uvgrtp::rtp(fmt_, ssrc_, ipv6_));
//srtp_ = std::shared_ptr<uvgrtp::srtp> (new uvgrtp::srtp(rce_flags_));
// why are they local and remote key/salt the same? // why are they local and remote key/salt the same?
if ((ret = srtp_->init(SRTP, rce_flags_, key, key, salt, salt)) != RTP_OK) { if ((ret = srtp_->init(SRTP, rce_flags_, key, key, salt, salt)) != RTP_OK) {
UVG_LOG_WARN("Failed to initialize SRTP for media stream!"); UVG_LOG_WARN("Failed to initialize SRTP for media stream!");
return free_resources(ret); return free_resources(ret);
} }
// srtcp_ = std::shared_ptr<uvgrtp::srtcp> (new uvgrtp::srtcp());
if ((ret = srtcp_->init(SRTCP, rce_flags_, key, key, salt, salt)) != RTP_OK) { if ((ret = srtcp_->init(SRTCP, rce_flags_, key, key, salt, salt)) != RTP_OK) {
UVG_LOG_WARN("Failed to initialize SRTCP for media stream!"); UVG_LOG_WARN("Failed to initialize SRTCP for media stream!");
return free_resources(ret); return free_resources(ret);
} }
//rtcp_ = std::shared_ptr<uvgrtp::rtcp> (new uvgrtp::rtcp(rtp_, ssrc_, remote_ssrc_, cname_, sfp_, srtcp_, rce_flags_)); return start_components();
//socket_->install_handler(rtcp_.get(), rtcp_->send_packet_handler_vec);
//socket_->install_handler(srtp_.get(), srtp_->send_packet_handler);
/*
reception_flow_->new_install_handler(
1, remote_ssrc_,
std::bind(&uvgrtp::rtp::new_packet_handler, rtp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4, std::placeholders::_5),
nullptr);
if (rce_flags_ & RCE_RTCP) {
reception_flow_->new_install_handler(
6, remote_ssrc_,
std::bind(&uvgrtp::rtcp::new_recv_packet_handler_common, rtcp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4, std::placeholders::_5), rtcp_.get());
}
if (rce_flags_ & RCE_RTCP_MUX) {
rtcp_->set_socket(socket_);
reception_flow_->new_install_handler(
2, remote_ssrc_,
std::bind(&uvgrtp::rtcp::new_recv_packet_handler, rtcp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4, std::placeholders::_5), nullptr);
}
reception_flow_->new_install_handler(
4, remote_ssrc_,
std::bind(&uvgrtp::srtp::new_recv_packet_handler, srtp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4, std::placeholders::_5), srtp_.get());
*/
return RTP_OK;//start_components();
} }
rtp_error_t uvgrtp::media_stream::start_components() rtp_error_t uvgrtp::media_stream::start_components()

View File

@ -581,9 +581,9 @@ void uvgrtp::reception_flow::process_packet(int rce_flags)
/* -------------------- ZRTP check --------------------------------- */ /* -------------------- ZRTP check --------------------------------- */
// Magic Cookie 0x5a525450 // Magic Cookie 0x5a525450
if (ntohl(*(uint32_t*)&ptr[4]) == 0x5a525450) { if (ntohl(*(uint32_t*)&ptr[4]) == 0x5a525450) {
// TODO: Add functionality if (handlers->zrtp.handler != nullptr) {
//UVG_LOG_INFO("ZRTP packet"); retval = handlers->zrtp.handler(nullptr, rce_flags, &ptr[0], size, &frame);
retval = handlers->zrtp.handler(nullptr, rce_flags, &ptr[0], size, &frame); }
break; break;
} }
@ -592,27 +592,38 @@ void uvgrtp::reception_flow::process_packet(int rce_flags)
retval = RTP_PKT_MODIFIED; retval = RTP_PKT_MODIFIED;
/* Create RTP header */ /* Create RTP header */
retval = handlers->rtp.handler(nullptr, rce_flags, &ptr[0], size, &frame); if (handlers->rtp.handler != nullptr) {
retval = handlers->rtp.handler(nullptr, rce_flags, &ptr[0], size, &frame);
}
else {
UVG_LOG_INFO("RTP handler is null");
}
/* If SRTP is enabled -> send through SRTP handler */ /* If SRTP is enabled -> send through SRTP handler */
if (rce_flags & RCE_SRTP && retval == RTP_PKT_MODIFIED) { if (rce_flags & RCE_SRTP && retval == RTP_PKT_MODIFIED) {
retval = handlers->srtp.handler(handlers->srtp.args, rce_flags, &ptr[0], size, &frame); if (handlers->srtp.handler != nullptr) {
retval = handlers->srtp.handler(handlers->srtp.args, rce_flags, &ptr[0], size, &frame);
}
} }
/* Update RTCP session statistics */ /* Update RTCP session statistics */
if (rce_flags & RCE_RTCP) { if (rce_flags & RCE_RTCP) {
retval = handlers->rtcp_common.handler(handlers->rtcp_common.args, rce_flags, &ptr[0], size, &frame); if (handlers->rtcp_common.handler != nullptr) {
retval = handlers->rtcp_common.handler(handlers->rtcp_common.args, rce_flags, &ptr[0], size, &frame);
}
} }
/* If packet is ok, hand over to media handler */ /* If packet is ok, hand over to media handler */
if (retval == RTP_PKT_MODIFIED || retval == RTP_PKT_NOT_HANDLED) { if (retval == RTP_PKT_MODIFIED || retval == RTP_PKT_NOT_HANDLED) {
retval = handlers->media.handler(handlers->media.args, rce_flags, &ptr[0], size, &frame); if (handlers->media.handler && frame) {
retval = handlers->media.handler(handlers->media.args, rce_flags, &ptr[0], size, &frame);
}
/* Last, if one or more packets are ready, return them to the user */ /* Last, if one or more packets are ready, return them to the user */
if (retval == RTP_PKT_READY) { if (retval == RTP_PKT_READY) {
return_frame(frame); return_frame(frame);
break; break;
} }
else if (retval == RTP_MULTIPLE_PKTS_READY && handlers->getter != nullptr) { else if (retval == RTP_MULTIPLE_PKTS_READY && handlers->getter != nullptr) {
UVG_LOG_INFO("TODO:is this correct???"); //UVG_LOG_INFO("TODO:is this correct???");
while (handlers->getter(&frame) == RTP_PKT_READY) { while (handlers->getter(&frame) == RTP_PKT_READY) {
return_frame(frame); return_frame(frame);
} }

View File

@ -36,8 +36,16 @@ uvgrtp::zrtp::zrtp():
remote_ip6_addr_(), remote_ip6_addr_(),
initialized_(false), initialized_(false),
receiver_(), receiver_(),
dh_finished_(false), hello_(nullptr),
state_(0) hello_ack_(nullptr),
commit_(nullptr),
dh1_(nullptr),
dh2_(nullptr),
conf1_(nullptr),
conf2_(nullptr),
confack_(nullptr),
type_(-1),
len_(0)
{ {
cctx_.sha256 = new uvgrtp::crypto::sha256; cctx_.sha256 = new uvgrtp::crypto::sha256;
cctx_.dh = new uvgrtp::crypto::dh; cctx_.dh = new uvgrtp::crypto::dh;
@ -373,8 +381,8 @@ bool uvgrtp::zrtp::are_we_initiator(uint8_t *our_hvi, uint8_t *their_hvi)
rtp_error_t uvgrtp::zrtp::begin_session() rtp_error_t uvgrtp::zrtp::begin_session()
{ {
auto hello = uvgrtp::zrtp_msg::hello(session_); auto hello = uvgrtp::zrtp_msg::hello(session_);
auto hello_ack = uvgrtp::zrtp_msg::hello_ack(); auto hello_ack = uvgrtp::zrtp_msg::hello_ack();
bool hello_recv = false; bool hello_recv = false;
uvgrtp::clock::hrc::hrc_t start = uvgrtp::clock::hrc::now(); uvgrtp::clock::hrc::hrc_t start = uvgrtp::clock::hrc::now();
@ -382,11 +390,62 @@ rtp_error_t uvgrtp::zrtp::begin_session()
int i = 1; int i = 1;
while (true) { while (true) {
/* We received something interesting, either Hello message from remote in which case
* we need to send HelloACK message back and keep sending our Hello until HelloACK is received,
* or HelloACK message which means we can stop sending our */
/* We received Hello message from remote, parse it and send */
if (hello_ != nullptr) {
UVG_LOG_DEBUG("Got ZRTP Hello. Sending Hello ACK");
hello_ack.send_msg(local_socket_, remote_addr_, remote_ip6_addr_);
if (!hello_recv) {
hello_recv = true;
/* Copy interesting information from receiver's
* message buffer to remote capabilities struct for later use */
hello.parse_msg(hello_, session_, len_);
UVG_LOG_INFO("ZRTP Hello parsed");
if (session_.capabilities.version != ZRTP_VERSION) {
/* Section 4.1.1:
*
* "If an endpoint receives a Hello message with an unsupported
* version number that is lower than the endpoint's current Hello
* message, the endpoint MUST send an Error message (Section 5.9)
* indicating failure to support this ZRTP version."
*/
if (session_.capabilities.version < ZRTP_VERSION) {
UVG_LOG_ERROR("Remote supports version %d, uvgRTP supports %d. Session cannot continue!",
session_.capabilities.version, ZRTP_VERSION);
return RTP_NOT_SUPPORTED;
}
UVG_LOG_WARN("ZRTP Protocol version %u not supported, keep sending Hello Messages",
session_.capabilities.version);
hello_recv = false;
}
}
/* We received ACK for our Hello message.
* Make sure we've received Hello message also before exiting */
}
if (hello_ack_ != nullptr) {
if (hello_recv)
{
UVG_LOG_DEBUG("Got Hello ACK! Ending Hello phase");
return RTP_OK;
}
else
{
UVG_LOG_DEBUG("Got Hello ACK without Hello!");
}
}
long int next_sendslot = i * interval; long int next_sendslot = i * interval;
long int run_time = (long int)uvgrtp::clock::hrc::diff_now(start); long int run_time = (long int)uvgrtp::clock::hrc::diff_now(start);
long int diff_ms = next_sendslot - run_time; long int diff_ms = next_sendslot - run_time;
int type = 0;
int poll_timeout = (int)diff_ms;
if (diff_ms < 0) { if (diff_ms < 0) {
UVG_LOG_DEBUG("Sending ZRTP hello # %i", i); UVG_LOG_DEBUG("Sending ZRTP hello # %i", i);
@ -394,73 +453,14 @@ rtp_error_t uvgrtp::zrtp::begin_session()
UVG_LOG_ERROR("Failed to send Hello message"); UVG_LOG_ERROR("Failed to send Hello message");
} }
++i; ++i;
}
else if (receiver_.recv_msg(local_socket_, poll_timeout, 0, type) == RTP_OK) {
/* We received something interesting, either Hello message from remote in which case
* we need to send HelloACK message back and keep sending our Hello until HelloACK is received,
* or HelloACK message which means we can stop sending our */
/* We received Hello message from remote, parse it and send */
if (type == ZRTP_FT_HELLO) {
UVG_LOG_DEBUG("Got ZRTP Hello. Sending Hello ACK");
hello_ack.send_msg(local_socket_, remote_addr_, remote_ip6_addr_);
if (!hello_recv) {
hello_recv = true;
/* Copy interesting information from receiver's
* message buffer to remote capabilities struct for later use */
hello.parse_msg(receiver_, session_);
if (session_.capabilities.version != ZRTP_VERSION) {
/* Section 4.1.1:
*
* "If an endpoint receives a Hello message with an unsupported
* version number that is lower than the endpoint's current Hello
* message, the endpoint MUST send an Error message (Section 5.9)
* indicating failure to support this ZRTP version."
*/
if (session_.capabilities.version < ZRTP_VERSION) {
UVG_LOG_ERROR("Remote supports version %d, uvgRTP supports %d. Session cannot continue!",
session_.capabilities.version, ZRTP_VERSION);
return RTP_NOT_SUPPORTED;
}
UVG_LOG_WARN("ZRTP Protocol version %u not supported, keep sending Hello Messages",
session_.capabilities.version);
hello_recv = false;
}
}
/* We received ACK for our Hello message.
* Make sure we've received Hello message also before exiting */
}
else if (type == ZRTP_FT_HELLO_ACK) {
if (hello_recv)
{
UVG_LOG_DEBUG("Got Hello ACK!");
return RTP_OK;
}
else
{
UVG_LOG_DEBUG("Got Hello ACK without Hello!");
}
}
else {
/* at this point we do not care about other messages */
UVG_LOG_DEBUG("Got an unknown ZRTP message!");
}
}
else
{
UVG_LOG_DEBUG("Did not get any ZRTP messages on try # %i", i);
std::this_thread::sleep_for(std::chrono::milliseconds(diff_ms));
if (interval < 200) { if (interval < 200) {
interval *= 2; interval *= 2;
} }
} }
else {
std::this_thread::sleep_for(std::chrono::milliseconds(diff_ms));
}
if (i > 20) { if (i > 20) {
break; break;
} }
@ -473,23 +473,21 @@ rtp_error_t uvgrtp::zrtp::begin_session()
rtp_error_t uvgrtp::zrtp::init_session(int key_agreement) rtp_error_t uvgrtp::zrtp::init_session(int key_agreement)
{ {
/* Create ZRTP session from capabilities struct we've constructed */ /* Create ZRTP session from capabilities struct we've constructed */
session_.hash_algo = S256; session_.hash_algo = S256;
session_.cipher_algo = AES1; session_.cipher_algo = AES1;
session_.auth_tag_type = HS32; session_.auth_tag_type = HS32;
session_.key_agreement_type = key_agreement; session_.key_agreement_type = key_agreement;
session_.sas_type = B32; session_.sas_type = B32;
int type = 0; auto commit = uvgrtp::zrtp_msg::commit(session_);
auto commit = uvgrtp::zrtp_msg::commit(session_);
/* First check if remote has already sent the message. /* First check if remote has already sent the message.
* If so, they are the initiator and we're the responder */ * If so, they are the initiator and we're the responder */
while (receiver_.recv_msg(local_socket_, 0, MSG_DONTWAIT, type) != RTP_INTERRUPTED) { if (commit_ != nullptr) {
if (type == ZRTP_FT_COMMIT) { commit.parse_msg(commit_, session_, len_);
commit.parse_msg(receiver_, session_); session_.role = RESPONDER;
session_.role = RESPONDER; UVG_LOG_DEBUG("------1------------RESPONDER");
return RTP_OK; return RTP_OK;
}
} }
/* If we proceed to sending Commit message, we can assume we're the initiator. /* If we proceed to sending Commit message, we can assume we're the initiator.
@ -501,42 +499,44 @@ rtp_error_t uvgrtp::zrtp::init_session(int key_agreement)
int i = 1; int i = 1;
while (true) { while (true) {
if (commit_) {
/* As per RFC 6189, if both parties have sent Commit message and the mode is DH,
* hvi shall determine who is the initiator (the party with larger hvi is initiator) */
commit.parse_msg(commit_, session_, len_);
/* Our hvi is smaller than remote's meaning we are the responder.
*
* Commit message must be ACKed with DHPart1 messages so we need exit,
* construct that message and sent it to remote */
if (!are_we_initiator(session_.hash_ctx.o_hvi, session_.hash_ctx.r_hvi)) {
session_.role = RESPONDER;
UVG_LOG_DEBUG("------------------RESPONDER");
return RTP_OK;
}
}
if (dh1_ || conf1_) {
return RTP_OK;
}
long int next_sendslot = i * interval; long int next_sendslot = i * interval;
long int run_time = (long int)uvgrtp::clock::hrc::diff_now(start); long int run_time = (long int)uvgrtp::clock::hrc::diff_now(start);
long int diff_ms = next_sendslot - run_time; long int diff_ms = next_sendslot - run_time;
int poll_timeout = (int)diff_ms;
if (diff_ms < 0) { if (diff_ms < 0) {
if (commit.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) { if (commit.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) {
UVG_LOG_ERROR("Failed to send Commit message!"); UVG_LOG_ERROR("Failed to send Commit message!");
} }
++i; UVG_LOG_DEBUG("Commit sent");
}
else if (receiver_.recv_msg(local_socket_, poll_timeout, 0, type) == RTP_OK) {
/* As per RFC 6189, if both parties have sent Commit message and the mode is DH,
* hvi shall determine who is the initiator (the party with larger hvi is initiator) */
if (type == ZRTP_FT_COMMIT) {
commit.parse_msg(receiver_, session_);
/* Our hvi is smaller than remote's meaning we are the responder.
*
* Commit message must be ACKed with DHPart1 messages so we need exit,
* construct that message and sent it to remote */
if (!are_we_initiator(session_.hash_ctx.o_hvi, session_.hash_ctx.r_hvi)) {
session_.role = RESPONDER;
return RTP_OK;
}
} else if (type == ZRTP_FT_DH_PART1 || type == ZRTP_FT_CONFIRM1) {
return RTP_OK;
}
}
else
{
std::this_thread::sleep_for(std::chrono::milliseconds(diff_ms));
if (interval < 1200) { if (interval < 1200) {
interval *= 2; interval *= 2;
} }
++i;
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
if (i > 10) { if (i > 10) {
break; break;
@ -549,61 +549,57 @@ rtp_error_t uvgrtp::zrtp::init_session(int key_agreement)
rtp_error_t uvgrtp::zrtp::dh_part1() rtp_error_t uvgrtp::zrtp::dh_part1()
{ {
auto dhpart = uvgrtp::zrtp_msg::dh_key_exchange(session_, 1); auto dhpart = uvgrtp::zrtp_msg::dh_key_exchange(session_, 1);
int type = 0;
uvgrtp::clock::hrc::hrc_t start = uvgrtp::clock::hrc::now(); uvgrtp::clock::hrc::hrc_t start = uvgrtp::clock::hrc::now();
int interval = 150; int interval = 150;
int i = 1; int i = 1;
while (true) { while (true) {
if (dh2_ != nullptr) {
if (dhpart.parse_msg(dh2_, session_, len_) != RTP_OK) {
UVG_LOG_ERROR("Failed to parse DHPart2 Message!");
continue;
}
UVG_LOG_DEBUG("DHPart2 received and parse successfully!");
/* parse_msg() above extracted the public key of remote and saved it to session_.
* Now we must generate shared secrets (DHResult, total_hash, and s0) */
generate_shared_secrets_dh();
return RTP_OK;
}
long int next_sendslot = i * interval; long int next_sendslot = i * interval;
long int run_time = (long int)uvgrtp::clock::hrc::diff_now(start); long int run_time = (long int)uvgrtp::clock::hrc::diff_now(start);
long int diff_ms = next_sendslot - run_time; long int diff_ms = next_sendslot - run_time;
int poll_timeout = (int)diff_ms;
if (diff_ms < 0) { if (diff_ms < 0) {
if (dhpart.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) { if (dhpart.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) {
UVG_LOG_ERROR("Failed to send DHPart1 Message!"); UVG_LOG_ERROR("Failed to send DHPart1 Message!");
} }
++i; UVG_LOG_DEBUG("DHPart1 sent");
}
if (receiver_.recv_msg(local_socket_, poll_timeout, 0, type) == RTP_OK) {
if (type == ZRTP_FT_DH_PART2) {
if (dhpart.parse_msg(receiver_, session_) != RTP_OK) {
UVG_LOG_ERROR("Failed to parse DHPart2 Message!");
continue;
}
UVG_LOG_DEBUG("DHPart2 received and parse successfully!");
/* parse_msg() above extracted the public key of remote and saved it to session_.
* Now we must generate shared secrets (DHResult, total_hash, and s0) */
generate_shared_secrets_dh();
return RTP_OK;
}
}
else
{
std::this_thread::sleep_for(std::chrono::milliseconds(diff_ms));
if (interval < 1200) { if (interval < 1200) {
interval *= 2; interval *= 2;
} }
++i;
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
if (i > 10) { if (i > 10) {
break; break;
} }
} }
return RTP_TIMEOUT; return RTP_TIMEOUT;
} }
rtp_error_t uvgrtp::zrtp::dh_part2() rtp_error_t uvgrtp::zrtp::dh_part2()
{ {
int type = 0;
rtp_error_t ret = RTP_OK; rtp_error_t ret = RTP_OK;
auto dhpart = uvgrtp::zrtp_msg::dh_key_exchange(session_, 2); auto dhpart = uvgrtp::zrtp_msg::dh_key_exchange(session_, 2);
if ((ret = dhpart.parse_msg(receiver_, session_)) != RTP_OK) { if ((ret = dhpart.parse_msg(dh1_, session_, len_)) != RTP_OK) {
UVG_LOG_ERROR("Failed to parse DHPart1 Message!"); UVG_LOG_ERROR("Failed to parse DHPart1 Message!");
return ret; return ret;
} }
@ -617,30 +613,28 @@ rtp_error_t uvgrtp::zrtp::dh_part2()
int i = 1; int i = 1;
while (true) { while (true) {
if (conf1_ != nullptr) {
UVG_LOG_DEBUG("Confirm1 Message received");
return RTP_OK;
}
long int next_sendslot = i * interval; long int next_sendslot = i * interval;
long int run_time = (long int)uvgrtp::clock::hrc::diff_now(start); long int run_time = (long int)uvgrtp::clock::hrc::diff_now(start);
long int diff_ms = next_sendslot - run_time; long int diff_ms = next_sendslot - run_time;
int poll_timeout = (int)diff_ms;
if (diff_ms < 0) { if (diff_ms < 0) {
if ((ret = dhpart.send_msg(local_socket_, remote_addr_, remote_ip6_addr_)) != RTP_OK) { if ((ret = dhpart.send_msg(local_socket_, remote_addr_, remote_ip6_addr_)) != RTP_OK) {
UVG_LOG_ERROR("Failed to send DHPart2 Message!"); UVG_LOG_ERROR("Failed to send DHPart2 Message!");
return ret; return ret;
} }
++i; UVG_LOG_DEBUG("DHPart2 sent");
}
if (receiver_.recv_msg(local_socket_, poll_timeout, 0, type) == RTP_OK) {
if (type == ZRTP_FT_CONFIRM1) {
UVG_LOG_DEBUG("Confirm1 Message received");
return RTP_OK;
}
}
else
{
std::this_thread::sleep_for(std::chrono::milliseconds(diff_ms));
if (interval < 1200) { if (interval < 1200) {
interval *= 2; interval *= 2;
} }
++i;
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
if (i > 10) { if (i > 10) {
break; break;
@ -651,68 +645,65 @@ rtp_error_t uvgrtp::zrtp::dh_part2()
rtp_error_t uvgrtp::zrtp::responder_finalize_session() rtp_error_t uvgrtp::zrtp::responder_finalize_session()
{ {
auto confirm = uvgrtp::zrtp_msg::confirm(session_, 1); auto confirm = uvgrtp::zrtp_msg::confirm(session_, 1);
auto confack = uvgrtp::zrtp_msg::confack(session_); auto confack = uvgrtp::zrtp_msg::confack(session_);
int type = 0;
uvgrtp::clock::hrc::hrc_t start = uvgrtp::clock::hrc::now(); uvgrtp::clock::hrc::hrc_t start = uvgrtp::clock::hrc::now();
int interval = 150; int interval = 150;
int i = 1; int i = 1;
while (true) { while (true) {
if (conf2_ != nullptr) {
if (confirm.parse_msg(conf2_, session_) != RTP_OK) {
UVG_LOG_ERROR("Failed to parse Confirm2 Message!");
continue;
}
rtp_error_t ret = RTP_OK;
if ((ret = validate_session()) != RTP_OK) {
UVG_LOG_ERROR("Mismatch on one of the received MACs/Hashes, session cannot continue");
return ret;
}
/* TODO: send in a loop? */
confack.send_msg(local_socket_, remote_addr_, remote_ip6_addr_);
UVG_LOG_DEBUG("ConfACK sent");
return RTP_OK;
}
long int next_sendslot = i * interval; long int next_sendslot = i * interval;
long int run_time = (long int)uvgrtp::clock::hrc::diff_now(start); long int run_time = (long int)uvgrtp::clock::hrc::diff_now(start);
long int diff_ms = next_sendslot - run_time; long int diff_ms = next_sendslot - run_time;
int poll_timeout = (int)diff_ms;
if (diff_ms < 0) { if (diff_ms < 0) {
if (confirm.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) { if (confirm.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) {
UVG_LOG_ERROR("Failed to send Confirm1 Message!"); UVG_LOG_ERROR("Failed to send Confirm1 Message!");
} }
++i; ++i;
} UVG_LOG_DEBUG("Confirm1 sent");
if (receiver_.recv_msg(local_socket_, poll_timeout, 0, type) == RTP_OK) {
if (type == ZRTP_FT_CONFIRM2) {
if (confirm.parse_msg(receiver_, session_) != RTP_OK) {
UVG_LOG_ERROR("Failed to parse Confirm2 Message!");
continue;
}
rtp_error_t ret = RTP_OK;
if ((ret = validate_session()) != RTP_OK) {
UVG_LOG_ERROR("Mismatch on one of the received MACs/Hashes, session cannot continue");
return ret;
}
/* TODO: send in a loop? */
confack.send_msg(local_socket_, remote_addr_, remote_ip6_addr_);
return RTP_OK;
}
}
else
{
std::this_thread::sleep_for(std::chrono::milliseconds(diff_ms));
if (interval < 1200) { if (interval < 1200) {
interval *= 2; interval *= 2;
} }
} }
else {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (i > 10) { if (i > 10) {
break; break;
} }
} }
return RTP_TIMEOUT; return RTP_TIMEOUT;
} }
rtp_error_t uvgrtp::zrtp::initiator_finalize_session() rtp_error_t uvgrtp::zrtp::initiator_finalize_session()
{ {
rtp_error_t ret = RTP_OK; rtp_error_t ret = RTP_OK;
auto confirm = uvgrtp::zrtp_msg::confirm(session_, 2); auto confirm = uvgrtp::zrtp_msg::confirm(session_, 2);
int type = 0;
uvgrtp::clock::hrc::hrc_t start = uvgrtp::clock::hrc::now(); uvgrtp::clock::hrc::hrc_t start = uvgrtp::clock::hrc::now();
int interval = 150; int interval = 150;
int i = 1; int i = 1;
if ((ret = confirm.parse_msg(receiver_, session_)) != RTP_OK) { if ((ret = confirm.parse_msg(conf1_, session_)) != RTP_OK) {
UVG_LOG_ERROR("Failed to parse Confirm1 Message!"); UVG_LOG_ERROR("Failed to parse Confirm1 Message!");
return ret; return ret;
} }
@ -723,10 +714,14 @@ rtp_error_t uvgrtp::zrtp::initiator_finalize_session()
} }
while (true) { while (true) {
if (confack_ != nullptr) {
UVG_LOG_DEBUG("Conf2ACK received successfully!");
return RTP_OK;
}
long int next_sendslot = i * interval; long int next_sendslot = i * interval;
long int run_time = (long int)uvgrtp::clock::hrc::diff_now(start); long int run_time = (long int)uvgrtp::clock::hrc::diff_now(start);
long int diff_ms = next_sendslot - run_time; long int diff_ms = next_sendslot - run_time;
int poll_timeout = (int)diff_ms;
if (diff_ms < 0) { if (diff_ms < 0) {
if ((ret = confirm.send_msg(local_socket_, remote_addr_, remote_ip6_addr_)) != RTP_OK) { if ((ret = confirm.send_msg(local_socket_, remote_addr_, remote_ip6_addr_)) != RTP_OK) {
@ -734,20 +729,13 @@ rtp_error_t uvgrtp::zrtp::initiator_finalize_session()
return ret; return ret;
} }
++i; ++i;
}
if (receiver_.recv_msg(local_socket_, poll_timeout, 0, type) == RTP_OK) {
if (type == ZRTP_FT_CONF2_ACK) {
UVG_LOG_DEBUG("Conf2ACK received successfully!");
return RTP_OK;
}
}
else
{
std::this_thread::sleep_for(std::chrono::milliseconds(diff_ms));
if (interval < 1200) { if (interval < 1200) {
interval *= 2; interval *= 2;
} }
} }
else {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (i > 10) { if (i > 10) {
break; break;
} }
@ -799,6 +787,15 @@ rtp_error_t uvgrtp::zrtp::init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket
UVG_LOG_DEBUG("Starting ZRTP Diffie-Hellman negotiation with %s", uvgrtp::socket::sockaddr_to_string(addr).c_str()); UVG_LOG_DEBUG("Starting ZRTP Diffie-Hellman negotiation with %s", uvgrtp::socket::sockaddr_to_string(addr).c_str());
} }
hello_ = nullptr;
hello_ack_ = nullptr;
commit_ = nullptr;
dh1_ = nullptr;
dh2_ = nullptr;
conf1_ = nullptr;
conf2_ = nullptr;
confack_ = nullptr;
/* TODO: set all fields initially to zero */ /* TODO: set all fields initially to zero */
memset(session_.hash_ctx.o_hvi, 0, sizeof(session_.hash_ctx.o_hvi)); memset(session_.hash_ctx.o_hvi, 0, sizeof(session_.hash_ctx.o_hvi));
@ -836,7 +833,6 @@ rtp_error_t uvgrtp::zrtp::init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket
* message. This should be calculated now because the next step is choosing * message. This should be calculated now because the next step is choosing
* the the roles for participants. */ * the the roles for participants. */
auto dh_msg = uvgrtp::zrtp_msg::dh_key_exchange(session_, 2); auto dh_msg = uvgrtp::zrtp_msg::dh_key_exchange(session_, 2);
cctx_.sha256->update((uint8_t *)session_.l_msg.dh.second, session_.l_msg.dh.first); cctx_.sha256->update((uint8_t *)session_.l_msg.dh.second, session_.l_msg.dh.first);
cctx_.sha256->update((uint8_t *)session_.r_msg.hello.second, session_.r_msg.hello.first); cctx_.sha256->update((uint8_t *)session_.r_msg.hello.second, session_.r_msg.hello.first);
cctx_.sha256->final((uint8_t *)session_.hash_ctx.o_hvi); cctx_.sha256->final((uint8_t *)session_.hash_ctx.o_hvi);
@ -879,16 +875,16 @@ rtp_error_t uvgrtp::zrtp::init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket
return ret; return ret;
} }
} }
UVG_LOG_INFO("ZRTP has been initialized using DHMode");
/* ZRTP has been initialized using DHMode */ /* ZRTP has been initialized using DHMode */
initialized_ = true; initialized_ = true;
/*
/* reset the timeout (no longer needed) */ /* reset the timeout (no longer needed)
struct timeval tv = { 0, 0 }; struct timeval tv = { 0, 0 };
if (local_socket_->setsockopt(SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv)) != RTP_OK) if (local_socket_->setsockopt(SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv)) != RTP_OK)
return RTP_GENERIC_ERROR; return RTP_GENERIC_ERROR;
*/
/* Session has been initialized successfully and SRTP can start */ /* Session has been initialized successfully and SRTP can start */
return RTP_OK; return RTP_OK;
} }
@ -904,6 +900,15 @@ rtp_error_t uvgrtp::zrtp::init_msm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket
session_.ssrc = ssrc; session_.ssrc = ssrc;
session_.seq = 0; session_.seq = 0;
hello_ = nullptr;
hello_ack_ = nullptr;
commit_ = nullptr;
dh1_ = nullptr;
dh2_ = nullptr;
conf1_ = nullptr;
conf2_ = nullptr;
confack_ = nullptr;
UVG_LOG_DEBUG("Generating ZRTP keys in multistream mode"); UVG_LOG_DEBUG("Generating ZRTP keys in multistream mode");
if ((ret = begin_session()) != RTP_OK) { if ((ret = begin_session()) != RTP_OK) {
@ -968,7 +973,7 @@ rtp_error_t uvgrtp::zrtp::get_srtp_keys(
return RTP_OK; return RTP_OK;
} }
rtp_error_t uvgrtp::zrtp::new_packet_handler(void* args, int rce_flags, uint8_t* read_ptr, size_t size, frame::rtp_frame** out) rtp_error_t uvgrtp::zrtp::packet_handler(void* args, int rce_flags, uint8_t* read_ptr, size_t size, frame::rtp_frame** out)
{ {
if (size < 0 || (uint32_t)size < sizeof(uvgrtp::zrtp_msg::zrtp_msg)) if (size < 0 || (uint32_t)size < sizeof(uvgrtp::zrtp_msg::zrtp_msg))
{ {
@ -985,60 +990,283 @@ rtp_error_t uvgrtp::zrtp::new_packet_handler(void* args, int rce_flags, uint8_t*
if (msg->header.version || msg->preamble != ZRTP_PREAMBLE) { if (msg->header.version || msg->preamble != ZRTP_PREAMBLE) {
return RTP_PKT_NOT_HANDLED; return RTP_PKT_NOT_HANDLED;
} }
}
rtp_error_t uvgrtp::zrtp::packet_handler(ssize_t size, void *packet, int rce_flags, frame::rtp_frame **out)
{
if (size < 0 || (uint32_t)size < sizeof(uvgrtp::zrtp_msg::zrtp_msg))
{
return RTP_PKT_NOT_HANDLED;
}
(void)rce_flags;
(void)out;
auto msg = (uvgrtp::zrtp_msg::zrtp_msg *)packet;
/* not a ZRTP packet */
if (msg->header.version || msg->header.magic != ZRTP_MAGIC || msg->preamble != ZRTP_PREAMBLE)
return RTP_PKT_NOT_HANDLED;
switch (msg->msgblock) { switch (msg->msgblock) {
/* None of these messages should be received by this stream case ZRTP_MSG_HELLO:
* during this stage so return RTP_GENERIC_ERROR to indicate that the packet {
* is invalid and that it should not be dispatched to other packet handlers */ // TODO: Check length based on algorithms
case uvgrtp::zrtp_msg::ZRTP_MSG_HELLO: if (msg->length < 22) // see rfc 6189 section 5.8
{
UVG_LOG_WARN("ZRTP Hello length field is wrong");
return RTP_INVALID_VALUE;
}
UVG_LOG_DEBUG("ZRTP Hello message received, verify CRC32!");
zrtp_hello* hello = (zrtp_hello*)msg;
if (!uvgrtp::crypto::crc32::verify_crc32(read_ptr, size - 4, hello->crc)) {
return RTP_NOT_SUPPORTED;
}
if (hello_ != nullptr) {
//UVG_LOG_DEBUG("Already got Hello, discarding new one");
return RTP_OK;
}
hello_ = hello;
type_ = ZRTP_FT_HELLO;
len_ = size;
return RTP_OK;
}
case ZRTP_MSG_HELLO_ACK: case ZRTP_MSG_HELLO_ACK:
{
if (msg->length != 3) // see rfc 6189 section 5.3
{
UVG_LOG_WARN("ZRTP Hello ACK length field is wrong");
return RTP_INVALID_VALUE;
}
UVG_LOG_DEBUG("ZRTP HelloACK message received, verify CRC32!");
zrtp_hello_ack* ha_msg = (zrtp_hello_ack*)msg;
if (!uvgrtp::crypto::crc32::verify_crc32(read_ptr, size - 4, ha_msg->crc))
return RTP_NOT_SUPPORTED;
if (hello_ack_ != nullptr) {
//UVG_LOG_DEBUG("Already got HelloACK, discarding new one");
return RTP_OK;
}
hello_ack_ = ha_msg;
type_ = ZRTP_FT_HELLO_ACK;
len_ = size;
return RTP_OK;
}
case ZRTP_MSG_COMMIT: case ZRTP_MSG_COMMIT:
{
if (msg->length != 29 &&
msg->length != 25 &&
msg->length != 27) // see rfc 6189 section 5.4
{
UVG_LOG_WARN("ZRTP Commit length field is wrong");
return RTP_INVALID_VALUE;
}
UVG_LOG_DEBUG("ZRTP Commit message received, verify CRC32!");
zrtp_commit* commit = (zrtp_commit*)msg;
if (!uvgrtp::crypto::crc32::verify_crc32(read_ptr, size - 4, commit->crc))
return RTP_NOT_SUPPORTED;
if (commit_ != nullptr) {
UVG_LOG_DEBUG("Already got Commit, discarding new one");
return RTP_OK;
}
commit_ = commit;
type_ = ZRTP_FT_COMMIT;
len_ = size;
return RTP_OK;
}
case ZRTP_MSG_DH_PART1: case ZRTP_MSG_DH_PART1:
{
// TODO: Check based on KA type
if (msg->length < 21) // see rfc 6189 section 5.5
{
UVG_LOG_WARN("ZRTP DH Part1 length field is wrong");
return RTP_INVALID_VALUE;
}
UVG_LOG_DEBUG("ZRTP DH Part1 message received, verify CRC32!");
zrtp_dh* dh = (zrtp_dh*)msg;
if (!uvgrtp::crypto::crc32::verify_crc32(read_ptr, size - 4, dh->crc))
return RTP_NOT_SUPPORTED;
if (dh1_ != nullptr) {
UVG_LOG_DEBUG("Already got DHPart1, discarding new one");
return RTP_OK;
}
dh1_ = dh;
type_ = ZRTP_FT_DH_PART1;
len_ = size;
return RTP_OK;
}
case ZRTP_MSG_DH_PART2: case ZRTP_MSG_DH_PART2:
{
// TODO: Check based on KA type
if (msg->length < 21) // see rfc 6189 section 5.6
{
UVG_LOG_WARN("ZRTP DH Part2 length field is wrong");
return RTP_INVALID_VALUE;
}
UVG_LOG_DEBUG("ZRTP DH Part2 message received, verify CRC32!");
zrtp_dh* dh = (zrtp_dh*)msg;
if (!uvgrtp::crypto::crc32::verify_crc32(read_ptr, size - 4, dh->crc))
return RTP_NOT_SUPPORTED;
if (dh2_ != nullptr) {
UVG_LOG_DEBUG("Already got DHPart2, discarding new one");
return RTP_OK;
}
dh2_ = dh;
type_ = ZRTP_FT_DH_PART2;
len_ = size;
return RTP_OK;
}
case ZRTP_MSG_CONFIRM1: case ZRTP_MSG_CONFIRM1:
{
// TODO: Check based on signiture
if (msg->length < 19) // see rfc 6189 section 5.6
{
UVG_LOG_WARN("ZRTP Confirm1 length field is wrong");
return RTP_INVALID_VALUE;
}
rtp_error_t ret = RTP_OK;
UVG_LOG_DEBUG("ZRTP Confirm1 message received, verify CRC32!");
zrtp_confirm* dh = (zrtp_confirm*)msg;
if (!uvgrtp::crypto::crc32::verify_crc32(read_ptr, size - 4, dh->crc))
return RTP_NOT_SUPPORTED;
if (conf1_ != nullptr) {
UVG_LOG_DEBUG("Already got Confirm1, discarding new one");
return RTP_OK;
}
conf1_ = dh;
type_ = ZRTP_FT_CONFIRM1;
len_ = size;
return RTP_OK;
}
case ZRTP_MSG_CONFIRM2: case ZRTP_MSG_CONFIRM2:
{
// TODO: Check based on signiture
if (msg->length < 19) // see rfc 6189 section 5.6
{
UVG_LOG_WARN("ZRTP Confirm1 length field is wrong");
return RTP_INVALID_VALUE;
}
UVG_LOG_DEBUG("ZRTP Confirm2 message received, verify CRC32!");
zrtp_confirm* dh = (zrtp_confirm*)msg;
if (!uvgrtp::crypto::crc32::verify_crc32(read_ptr, size - 4, dh->crc))
return RTP_NOT_SUPPORTED;
if (conf2_ != nullptr) {
UVG_LOG_DEBUG("Already got Confirm2, discarding new one");
return RTP_OK;
}
conf2_ = dh;
type_ = ZRTP_FT_CONFIRM2;
len_ = size;
return RTP_OK;
}
case ZRTP_MSG_CONF2_ACK: case ZRTP_MSG_CONF2_ACK:
return RTP_GENERIC_ERROR; {
if (msg->length != 3) // see rfc 6189 section 5.8
{
UVG_LOG_WARN("ZRTP Conf2 ACK length field is wrong");
return RTP_INVALID_VALUE;
}
UVG_LOG_DEBUG("ZRTP Conf2 ACK message received, verify CRC32!");
zrtp_confack* ca = (zrtp_confack*)msg;
if (!uvgrtp::crypto::crc32::verify_crc32(read_ptr, size - 4, ca->crc))
return RTP_NOT_SUPPORTED;
if (confack_ != nullptr) {
UVG_LOG_DEBUG("Already got Conf2ACK, discarding new one");
return RTP_OK;
}
confack_ = ca;
type_ = ZRTP_FT_CONF2_ACK;
len_ = size;
return RTP_OK;
}
case ZRTP_MSG_ERROR: case ZRTP_MSG_ERROR:
/* TODO: */ {
if (msg->length != 4) // see rfc 6189 section 5.9
{
UVG_LOG_WARN("ZRTP Error length field is wrong");
return RTP_INVALID_VALUE;
}
UVG_LOG_DEBUG("ZRTP Error message received");
return RTP_OK; return RTP_OK;
}
case ZRTP_MSG_ERROR_ACK: case ZRTP_MSG_ERROR_ACK:
/* TODO: */ {
if (msg->length != 3) // see rfc 6189 section 5.10
{
UVG_LOG_WARN("ZRTP Error ACK length field is wrong");
return RTP_INVALID_VALUE;
}
UVG_LOG_DEBUG("ZRTP Error ACK message received");
return RTP_OK; return RTP_OK;
}
case ZRTP_MSG_SAS_RELAY: case ZRTP_MSG_SAS_RELAY:
{
// TODO: Check based on signiture
if (msg->length < 19) // see rfc 6189 section 5.14
{
UVG_LOG_WARN("ZRTP SAS Relay length field is wrong");
return RTP_INVALID_VALUE;
}
UVG_LOG_DEBUG("ZRTP SAS Relay message received");
return RTP_OK; return RTP_OK;
}
case ZRTP_MSG_RELAY_ACK: case ZRTP_MSG_RELAY_ACK:
{
if (msg->length != 3) // see rfc 6189 section 5.14
{
UVG_LOG_WARN("ZRTP Relay ACK length field is wrong");
return RTP_INVALID_VALUE;
}
UVG_LOG_DEBUG("ZRTP Relay ACK message received");
return RTP_OK; return RTP_OK;
}
case ZRTP_MSG_PING_ACK: case ZRTP_MSG_PING_ACK:
{
if (msg->length != 9) // see rfc 6189 section 5.16
{
UVG_LOG_WARN("ZRTP Relay ACK length field is wrong");
return RTP_INVALID_VALUE;
}
UVG_LOG_DEBUG("ZRTP Ping ACK message received");
return RTP_OK; return RTP_OK;
}
/* TODO: goclear & co-opeartion with srtp */ default: {
return RTP_OK;
}
} }
return RTP_OK;
} }

View File

@ -2,7 +2,12 @@
#include "zrtp/zrtp_receiver.hh" #include "zrtp/zrtp_receiver.hh"
#include "zrtp/defines.hh" #include "zrtp/defines.hh"
#include "zrtp/commit.hh"
#include "zrtp/confack.hh"
#include "zrtp/confirm.hh"
#include "zrtp/dh_kxchng.hh"
#include "zrtp/hello.hh"
#include "zrtp/hello_ack.hh"
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
@ -64,7 +69,8 @@ namespace uvgrtp {
uint8_t *their_msalt, uint32_t tsalt_len uint8_t *their_msalt, uint32_t tsalt_len
); );
/* ZRTP packet handler is used after ZRTP state initialization has finished /* TODO REWRITE THIS
ZRTP packet handler is used after ZRTP state initialization has finished
* and media exchange has started. RTP reception flow gives the packet * and media exchange has started. RTP reception flow gives the packet
* to "zrtp_handler" which then checks whether the packet is a ZRTP packet * to "zrtp_handler" which then checks whether the packet is a ZRTP packet
* or not and processes it accordingly. * or not and processes it accordingly.
@ -72,8 +78,7 @@ namespace uvgrtp {
* Return RTP_OK on success * Return RTP_OK on success
* Return RTP_PKT_NOT_HANDLED if "buffer" does not contain a ZRTP message * Return RTP_PKT_NOT_HANDLED if "buffer" does not contain a ZRTP message
* Return RTP_GENERIC_ERROR if "buffer" contains an invalid ZRTP message */ * Return RTP_GENERIC_ERROR if "buffer" contains an invalid ZRTP message */
static rtp_error_t packet_handler(ssize_t size, void *packet, int rce_flags, frame::rtp_frame **out); rtp_error_t packet_handler(void* args, int rce_flags, uint8_t* read_ptr, size_t size, frame::rtp_frame** out);
rtp_error_t new_packet_handler(void* args, int rce_flags, uint8_t* read_ptr, size_t size, frame::rtp_frame** out);
inline bool has_dh_finished() const inline bool has_dh_finished() const
{ {
@ -120,7 +125,6 @@ namespace uvgrtp {
/* Derive new key using s0 as HMAC key */ /* Derive new key using s0 as HMAC key */
void derive_key(const char *label, uint32_t key_len, uint8_t *key); void derive_key(const char *label, uint32_t key_len, uint8_t *key);
rtp_error_t new_begin_session();
/* Being the ZRTP session by sending a Hello message to remote, /* Being the ZRTP session by sending a Hello message to remote,
* and responding to remote's Hello message using HelloAck message * and responding to remote's Hello message using HelloAck message
* *
@ -193,9 +197,20 @@ namespace uvgrtp {
std::mutex zrtp_mtx_; std::mutex zrtp_mtx_;
bool dh_finished_ = false; uvgrtp::zrtp_msg::zrtp_hello* hello_;
int state_; uvgrtp::zrtp_msg::zrtp_hello_ack* hello_ack_;
uvgrtp::zrtp_msg::zrtp_commit* commit_;
uvgrtp::zrtp_msg::zrtp_dh* dh1_;
uvgrtp::zrtp_msg::zrtp_dh* dh2_;
uvgrtp::zrtp_msg::zrtp_confirm* conf1_;
uvgrtp::zrtp_msg::zrtp_confirm* conf2_;
uvgrtp::zrtp_msg::zrtp_confack* confack_;
int type_;
size_t len_;
std::mutex state_mutex_; std::mutex state_mutex_;
bool dh_finished_ = false;
}; };
} }