rtp: Enable srtp replay protection

Add option "srtpreplayprotection" rtp.conf to enable srtp
replay protection.

ASTERISK-29260
Reported by: Alexander Traud

Change-Id: I5cd346e3c6b6812039d1901aa4b7be688173b458
This commit is contained in:
Alexander Traud 2021-01-26 10:09:53 -07:00 committed by George Joseph
parent 2770cc5872
commit 703158b903
5 changed files with 43 additions and 4 deletions

View File

@ -45,6 +45,18 @@ rtpend=20000
; connected. This option is set to 4 by default.
; probation=8
;
; Enable sRTP replay protection. Buggy SIP user agents (UAs) reset the
; sequence number (RTP-SEQ) on a re-INVITE, for example, with Session Timers
; or on Call Hold/Resume, but keep the synchronization source (RTP-SSRC). If
; the new RTP-SEQ is higher than the previous one, the call continues if the
; roll-over counter (sRTP-ROC) is zero (the call lasted less than 22 minutes).
; In all other cases, the call faces one-way audio or even no audio at all.
; "replay check failed (index too old)" gets printed continuously. This is a
; software bug. You have to report this to the creator of that UA. Until it is
; fixed, you could disable sRTP replay protection (see RFC 3711 section 3.3.2).
; This option is enabled by default.
; srtpreplayprotection=yes
;
; Whether to enable or disable ICE support. This option is enabled by default.
; icesupport=false
;

View File

@ -0,0 +1,9 @@
Subject: res_srtp
SRTP replay protection has been added to res_srtp and
a new configuration option "srtpreplayprotection" has
been added to the rtp.conf config file. For security
reasons, the default setting is "yes". Buggy clients
may not handle this correctly which could result in
no, or one way, audio and Asterisk error messages like
"replay check failed".

View File

@ -0,0 +1,9 @@
Subject: res_srtp
SRTP replay protection has been added to res_srtp and
a new configuration option "srtpreplayprotection" has
been added to the rtp.conf config file. For security
reasons, the default setting is "yes". Buggy clients
may not handle this correctly which could result in
no, or one way, audio and Asterisk error messages like
"replay check failed".

View File

@ -181,6 +181,7 @@ enum strict_rtp_mode {
#define STRICT_RTP_LEARN_TIMEOUT 5000
#define DEFAULT_STRICT_RTP STRICT_RTP_YES /*!< Enabled by default */
#define DEFAULT_SRTP_REPLAY_PROTECTION 1
#define DEFAULT_ICESUPPORT 1
#define DEFAULT_DTLS_MTU 1200
@ -203,6 +204,7 @@ static int nochecksums;
static int strictrtp = DEFAULT_STRICT_RTP; /*!< Only accept RTP frames from a defined source. If we receive an indication of a changing source, enter learning mode. */
static int learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL; /*!< Number of sequential RTP frames needed from a single source during learning mode to accept new source. */
static int learning_min_duration = DEFAULT_LEARNING_MIN_DURATION; /*!< Lowest acceptable timeout between the first and the last sequential RTP frame. */
static int srtp_replay_protection = DEFAULT_SRTP_REPLAY_PROTECTION;
#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
static int dtls_mtu = DEFAULT_DTLS_MTU;
#endif
@ -6082,7 +6084,7 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, s
/* If this is encrypted then decrypt the payload */
if ((*rtcpheader & 0xC0) && res_srtp && srtp && res_srtp->unprotect(
srtp, rtcpheader, &len, 1) < 0) {
srtp, rtcpheader, &len, 1 | (srtp_replay_protection << 1)) < 0) {
return &ast_null_frame;
}
@ -7170,7 +7172,7 @@ static struct ast_frame *ast_rtp_interpret(struct ast_rtp_instance *instance, st
/* If this payload is encrypted then decrypt it using the given SRTP instance */
if ((*read_area & 0xC0) && res_srtp && srtp && res_srtp->unprotect(
srtp, read_area, &res, 0) < 0) {
srtp, read_area, &res, 0 | (srtp_replay_protection << 1)) < 0) {
return &ast_null_frame;
}
@ -8958,6 +8960,8 @@ static char *handle_cli_rtp_settings(struct ast_cli_entry *e, int cmd, struct as
if (strictrtp) {
ast_cli(a->fd, " Probation: %d frames\n", learning_min_sequential);
}
ast_cli(a->fd, " Replay Protect: %s\n", AST_CLI_YESNO(srtp_replay_protection));
#ifdef HAVE_PJPROJECT
ast_cli(a->fd, " ICE support: %s\n", AST_CLI_YESNO(icesupport));
#endif
@ -9060,6 +9064,7 @@ static int rtp_reload(int reload, int by_external_config)
strictrtp = DEFAULT_STRICT_RTP;
learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL;
learning_min_duration = DEFAULT_LEARNING_MIN_DURATION;
srtp_replay_protection = DEFAULT_SRTP_REPLAY_PROTECTION;
/** This resource is not "reloaded" so much as unloaded and loaded again.
* In the case of the TURN related variables, the memory referenced by a
@ -9139,6 +9144,9 @@ static int rtp_reload(int reload, int by_external_config)
}
learning_min_duration = CALC_LEARNING_MIN_DURATION(learning_min_sequential);
}
if ((s = ast_variable_retrieve(cfg, "general", "srtpreplayprotection"))) {
srtp_replay_protection = ast_true(s);
}
#ifdef HAVE_PJPROJECT
if ((s = ast_variable_retrieve(cfg, "general", "icesupport"))) {
icesupport = ast_true(s);

View File

@ -364,11 +364,12 @@ static void ast_srtp_set_cb(struct ast_srtp *srtp, const struct ast_srtp_cb *cb,
}
/* Vtable functions */
static int ast_srtp_unprotect(struct ast_srtp *srtp, void *buf, int *len, int rtcp)
static int ast_srtp_unprotect(struct ast_srtp *srtp, void *buf, int *len, int flags)
{
int res = 0;
int i;
int retry = 0;
int rtcp = (flags & 0x01) >> 0;
int retry = (flags & 0x02) >> 1;
struct ast_rtp_instance_stats stats = {0,};
tryagain: