Implement packet replay protection
This commit is contained in:
parent
326aaf8070
commit
793ab80fce
|
@ -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_;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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_) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue