diff --git a/include/rtcp.hh b/include/rtcp.hh index 1f7f929..658a5ce 100644 --- a/include/rtcp.hh +++ b/include/rtcp.hh @@ -291,6 +291,9 @@ namespace uvg_rtp { size_t rtcp_pkt_count_; size_t rtcp_byte_count_; + /* Number of RTCP packets sent */ + size_t rtcp_pkt_sent_count_; + /* Flag that is true if the application has not yet sent an RTCP packet. */ bool initial_; diff --git a/include/util.hh b/include/util.hh index 82780c2..67c4740 100644 --- a/include/util.hh +++ b/include/util.hh @@ -235,6 +235,7 @@ extern thread_local rtp_error_t rtp_errno; #define TIME_DIFF(s, e, u) ((ssize_t)std::chrono::duration_cast(e - s).count()) #define SET_NEXT_FIELD_32(a, p, v) do { *(uint32_t *)&(a)[p] = (v); p += 4; } while (0) +#define SET_FIELD_32(a, i, v) do { *(uint32_t *)&(a)[i] = (v); } while (0) static inline void hex_dump(uint8_t *buf, size_t len) { diff --git a/src/rtcp.cc b/src/rtcp.cc index 798ed9d..c8cf294 100644 --- a/src/rtcp.cc +++ b/src/rtcp.cc @@ -22,7 +22,7 @@ uvg_rtp::rtcp::rtcp(uvg_rtp::rtp *rtp, int flags): tp_(0), tc_(0), tn_(0), pmembers_(0), members_(0), senders_(0), rtcp_bandwidth_(0), we_sent_(0), avg_rtcp_pkt_pize_(0), rtcp_pkt_count_(0), - initial_(true), num_receivers_(0), + rtcp_pkt_sent_count_(0), initial_(true), num_receivers_(0), sender_hook_(nullptr), receiver_hook_(nullptr), sdes_hook_(nullptr), diff --git a/src/rtcp/runner.cc b/src/rtcp/runner.cc index 43f2dd1..3529900 100644 --- a/src/rtcp/runner.cc +++ b/src/rtcp/runner.cc @@ -23,6 +23,8 @@ std::vector uvg_rtp::rtcp::get_participants() rtp_error_t uvg_rtp::rtcp::generate_report() { + rtcp_pkt_sent_count_++; + if (our_role_ == RECEIVER) return generate_receiver_report(); return generate_sender_report(); diff --git a/src/rtcp/sender.cc b/src/rtcp/sender.cc index c1db704..0760827 100644 --- a/src/rtcp/sender.cc +++ b/src/rtcp/sender.cc @@ -29,7 +29,9 @@ rtp_error_t uvg_rtp::rtcp::handle_sender_report_packet(uint8_t *packet, size_t s if (!packet || !size) return RTP_INVALID_VALUE; + auto srtpi = (*(uint32_t *)&packet[size - SRTCP_INDEX_LENGTH - AUTH_TAG_LENGTH]); auto frame = new uvg_rtp::frame::rtcp_sender_report; + auto ret = RTP_OK; frame->header.version = (packet[0] >> 6) & 0x3; frame->header.padding = (packet[0] >> 5) & 0x1; @@ -37,6 +39,20 @@ rtp_error_t uvg_rtp::rtcp::handle_sender_report_packet(uint8_t *packet, size_t s frame->header.length = ntohs(*(uint16_t *)&packet[2]); frame->ssrc = ntohl(*(uint32_t *)&packet[4]); + if (flags_ & RCE_SRTP) { + if ((ret = srtcp_->verify_auth_tag(packet, size)) != RTP_OK) { + LOG_ERROR("Failed to verify RTCP authentication tag!"); + return RTP_AUTH_TAG_MISMATCH; + } + + if (((srtpi >> 31) & 0x1) && !(flags_ & RCE_SRTP_NULL_CIPHER)) { + if (srtcp_->decrypt(frame->ssrc, srtpi & 0x7fffffff, packet, size) != RTP_OK) { + LOG_ERROR("Failed to decrypt RTCP Sender Report"); + return ret; + } + } + } + if (!is_participant(frame->ssrc)) { LOG_WARN("Sender Report received from an unknown participant"); add_participant(frame->ssrc); @@ -98,6 +114,9 @@ rtp_error_t uvg_rtp::rtcp::generate_sender_report() frame_size += 20; /* sender info */ frame_size += num_receivers_ * 24; /* report blocks */ + if (flags_ & RCE_SRTP) + frame_size += SRTCP_INDEX_LENGTH + AUTH_TAG_LENGTH; + if (!(frame = new uint8_t[frame_size])) { LOG_ERROR("Failed to allocate space for RTCP Receiver Report"); return RTP_MEMORY_ERROR; @@ -140,9 +159,21 @@ rtp_error_t uvg_rtp::rtcp::generate_sender_report() ptr += p.second->stats.lsr ? 0 : 4; } + /* Encrypt the packet if NULL cipher has not been enabled, + * calculate authentication tag for the packet and add SRTCP index at the end */ + if (flags_ & RCE_SRTP) { + if (!(RCE_SRTP & RCE_SRTP_NULL_CIPHER)) { + srtcp_->encrypt(ssrc_, rtcp_pkt_sent_count_, &frame[8], frame_size - 8 - SRTCP_INDEX_LENGTH - AUTH_TAG_LENGTH); + SET_FIELD_32(frame, frame_size - SRTCP_INDEX_LENGTH - AUTH_TAG_LENGTH, (1 << 31) | rtcp_pkt_sent_count_); + } else { + SET_FIELD_32(frame, frame_size - SRTCP_INDEX_LENGTH - AUTH_TAG_LENGTH, (0 << 31) | rtcp_pkt_sent_count_); + } + srtcp_->add_auth_tag(frame, frame_size); + } + for (auto& p : participants_) { if ((ret = p.second->socket->sendto(p.second->address, frame, frame_size, 0)) != RTP_OK) { - LOG_ERROR("sendto() failed!"); + log_platform_error("sendto(2) failed"); goto end; } diff --git a/src/srtp/srtcp.cc b/src/srtp/srtcp.cc index 35feb78..5b57435 100644 --- a/src/srtp/srtcp.cc +++ b/src/srtp/srtcp.cc @@ -72,26 +72,8 @@ rtp_error_t uvg_rtp::srtcp::decrypt(uint32_t ssrc, uint32_t seq, uint8_t *buffer uvg_rtp::crypto::aes::ctr ctr(srtp_ctx_->key_ctx.remote.enc_key, sizeof(srtp_ctx_->key_ctx.remote.enc_key), iv); - /* ... otherwise calculate authentication tag for the packet - * and compare it against the one we received */ - auto hmac_sha1 = uvg_rtp::crypto::hmac::sha1(srtp_ctx_->key_ctx.remote.auth_key, AES_KEY_LENGTH); - - hmac_sha1.update(buffer, size - AUTH_TAG_LENGTH - SRTCP_INDEX_LENGTH); - hmac_sha1.final((uint8_t *)&digest); - - if (memcmp(&digest, &buffer[size - AUTH_TAG_LENGTH - SRTCP_INDEX_LENGTH], AUTH_TAG_LENGTH)) { - LOG_ERROR("Authentication tag mismatch!"); - return RTP_AUTH_TAG_MISMATCH; - } - - size_t size_ = size - AUTH_TAG_LENGTH - SRTCP_INDEX_LENGTH - RTCP_HEADER_LENGTH; - uint8_t *new_buffer = new uint8_t[size_]; - - ctr.decrypt(new_buffer, buffer + RTCP_HEADER_LENGTH, size_); - memset(buffer + RTCP_HEADER_LENGTH, 0, size); - memcpy(buffer + RTCP_HEADER_LENGTH, new_buffer, size_); - delete[] new_buffer; - + /* skip header and sender ssrc */ + ctr.decrypt(&buffer[8], &buffer[8], size - 8 - AUTH_TAG_LENGTH - SRTCP_INDEX_LENGTH); return RTP_OK; } #endif