From: Alexander Traud Date: Tue, 26 Jan 2021 17:09:53 +0000 (-0700) Subject: rtp: Enable srtp replay protection X-Git-Tag: certified/16.8-cert6~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=93468c531a20f598874d09c3a23eba8cda30589b;p=thirdparty%2Fasterisk.git rtp: Enable srtp replay protection Add option "srtpreplayprotection" rtp.conf to enable srtp replay protection. ASTERISK-29260 Reported by: Alexander Traud Change-Id: I5cd346e3c6b6812039d1901aa4b7be688173b458 --- diff --git a/configs/samples/rtp.conf.sample b/configs/samples/rtp.conf.sample index a94707e596..c60167745a 100644 --- a/configs/samples/rtp.conf.sample +++ b/configs/samples/rtp.conf.sample @@ -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 ; diff --git a/doc/CHANGES-staging/srtp_replay_protection.txt b/doc/CHANGES-staging/srtp_replay_protection.txt new file mode 100644 index 0000000000..945ddb5704 --- /dev/null +++ b/doc/CHANGES-staging/srtp_replay_protection.txt @@ -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". diff --git a/doc/UPGRADE-staging/srtp_replay_protection.txt b/doc/UPGRADE-staging/srtp_replay_protection.txt new file mode 100644 index 0000000000..945ddb5704 --- /dev/null +++ b/doc/UPGRADE-staging/srtp_replay_protection.txt @@ -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". diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index aed7a891b1..0f428b1936 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -178,6 +178,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 @@ -202,6 +203,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 @@ -5927,7 +5929,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; } @@ -7009,7 +7011,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; } @@ -8919,6 +8921,7 @@ static int rtp_reload(int reload) 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 @@ -9000,6 +9003,9 @@ static int rtp_reload(int reload) } 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); diff --git a/res/res_srtp.c b/res/res_srtp.c index 3e4b51fafb..7098621c78 100644 --- a/res/res_srtp.c +++ b/res/res_srtp.c @@ -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: