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 install_packet_handlers();
uint32_t get_default_bandwidth_kbps(rtp_format_t fmt);
bool check_pull_preconditions();

View File

@ -302,58 +302,68 @@ rtp_error_t uvgrtp::media_stream::free_resources(rtp_error_t 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()
{
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_);
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_));
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);
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) {
/* If we are using ZRTP, we only install the ZRTP handler first. Rest of the handlers are installed after ZRTP is
finished. If ZRTP is not enabled, we can install all the required handlers now */
if ((rce_flags_ & RCE_SRTP_KMNGMNT_ZRTP) && zrtp_) {
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());
3, remote_ssrc_,
std::bind(&uvgrtp::zrtp::packet_handler, zrtp_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4, std::placeholders::_5),
nullptr);
}
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);
else {
install_packet_handlers();
}
if (rce_flags_ & RCE_SRTP) {
srtp_ = std::shared_ptr<uvgrtp::srtp>(new uvgrtp::srtp(rce_flags_));
srtcp_ = std::shared_ptr<uvgrtp::srtcp>(new uvgrtp::srtcp());
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);
}
/* If we are using SRTP user keys, reception is started after SRTP is initalised in add_srtp_ctx() */
if (rce_flags_ & RCE_SRTP_KMNGMNT_USER) {
return RTP_OK;
}
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);
}
}
UVG_LOG_DEBUG("Starting multistream negotiation ----------");
}
ret = RTP_OK;
@ -385,16 +397,19 @@ rtp_error_t uvgrtp::media_stream::init(std::shared_ptr<uvgrtp::zrtp> zrtp)
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)
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)
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
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;
}
@ -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;
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)
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?
if ((ret = srtp_->init(SRTP, rce_flags_, key, key, salt, salt)) != RTP_OK) {
UVG_LOG_WARN("Failed to initialize SRTP for media stream!");
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) {
UVG_LOG_WARN("Failed to initialize SRTCP for media stream!");
return free_resources(ret);
}
//rtcp_ = std::shared_ptr<uvgrtp::rtcp> (new uvgrtp::rtcp(rtp_, ssrc_, remote_ssrc_, cname_, sfp_, srtcp_, rce_flags_));
//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();
return 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 --------------------------------- */
// Magic Cookie 0x5a525450
if (ntohl(*(uint32_t*)&ptr[4]) == 0x5a525450) {
// TODO: Add functionality
//UVG_LOG_INFO("ZRTP packet");
retval = handlers->zrtp.handler(nullptr, rce_flags, &ptr[0], size, &frame);
if (handlers->zrtp.handler != nullptr) {
retval = handlers->zrtp.handler(nullptr, rce_flags, &ptr[0], size, &frame);
}
break;
}
@ -592,27 +592,38 @@ void uvgrtp::reception_flow::process_packet(int rce_flags)
retval = RTP_PKT_MODIFIED;
/* 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 (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 */
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 (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 */
if (retval == RTP_PKT_READY) {
return_frame(frame);
break;
}
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) {
return_frame(frame);
}

View File

@ -36,8 +36,16 @@ uvgrtp::zrtp::zrtp():
remote_ip6_addr_(),
initialized_(false),
receiver_(),
dh_finished_(false),
state_(0)
hello_(nullptr),
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_.dh = new uvgrtp::crypto::dh;
@ -373,20 +381,71 @@ bool uvgrtp::zrtp::are_we_initiator(uint8_t *our_hvi, uint8_t *their_hvi)
rtp_error_t uvgrtp::zrtp::begin_session()
{
auto hello = uvgrtp::zrtp_msg::hello(session_);
auto hello_ack = uvgrtp::zrtp_msg::hello_ack();
auto hello = uvgrtp::zrtp_msg::hello(session_);
auto hello_ack = uvgrtp::zrtp_msg::hello_ack();
bool hello_recv = false;
uvgrtp::clock::hrc::hrc_t start = uvgrtp::clock::hrc::now();
int interval = 50;
int i = 1;
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 run_time = (long int)uvgrtp::clock::hrc::diff_now(start);
long int diff_ms = next_sendslot - run_time;
int type = 0;
int poll_timeout = (int)diff_ms;
if (diff_ms < 0) {
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");
}
++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) {
interval *= 2;
}
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(diff_ms));
}
if (i > 20) {
break;
}
@ -473,23 +473,21 @@ rtp_error_t uvgrtp::zrtp::begin_session()
rtp_error_t uvgrtp::zrtp::init_session(int key_agreement)
{
/* Create ZRTP session from capabilities struct we've constructed */
session_.hash_algo = S256;
session_.cipher_algo = AES1;
session_.auth_tag_type = HS32;
session_.hash_algo = S256;
session_.cipher_algo = AES1;
session_.auth_tag_type = HS32;
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.
* If so, they are the initiator and we're the responder */
while (receiver_.recv_msg(local_socket_, 0, MSG_DONTWAIT, type) != RTP_INTERRUPTED) {
if (type == ZRTP_FT_COMMIT) {
commit.parse_msg(receiver_, session_);
session_.role = RESPONDER;
return RTP_OK;
}
if (commit_ != nullptr) {
commit.parse_msg(commit_, session_, len_);
session_.role = RESPONDER;
UVG_LOG_DEBUG("------1------------RESPONDER");
return RTP_OK;
}
/* If we proceed to sending Commit message, we can assume we're the initiator.
@ -500,43 +498,45 @@ rtp_error_t uvgrtp::zrtp::init_session(int key_agreement)
int interval = 150;
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 run_time = (long int)uvgrtp::clock::hrc::diff_now(start);
long int diff_ms = next_sendslot - run_time;
int poll_timeout = (int)diff_ms;
if (diff_ms < 0) {
if (commit.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) {
UVG_LOG_ERROR("Failed to send Commit message!");
}
++i;
}
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));
UVG_LOG_DEBUG("Commit sent");
if (interval < 1200) {
interval *= 2;
}
++i;
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (i > 10) {
break;
@ -549,61 +549,57 @@ rtp_error_t uvgrtp::zrtp::init_session(int key_agreement)
rtp_error_t uvgrtp::zrtp::dh_part1()
{
auto dhpart = uvgrtp::zrtp_msg::dh_key_exchange(session_, 1);
int type = 0;
auto dhpart = uvgrtp::zrtp_msg::dh_key_exchange(session_, 1);
uvgrtp::clock::hrc::hrc_t start = uvgrtp::clock::hrc::now();
int interval = 150;
int i = 1;
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 run_time = (long int)uvgrtp::clock::hrc::diff_now(start);
long int diff_ms = next_sendslot - run_time;
int poll_timeout = (int)diff_ms;
if (diff_ms < 0) {
if (dhpart.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) {
UVG_LOG_ERROR("Failed to send DHPart1 Message!");
}
++i;
}
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));
UVG_LOG_DEBUG("DHPart1 sent");
if (interval < 1200) {
interval *= 2;
}
++i;
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (i > 10) {
break;
}
}
return RTP_TIMEOUT;
}
rtp_error_t uvgrtp::zrtp::dh_part2()
{
int type = 0;
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!");
return ret;
}
@ -617,30 +613,28 @@ rtp_error_t uvgrtp::zrtp::dh_part2()
int i = 1;
while (true) {
if (conf1_ != nullptr) {
UVG_LOG_DEBUG("Confirm1 Message received");
return RTP_OK;
}
long int next_sendslot = i * interval;
long int run_time = (long int)uvgrtp::clock::hrc::diff_now(start);
long int diff_ms = next_sendslot - run_time;
int poll_timeout = (int)diff_ms;
if (diff_ms < 0) {
if ((ret = dhpart.send_msg(local_socket_, remote_addr_, remote_ip6_addr_)) != RTP_OK) {
UVG_LOG_ERROR("Failed to send DHPart2 Message!");
return ret;
}
++i;
}
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));
UVG_LOG_DEBUG("DHPart2 sent");
if (interval < 1200) {
interval *= 2;
}
++i;
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (i > 10) {
break;
@ -651,68 +645,65 @@ rtp_error_t uvgrtp::zrtp::dh_part2()
rtp_error_t uvgrtp::zrtp::responder_finalize_session()
{
auto confirm = uvgrtp::zrtp_msg::confirm(session_, 1);
auto confack = uvgrtp::zrtp_msg::confack(session_);
int type = 0;
auto confirm = uvgrtp::zrtp_msg::confirm(session_, 1);
auto confack = uvgrtp::zrtp_msg::confack(session_);
uvgrtp::clock::hrc::hrc_t start = uvgrtp::clock::hrc::now();
int interval = 150;
int i = 1;
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 run_time = (long int)uvgrtp::clock::hrc::diff_now(start);
long int diff_ms = next_sendslot - run_time;
int poll_timeout = (int)diff_ms;
if (diff_ms < 0) {
if (confirm.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) {
UVG_LOG_ERROR("Failed to send Confirm1 Message!");
}
++i;
}
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));
UVG_LOG_DEBUG("Confirm1 sent");
if (interval < 1200) {
interval *= 2;
}
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (i > 10) {
break;
}
}
return RTP_TIMEOUT;
}
rtp_error_t uvgrtp::zrtp::initiator_finalize_session()
{
rtp_error_t ret = RTP_OK;
auto confirm = uvgrtp::zrtp_msg::confirm(session_, 2);
int type = 0;
auto confirm = uvgrtp::zrtp_msg::confirm(session_, 2);
uvgrtp::clock::hrc::hrc_t start = uvgrtp::clock::hrc::now();
int interval = 150;
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!");
return ret;
}
@ -723,10 +714,14 @@ rtp_error_t uvgrtp::zrtp::initiator_finalize_session()
}
while (true) {
if (confack_ != nullptr) {
UVG_LOG_DEBUG("Conf2ACK received successfully!");
return RTP_OK;
}
long int next_sendslot = i * interval;
long int run_time = (long int)uvgrtp::clock::hrc::diff_now(start);
long int diff_ms = next_sendslot - run_time;
int poll_timeout = (int)diff_ms;
if (diff_ms < 0) {
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;
}
++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) {
interval *= 2;
}
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (i > 10) {
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());
}
hello_ = nullptr;
hello_ack_ = nullptr;
commit_ = nullptr;
dh1_ = nullptr;
dh2_ = nullptr;
conf1_ = nullptr;
conf2_ = nullptr;
confack_ = nullptr;
/* TODO: set all fields initially to zero */
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
* the the roles for participants. */
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_.r_msg.hello.second, session_.r_msg.hello.first);
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;
}
}
UVG_LOG_INFO("ZRTP has been initialized using DHMode");
/* ZRTP has been initialized using DHMode */
initialized_ = true;
/* reset the timeout (no longer needed) */
/*
/* reset the timeout (no longer needed)
struct timeval tv = { 0, 0 };
if (local_socket_->setsockopt(SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv)) != RTP_OK)
return RTP_GENERIC_ERROR;
*/
/* Session has been initialized successfully and SRTP can start */
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_.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");
if ((ret = begin_session()) != RTP_OK) {
@ -968,7 +973,7 @@ rtp_error_t uvgrtp::zrtp::get_srtp_keys(
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))
{
@ -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) {
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) {
/* None of these messages should be received by this stream
* 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 */
case uvgrtp::zrtp_msg::ZRTP_MSG_HELLO:
case ZRTP_MSG_HELLO:
{
// TODO: Check length based on algorithms
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:
{
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:
{
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:
{
// 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:
{
// 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:
{
// 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:
{
// 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:
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:
/* 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;
}
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;
}
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;
}
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;
}
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;
}
/* 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/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
#include <winsock2.h>
@ -64,7 +69,8 @@ namespace uvgrtp {
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
* to "zrtp_handler" which then checks whether the packet is a ZRTP packet
* or not and processes it accordingly.
@ -72,8 +78,7 @@ namespace uvgrtp {
* Return RTP_OK on success
* Return RTP_PKT_NOT_HANDLED if "buffer" does not contain a 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 new_packet_handler(void* args, int rce_flags, uint8_t* read_ptr, size_t size, 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);
inline bool has_dh_finished() const
{
@ -120,7 +125,6 @@ namespace uvgrtp {
/* Derive new key using s0 as HMAC 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,
* and responding to remote's Hello message using HelloAck message
*
@ -193,9 +197,20 @@ namespace uvgrtp {
std::mutex zrtp_mtx_;
bool dh_finished_ = false;
int state_;
uvgrtp::zrtp_msg::zrtp_hello* hello_;
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_;
bool dh_finished_ = false;
};
}