Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 303637) +++ channels/chan_sip.c (working copy) @@ -5203,22 +5203,27 @@ } if (ast_test_flag(&p->flags[1], SIP_PAGE2_USE_SRTP)) { + unsigned int suite; + + suite = (ast_test_flag(&p->flags[1], SIP_PAGE2_SRTP_CRYPTO_SUITE) >> 29); + ast_verbose(VERBOSE_PREFIX_2 "Encrypted Media is required, offering suite %d.\n", suite); + if (ast_test_flag(&p->flags[0], SIP_REINVITE)) { ast_debug(1, "Direct media not possible when using SRTP, ignoring canreinvite setting\n"); ast_clear_flag(&p->flags[0], SIP_REINVITE); } - if (p->rtp && !p->srtp && setup_srtp(&p->srtp) < 0) { + if (p->rtp && !p->srtp && setup_srtp(&p->srtp, suite) < 0) { ast_log(LOG_WARNING, "SRTP audio setup failed\n"); return -1; } - if (p->vrtp && !p->vsrtp && setup_srtp(&p->vsrtp) < 0) { + if (p->vrtp && !p->vsrtp && setup_srtp(&p->vsrtp, suite) < 0) { ast_log(LOG_WARNING, "SRTP video setup failed\n"); return -1; } - if (p->trtp && !p->vsrtp && setup_srtp(&p->tsrtp) < 0) { + if (p->trtp && !p->vsrtp && setup_srtp(&p->tsrtp, suite) < 0) { ast_log(LOG_WARNING, "SRTP text setup failed\n"); return -1; } @@ -10578,7 +10583,7 @@ if (!srtp->crypto) { srtp->crypto = sdp_crypto_setup(); } - if (srtp->crypto && (sdp_crypto_offer(srtp->crypto) >= 0)) { + if (srtp->crypto && (sdp_crypto_offer(srtp->crypto, srtp->flags & 0x3) >= 0)) { *a_crypto = sdp_crypto_attrib(srtp->crypto); } @@ -26392,6 +26397,26 @@ ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_Q850_REASON); } else if (!strcasecmp(v->name, "encryption")) { ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_USE_SRTP); + if (ast_test_flag(&peer->flags[1], SIP_PAGE2_USE_SRTP)) { + /* + * To mimic behavior from before encryption_suite was introduced, + * we set crypto suite to aes_80 if encryption=yes. + */ + ast_set_flag(&peer->flags[1], SIP_PAGE2_SRTP_CRYPTO_USE_AES_80); + ast_clear_flag(&peer->flags[1], SIP_PAGE2_SRTP_CRYPTO_USE_AES_32); + } + } else if (!strcasecmp(v->name, "encryption_suite")) { + if (!strcasecmp(v->value, "aes_32")) { + ast_clear_flag(&peer->flags[1], SIP_PAGE2_SRTP_CRYPTO_USE_AES_80); + ast_set_flag(&peer->flags[1], SIP_PAGE2_SRTP_CRYPTO_USE_AES_32); + } else if (!strcasecmp(v->value, "aes_80")){ + ast_set_flag(&peer->flags[1], SIP_PAGE2_SRTP_CRYPTO_USE_AES_80); + ast_clear_flag(&peer->flags[1], SIP_PAGE2_SRTP_CRYPTO_USE_AES_32); + } else { + ast_clear_flag(&peer->flags[1], SIP_PAGE2_SRTP_CRYPTO_USE_AES_80); + ast_clear_flag(&peer->flags[1], SIP_PAGE2_SRTP_CRYPTO_USE_AES_32); + ast_warning(VERBOSE_PREFIX_2 "Invalid SRTP_CRYPTO_SUITE: %s, please use aes_80 or aes_32.\n", v->value); + } } else if (!strcasecmp(v->name, "snom_aoc_enabled")) { ast_set2_flag(&peer->flags[2], ast_true(v->value), SIP_PAGE3_SNOM_AOC); } @@ -28210,8 +28235,30 @@ } /* SRTP */ -static int setup_srtp(struct sip_srtp **srtp) +static void set_srtp_suite_flags(struct sip_srtp *srtp, int suite) { + switch (suite) { + case 0: + ast_clear_flag(srtp, SRTP_CRYPTO_USE_AES_80); + ast_clear_flag(srtp, SRTP_CRYPTO_USE_AES_32); + break; + case SRTP_CRYPTO_USE_AES_80: + ast_set_flag(srtp, SRTP_CRYPTO_USE_AES_80); + ast_clear_flag(srtp, SRTP_CRYPTO_USE_AES_32); + break; + case SRTP_CRYPTO_USE_AES_32: + ast_clear_flag(srtp, SRTP_CRYPTO_USE_AES_80); + ast_set_flag(srtp, SRTP_CRYPTO_USE_AES_32); + break; + default: + ast_verbose(VERBOSE_PREFIX_2 "Invalid SRTP_CRYPTO_SUITE = %d.\n", suite); + break; + } + ast_verbose(VERBOSE_PREFIX_2 "SRTP_CRYPTO_SUITE is set to %d.\n", ast_test_flag(srtp, SRTP_CRYPTO_SUITE)); +} + +static int setup_srtp(struct sip_srtp **srtp, int suite) +{ if (!ast_rtp_engine_srtp_is_registered()) { ast_log(LOG_ERROR, "No SRTP module loaded, can't setup SRTP session.\n"); return -1; @@ -28221,11 +28268,15 @@ return -1; } + set_srtp_suite_flags(*srtp, suite); + return 0; } static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct sip_srtp **srtp, const char *a) { + int suite; + if (strncasecmp(a, "crypto:", 7)) { return FALSE; } @@ -28235,7 +28286,7 @@ return FALSE; } - if (setup_srtp(srtp) < 0) { + if (setup_srtp(srtp, 0) < 0) { return FALSE; } } @@ -28250,9 +28301,11 @@ return FALSE; } - if (sdp_crypto_process((*srtp)->crypto, a, rtp) < 0) { + suite = sdp_crypto_process((*srtp)->crypto, a, rtp); + if (suite < 0) { return FALSE; } + set_srtp_suite_flags(*srtp, suite); ast_set_flag(*srtp, SRTP_CRYPTO_OFFER_OK); Index: channels/sip/include/sip.h =================================================================== --- channels/sip/include/sip.h (revision 303637) +++ channels/sip/include/sip.h (working copy) @@ -336,6 +336,9 @@ #define SIP_PAGE2_VIDEOSUPPORT_ALWAYS (1 << 26) /*!< DP: Always set up video, even if endpoints don't support it */ #define SIP_PAGE2_HAVEPEERCONTEXT (1 << 27) /*< Are we associated with a configured peer context? */ #define SIP_PAGE2_USE_SRTP (1 << 28) /*!< DP: Whether we should offer (only) SRTP */ +#define SIP_PAGE2_SRTP_CRYPTO_SUITE (3 << 29) /*!< DP: SRTP suite to offer */ +#define SIP_PAGE2_SRTP_CRYPTO_USE_AES_80 (1 << 29) /*!< DP: SRTP suite to offer */ +#define SIP_PAGE2_SRTP_CRYPTO_USE_AES_32 (2 << 29) /*!< DP: SRTP suite to offer */ #define SIP_PAGE2_FLAGS_TO_COPY \ (SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_IGNORESDPVERSION | \ @@ -343,7 +346,8 @@ SIP_PAGE2_BUGGY_MWI | SIP_PAGE2_TEXTSUPPORT | SIP_PAGE2_FAX_DETECT | \ SIP_PAGE2_UDPTL_DESTINATION | SIP_PAGE2_VIDEOSUPPORT_ALWAYS | SIP_PAGE2_PREFERRED_CODEC | \ SIP_PAGE2_RPID_IMMEDIATE | SIP_PAGE2_RPID_UPDATE | SIP_PAGE2_SYMMETRICRTP |\ - SIP_PAGE2_Q850_REASON | SIP_PAGE2_HAVEPEERCONTEXT | SIP_PAGE2_USE_SRTP) + SIP_PAGE2_Q850_REASON | SIP_PAGE2_HAVEPEERCONTEXT |\ + SIP_PAGE2_USE_SRTP | SIP_PAGE2_SRTP_CRYPTO_SUITE) #define SIP_PAGE3_SNOM_AOC (1 << 0) /*!< DPG: Allow snom aoc messages */ Index: channels/sip/include/sdp_crypto.h =================================================================== --- channels/sip/include/sdp_crypto.h (revision 303637) +++ channels/sip/include/sdp_crypto.h (working copy) @@ -52,8 +52,8 @@ * \param attr the a:crypto line from SDP * \param rtp The rtp instance associated with the SDP being parsed * - * \retval 0 success - * \retval nonzero failure + * \retval suite_val (enum ast_srtp_suite) success + * \retval -1 failure */ int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_instance *rtp); @@ -64,11 +64,12 @@ * The offer is stored on the sdp_crypto struct in a_crypto * * \param A valid sdp_crypto struct + * \param A valid sdp_crypto suite value * * \retval 0 success * \retval nonzero failure */ -int sdp_crypto_offer(struct sdp_crypto *p); +int sdp_crypto_offer(struct sdp_crypto *p, enum ast_srtp_suite suite); /*! \brief Return the a_crypto value of the sdp_crypto struct Index: channels/sip/include/srtp.h =================================================================== --- channels/sip/include/srtp.h (revision 303637) +++ channels/sip/include/srtp.h (working copy) @@ -31,8 +31,9 @@ #include "sdp_crypto.h" /* SRTP flags */ -#define SRTP_ENCR_OPTIONAL (1 << 1) /* SRTP encryption optional */ -#define SRTP_CRYPTO_ENABLE (1 << 2) +#define SRTP_CRYPTO_SUITE (3 << 0) /* Preferred SRTP encryption suite */ +#define SRTP_CRYPTO_SUITE_USE_AES_80 (1 << 0) +#define SRTP_CRYPTO_SUITE_USE_AES_32 (1 << 1) #define SRTP_CRYPTO_OFFER_OK (1 << 3) /*! \brief structure for secure RTP audio */ Index: channels/sip/sdp_crypto.c =================================================================== --- channels/sip/sdp_crypto.c (revision 303637) +++ channels/sip/sdp_crypto.c (working copy) @@ -47,6 +47,18 @@ char local_key64[SRTP_MASTER_LEN64]; }; +/*! \brief Readable descriptions of SRTP crypto suites. + * \note Used for building SRTP a=crypto offers */ +const struct suite2stringtable { + const enum ast_srtp_suite suite; + const char *desc; +} suite2string[] = { + { AST_NULL_CIPHER, "NULL_CIPHER" }, + { AST_AES_CM_128_HMAC_SHA1_80, "AES_CM_128_HMAC_SHA1_80" }, + { AST_AES_CM_128_HMAC_SHA1_32, "AES_CM_128_HMAC_SHA1_32" }, + { AST_F8_128_HMAC_SHA1_80, "F8_128_HMAC_SHA1_80" } +}; + static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, unsigned long ssrc, int inbound); static struct sdp_crypto *sdp_crypto_alloc(void) @@ -281,19 +293,20 @@ snprintf(p->a_crypto, attr_len + 10, "a=crypto:%s %s inline:%s\r\n", tag, suite, p->local_key64); } - return 0; + return suite_val; } -int sdp_crypto_offer(struct sdp_crypto *p) +int sdp_crypto_offer(struct sdp_crypto *p, enum ast_srtp_suite suite) { char crypto_buf[128]; - const char *crypto_suite = "AES_CM_128_HMAC_SHA1_80"; /* Crypto offer */ if (p->a_crypto) { ast_free(p->a_crypto); } - if (snprintf(crypto_buf, sizeof(crypto_buf), "a=crypto:1 %s inline:%s\r\n", crypto_suite, p->local_key64) < 1) { + ast_verbose(VERBOSE_PREFIX_2, "Selecting '%s' for srtp crypto offer.\n", suite2string[suite].desc); + if (snprintf(crypto_buf, sizeof(crypto_buf), "a=crypto:1 %s inline:%s\r\n", + suite2string[suite].desc, p->local_key64) < 1) { return -1; } Index: include/asterisk/res_srtp.h =================================================================== --- include/asterisk/res_srtp.h (revision 303637) +++ include/asterisk/res_srtp.h (working copy) @@ -42,6 +42,7 @@ /* Crypto suites */ enum ast_srtp_suite { + AST_NULL_CIPHER = 0, AST_AES_CM_128_HMAC_SHA1_80 = 1, AST_AES_CM_128_HMAC_SHA1_32 = 2, AST_F8_128_HMAC_SHA1_80 = 3