Implement Secure RTCP for Sender Reports

This commit is contained in:
Aaro Altonen 2020-09-03 11:35:37 +03:00
parent cc9438da40
commit 2a4e45032a
6 changed files with 41 additions and 22 deletions

View File

@ -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_;

View File

@ -235,6 +235,7 @@ extern thread_local rtp_error_t rtp_errno;
#define TIME_DIFF(s, e, u) ((ssize_t)std::chrono::duration_cast<std::chrono::u>(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)
{

View File

@ -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),

View File

@ -23,6 +23,8 @@ std::vector<uint32_t> 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();

View File

@ -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;
}

View File

@ -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