Implement packet replay protection

This commit is contained in:
Aaro Altonen 2020-09-04 09:03:28 +03:00
parent 326aaf8070
commit 793ab80fce
8 changed files with 52 additions and 3 deletions

View File

@ -10,6 +10,7 @@
#endif
#include <cstdint>
#include <unordered_set>
#include <vector>
#include "../debug.hh"
@ -109,6 +110,8 @@ namespace uvg_rtp {
uint16_t s_l; /* highest received sequence number */
uint8_t *replay; /* list of recently received and authenticated SRTP packets */
int flags; /* context configuration flags */
srtp_key_ctx_t key_ctx;
} srtp_ctx_t;
@ -161,6 +164,10 @@ namespace uvg_rtp {
/* SRTP context containing all session information and keys */
srtp_ctx_t *srtp_ctx_;
/* Map containing all authentication tags of received packets (separate for SRTP and SRTCP)
* Used to implement replay protection */
std::unordered_set<uint32_t> replay_list_;
/* If NULL cipher is enabled, it means that RTP packets are not
* encrypted but other security mechanisms described in RFC 3711 may be used */
bool use_null_cipher_;

View File

@ -24,7 +24,9 @@ namespace uvg_rtp {
/* Verify the authentication tag present in "buffer"
*
* Return RTP_OK on success
* Return RTP_AUTH_TAG_MISMATCH if authentication tags don't match */
* Return RTP_AUTH_TAG_MISMATCH if authentication tags don't match
* Return RTP_INVALID_VALUE if received packet has already been received
* and replay protection has been enabled */
rtp_error_t verify_auth_tag(uint8_t *buffer, size_t len);
/* Decrypt and verify the authenticity of the RTCP packet

View File

@ -16,6 +16,9 @@ namespace uvg_rtp {
/* TODO: */
rtp_error_t decrypt(uint8_t *buffer, size_t len);
/* TODO: */
bool is_replayed_packet(uint32_t digest);
/* Decrypt the payload of an RTP packet and verify authentication tag (if enabled) */
static rtp_error_t recv_packet_handler(void *arg, int flags, frame::rtp_frame **out);

View File

@ -194,9 +194,12 @@ enum RTP_CTX_ENABLE_FLAGS {
* NOTE: this flag must be coupled with at least RCE_SRTP */
RCE_SRTP_AUTHENTICATE_RTP = 1 << 13,
/* Enable packet replay protection */
RCE_SRTP_REPLAY_PROTECTION = 1 << 14,
/* Enable RTCP for the media stream.
* If SRTP is enabled, SRTCP is used instead */
RCE_RTCP = 1 << 14,
RCE_RTCP = 1 << 15,
RCE_LAST = 1 << 15,
};

View File

@ -52,6 +52,9 @@ uvg_rtp::media_stream *uvg_rtp::session::create_stream(int r_port, int s_port, r
#ifdef __RTP_CRYPTO__
if (flags & RCE_SRTP) {
if (flags & RCE_SRTP_REPLAY_PROTECTION)
flags |= RCE_SRTP_AUTHENTICATE_RTP;
if (flags & RCE_SRTP_KMNGMNT_ZRTP) {
if (!zrtp_) {

View File

@ -94,6 +94,8 @@ rtp_error_t uvg_rtp::base_srtp::init(int type, int flags)
use_null_cipher_ = !!(flags & RCE_SRTP_NULL_CIPHER);
authenticate_rtp_ = !!(flags & RCE_SRTP_AUTHENTICATE_RTP);
srtp_ctx_->flags = flags;
int label_enc = 0;
int label_auth = 0;
int label_salt = 0;

View File

@ -55,8 +55,19 @@ rtp_error_t uvg_rtp::srtcp::verify_auth_tag(uint8_t *buffer, size_t len)
hmac_sha1.update((uint8_t *)&srtp_ctx_->roc, sizeof(srtp_ctx_->roc));
hmac_sha1.final((uint8_t *)&digest, AUTH_TAG_LENGTH);
if (memcmp(&digest, &buffer[len - AUTH_TAG_LENGTH], AUTH_TAG_LENGTH))
if (memcmp(&digest, &buffer[len - AUTH_TAG_LENGTH], AUTH_TAG_LENGTH)) {
LOG_ERROR("STCP authentication tag mismatch!");
return RTP_AUTH_TAG_MISMATCH;
}
if (srtp_ctx_->flags & RCE_SRTP_REPLAY_PROTECTION) {
if (replay_list_.find(digest) != replay_list_.end()) {
LOG_ERROR("Replayed packet received, discarding!");
return RTP_INVALID_VALUE;
}
replay_list_.insert(digest);
}
return RTP_OK;
}

View File

@ -41,6 +41,20 @@ rtp_error_t uvg_rtp::srtp::encrypt(uint32_t ssrc, uint16_t seq, uint8_t *buffer,
return RTP_OK;
}
bool uvg_rtp::srtp::is_replayed_packet(uint32_t digest)
{
if (!(srtp_ctx_->flags & RCE_SRTP_REPLAY_PROTECTION))
return false;
if (replay_list_.find(digest) != replay_list_.end()) {
LOG_ERROR("Replayed packet received, discarding!");
return true;
}
replay_list_.insert(digest);
return false;
}
rtp_error_t uvg_rtp::srtp::recv_packet_handler(void *arg, int flags, frame::rtp_frame **out)
{
(void)flags;
@ -63,6 +77,10 @@ rtp_error_t uvg_rtp::srtp::recv_packet_handler(void *arg, int flags, frame::rtp_
return RTP_GENERIC_ERROR;
}
if (srtp->is_replayed_packet(digest)) {
LOG_ERROR("Replayed packet received, discarding!");
return RTP_INVALID_VALUE;
}
frame->payload_len -= AUTH_TAG_LENGTH;
}