diff options
author | Alexander Traud <pabstraud@compuserve.com> | 2016-07-13 12:24:46 +0200 |
---|---|---|
committer | Alexander Traud <pabstraud@compuserve.com> | 2016-07-21 16:25:41 +0200 |
commit | 1d2173c7aed0587cdd434e69e89a3972a2642cd8 (patch) | |
tree | 3260e059b38d6e2b9f4f9817d362da9a2688d697 /main/sdp_srtp.c | |
parent | c2a72e6aa6515730acb30ad0a5392c97588d8935 (diff) |
res_srtp: Enable AES-256 and AES-GCM.
ASTERISK-26190 #close
Change-Id: I11326d80edd656524a51a19450e586c583aa0a0b
Diffstat (limited to 'main/sdp_srtp.c')
-rw-r--r-- | main/sdp_srtp.c | 373 |
1 files changed, 308 insertions, 65 deletions
diff --git a/main/sdp_srtp.c b/main/sdp_srtp.c index c92387bc2..a55aedf82 100644 --- a/main/sdp_srtp.c +++ b/main/sdp_srtp.c @@ -20,8 +20,7 @@ * * \brief SRTP and SDP Security descriptions * - * Specified in RFC 3711 - * Specified in RFC 4568 + * Specified in RFC 3711, 6188, 7714, and 4568 * * \author Mikael Magnusson <mikma@users.sourceforge.net> */ @@ -34,15 +33,15 @@ ASTERISK_REGISTER_FILE() -#include <math.h> -#include "asterisk/options.h" -#include "asterisk/utils.h" -#include "asterisk/sdp_srtp.h" +#include <math.h> /* for pow */ +#include <srtp/srtp.h> /* for SRTP_MAX_KEY_LEN, etc */ -#define SRTP_MASTER_LEN 30 -#define SRTP_MASTERKEY_LEN 16 -#define SRTP_MASTERSALT_LEN ((SRTP_MASTER_LEN) - (SRTP_MASTERKEY_LEN)) -#define SRTP_MASTER_LEN64 (((SRTP_MASTER_LEN) * 8 + 5) / 6 + 1) +#include "asterisk/linkedlists.h" /* for AST_LIST_NEXT, etc */ +#include "asterisk/logger.h" /* for ast_log, LOG_ERROR, etc */ +#include "asterisk/rtp_engine.h" /* for ast_rtp_engine_dtls, etc */ +#include "asterisk/sdp_srtp.h" /* for ast_sdp_srtp, etc */ +#include "asterisk/strings.h" /* for ast_strlen_zero */ +#include "asterisk/utils.h" /* for ast_set_flag, ast_test_flag, etc */ extern struct ast_srtp_res *res_srtp; extern struct ast_srtp_policy_res *res_srtp_policy; @@ -59,22 +58,31 @@ struct ast_sdp_srtp *ast_sdp_srtp_alloc(void) void ast_sdp_srtp_destroy(struct ast_sdp_srtp *srtp) { - if (srtp->crypto) { - ast_sdp_crypto_destroy(srtp->crypto); + struct ast_sdp_srtp *next; + + for (next = AST_LIST_NEXT(srtp, sdp_srtp_list); + srtp; + srtp = next, next = srtp ? AST_LIST_NEXT(srtp, sdp_srtp_list) : NULL) { + if (srtp->crypto) { + ast_sdp_crypto_destroy(srtp->crypto); + } + srtp->crypto = NULL; + ast_free(srtp); } - srtp->crypto = NULL; - ast_free(srtp); } struct ast_sdp_crypto { char *a_crypto; - unsigned char local_key[SRTP_MASTER_LEN]; + unsigned char local_key[SRTP_MAX_KEY_LEN]; int tag; - char local_key64[SRTP_MASTER_LEN64]; - unsigned char remote_key[SRTP_MASTER_LEN]; + char local_key64[((SRTP_MAX_KEY_LEN) * 8 + 5) / 6 + 1]; + unsigned char remote_key[SRTP_MAX_KEY_LEN]; + int key_len; }; -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 ast_sdp_crypto *sdp_crypto_alloc(const int key_len); +static struct ast_sdp_crypto *crypto_init_keys(struct ast_sdp_crypto *p, const int key_len); +static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, int key_len, unsigned long ssrc, int inbound); void ast_sdp_crypto_destroy(struct ast_sdp_crypto *crypto) { @@ -83,57 +91,67 @@ void ast_sdp_crypto_destroy(struct ast_sdp_crypto *crypto) ast_free(crypto); } -struct ast_sdp_crypto *ast_sdp_crypto_alloc(void) +static struct ast_sdp_crypto *crypto_init_keys(struct ast_sdp_crypto *p, const int key_len) { - struct ast_sdp_crypto *p; - int key_len; - unsigned char remote_key[SRTP_MASTER_LEN]; + unsigned char remote_key[key_len]; - if (!ast_rtp_engine_srtp_is_registered()) { + if (res_srtp->get_random(p->local_key, key_len) < 0) { return NULL; } - if (!(p = ast_calloc(1, sizeof(*p)))) { + ast_base64encode(p->local_key64, p->local_key, key_len, sizeof(p->local_key64)); + + p->key_len = ast_base64decode(remote_key, p->local_key64, sizeof(remote_key)); + + if (p->key_len != key_len) { + ast_log(LOG_ERROR, "base64 encode/decode bad len %d != %d\n", p->key_len, key_len); return NULL; } - p->tag = 1; - if (res_srtp->get_random(p->local_key, sizeof(p->local_key)) < 0) { - ast_sdp_crypto_destroy(p); + if (memcmp(remote_key, p->local_key, p->key_len)) { + ast_log(LOG_ERROR, "base64 encode/decode bad key\n"); return NULL; } - ast_base64encode(p->local_key64, p->local_key, SRTP_MASTER_LEN, sizeof(p->local_key64)); + ast_debug(1 , "local_key64 %s len %zu\n", p->local_key64, strlen(p->local_key64)); - key_len = ast_base64decode(remote_key, p->local_key64, sizeof(remote_key)); + return p; +} - if (key_len != SRTP_MASTER_LEN) { - ast_log(LOG_ERROR, "base64 encode/decode bad len %d != %d\n", key_len, SRTP_MASTER_LEN); - ast_sdp_crypto_destroy(p); +static struct ast_sdp_crypto *sdp_crypto_alloc(const int key_len) +{ + struct ast_sdp_crypto *p, *result; + + if (!ast_rtp_engine_srtp_is_registered()) { return NULL; } - if (memcmp(remote_key, p->local_key, SRTP_MASTER_LEN)) { - ast_log(LOG_ERROR, "base64 encode/decode bad key\n"); - ast_sdp_crypto_destroy(p); + if (!(p = ast_calloc(1, sizeof(*p)))) { return NULL; } + p->tag = 1; - ast_debug(1 , "local_key64 %s len %zu\n", p->local_key64, strlen(p->local_key64)); + /* default is a key which uses AST_AES_CM_128_HMAC_SHA1_xx */ + result = crypto_init_keys(p, key_len); + if (!result) { + ast_sdp_crypto_destroy(p); + } - return p; + return result; } -static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, unsigned long ssrc, int inbound) +struct ast_sdp_crypto *ast_sdp_crypto_alloc(void) { - const unsigned char *master_salt = NULL; + return sdp_crypto_alloc(SRTP_MASTER_KEY_LEN); +} +static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, int key_len, unsigned long ssrc, int inbound) +{ if (!ast_rtp_engine_srtp_is_registered()) { return -1; } - master_salt = master_key + SRTP_MASTERKEY_LEN; - if (res_srtp_policy->set_master_key(policy, master_key, SRTP_MASTERKEY_LEN, master_salt, SRTP_MASTERSALT_LEN) < 0) { + if (res_srtp_policy->set_master_key(policy, master_key, key_len, NULL, 0) < 0) { return -1; } @@ -147,7 +165,7 @@ static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, cons return 0; } -static int crypto_activate(struct ast_sdp_crypto *p, int suite_val, unsigned char *remote_key, struct ast_rtp_instance *rtp) +static int crypto_activate(struct ast_sdp_crypto *p, int suite_val, unsigned char *remote_key, int key_len, struct ast_rtp_instance *rtp) { struct ast_srtp_policy *local_policy = NULL; struct ast_srtp_policy *remote_policy = NULL; @@ -174,11 +192,11 @@ static int crypto_activate(struct ast_sdp_crypto *p, int suite_val, unsigned cha goto err; } - if (set_crypto_policy(local_policy, suite_val, p->local_key, stats.local_ssrc, 0) < 0) { + if (set_crypto_policy(local_policy, suite_val, p->local_key, key_len, stats.local_ssrc, 0) < 0) { goto err; } - if (set_crypto_policy(remote_policy, suite_val, remote_key, 0, 1) < 0) { + if (set_crypto_policy(remote_policy, suite_val, remote_key, key_len, 0, 1) < 0) { goto err; } @@ -215,12 +233,15 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr char *lifetime = NULL; /* Key lifetime (# of RTP packets) */ char *mki = NULL; /* Master Key Index */ int found = 0; - int key_len = 0; + int key_len_from_sdp; + int key_len_expected; + int tag_from_sdp; int suite_val = 0; - unsigned char remote_key[SRTP_MASTER_LEN]; - int taglen = 0; + unsigned char remote_key[SRTP_MAX_KEY_LEN]; + int taglen; double sdes_lifetime; - struct ast_sdp_crypto *crypto = srtp->crypto; + struct ast_sdp_crypto *crypto; + struct ast_sdp_srtp *tmp; if (!ast_rtp_engine_srtp_is_registered()) { return -1; @@ -239,7 +260,7 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr } /* RFC4568 9.1 - tag is 1-9 digits, greater than zero */ - if (sscanf(tag, "%30d", &crypto->tag) != 1 || crypto->tag <= 0 || crypto->tag > 999999999) { + if (sscanf(tag, "%30d", &tag_from_sdp) != 1 || tag_from_sdp <= 0 || tag_from_sdp > 999999999) { ast_log(LOG_WARNING, "Unacceptable a=crypto tag: %s\n", tag); return -1; } @@ -249,16 +270,107 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr return -1; } + /* On egress, Asterisk sent several crypto lines in the SIP/SDP offer + The remote party might have choosen another line than the first */ + for (tmp = srtp; tmp && tmp->crypto && tmp->crypto->tag != tag_from_sdp;) { + tmp = AST_LIST_NEXT(tmp, sdp_srtp_list); + } + if (tmp) { /* tag matched an already created crypto line */ + unsigned int flags = tmp->flags; + + /* Make that crypto line the head of the list, not by changing the + list structure but by exchanging the content of the list members */ + crypto = tmp->crypto; + tmp->crypto = srtp->crypto; + tmp->flags = srtp->flags; + srtp->crypto = crypto; + srtp->flags = flags; + } else { + crypto = srtp->crypto; + crypto->tag = tag_from_sdp; + } + if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80")) { suite_val = AST_AES_CM_128_HMAC_SHA1_80; ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); - taglen = 80; + key_len_expected = 30; } else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) { suite_val = AST_AES_CM_128_HMAC_SHA1_32; ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); - taglen = 32; + key_len_expected = 30; +#ifdef HAVE_SRTP_192 + } else if (!strcmp(suite, "AES_192_CM_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + key_len_expected = 38; + } else if (!strcmp(suite, "AES_192_CM_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + key_len_expected = 38; + /* RFC used a different name while in draft, some still use that */ + } else if (!strcmp(suite, "AES_CM_192_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 38; + } else if (!strcmp(suite, "AES_CM_192_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 38; +#endif +#ifdef HAVE_SRTP_256 + } else if (!strcmp(suite, "AES_256_CM_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = 46; + } else if (!strcmp(suite, "AES_256_CM_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = 46; + /* RFC used a different name while in draft, some still use that */ + } else if (!strcmp(suite, "AES_CM_256_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 46; + } else if (!strcmp(suite, "AES_CM_256_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 46; +#endif +#ifdef HAVE_SRTP_GCM + } else if (!strcmp(suite, "AEAD_AES_128_GCM")) { + suite_val = AST_AES_GCM_128; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_16); + key_len_expected = AES_128_GCM_KEYSIZE_WSALT; + } else if (!strcmp(suite, "AEAD_AES_256_GCM")) { + suite_val = AST_AES_GCM_256; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_16); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = AES_256_GCM_KEYSIZE_WSALT; + /* RFC contained a (too) short auth tag for RTP media, some still use that */ + } else if (!strcmp(suite, "AEAD_AES_128_GCM_8")) { + suite_val = AST_AES_GCM_128_8; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_8); + key_len_expected = AES_128_GCM_KEYSIZE_WSALT; + } else if (!strcmp(suite, "AEAD_AES_256_GCM_8")) { + suite_val = AST_AES_GCM_256_8; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_8); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = AES_256_GCM_KEYSIZE_WSALT; +#endif } else { - ast_log(LOG_WARNING, "Unsupported crypto suite: %s\n", suite); + ast_verb(1, "Unsupported crypto suite: %s\n", suite); return -1; } @@ -341,23 +453,55 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr return -1; } - key_len = ast_base64decode(remote_key, key_salt, sizeof(remote_key)); - if (key_len != SRTP_MASTER_LEN) { - ast_log(LOG_WARNING, "SRTP descriptions key length '%d' != master length '%d'\n", - key_len, SRTP_MASTER_LEN); + key_len_from_sdp = ast_base64decode(remote_key, key_salt, sizeof(remote_key)); + if (key_len_from_sdp != key_len_expected) { + ast_log(LOG_WARNING, "SRTP descriptions key length is '%d', not '%d'\n", + key_len_from_sdp, key_len_expected); return -1; } - if (!memcmp(crypto->remote_key, remote_key, sizeof(crypto->remote_key))) { + /* on default, the key is 30 (AES-128); throw that away (only) when the suite changed actually */ + /* ingress: optional, but saves one expensive call to get_random(.) */ + /* egress: required, because the local key was communicated before the remote key is processed */ + if (crypto->key_len != key_len_from_sdp) { + if (!crypto_init_keys(crypto, key_len_from_sdp)) { + return -1; + } + } else if (!memcmp(crypto->remote_key, remote_key, key_len_from_sdp)) { ast_debug(1, "SRTP remote key unchanged; maintaining current policy\n"); ast_set_flag(srtp, AST_SRTP_CRYPTO_OFFER_OK); return 0; } - memcpy(crypto->remote_key, remote_key, sizeof(crypto->remote_key)); - if (crypto_activate(crypto, suite_val, remote_key, rtp) < 0) { + if (key_len_from_sdp > sizeof(crypto->remote_key)) { + ast_log(LOG_ERROR, + "SRTP key buffer is %zu although it must be at least %d bytes\n", + sizeof(crypto->remote_key), key_len_from_sdp); return -1; } + memcpy(crypto->remote_key, remote_key, key_len_from_sdp); + + if (crypto_activate(crypto, suite_val, remote_key, key_len_from_sdp, rtp) < 0) { + return -1; + } + + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_32)) { + taglen = 32; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_16)) { + taglen = 16; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_8)) { + taglen = 8; + } else { + taglen = 80; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_256)) { + taglen |= 0x0200; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_192)) { + taglen |= 0x0100; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME)) { + taglen |= 0x0080; + } /* Finally, rebuild the crypto line */ if (ast_sdp_crypto_build_offer(crypto, taglen)) { @@ -375,10 +519,30 @@ int ast_sdp_crypto_build_offer(struct ast_sdp_crypto *p, int taglen) ast_free(p->a_crypto); } - if (ast_asprintf(&p->a_crypto, "%d AES_CM_128_HMAC_SHA1_%i inline:%s", - p->tag, taglen, p->local_key64) == -1) { - ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); - return -1; + if ((taglen & 0x007f) == 8) { + if (ast_asprintf(&p->a_crypto, "%d AEAD_AES_%d_GCM_%d inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64) == -1) { + ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); + return -1; + } + } else if ((taglen & 0x007f) == 16) { + if (ast_asprintf(&p->a_crypto, "%d AEAD_AES_%d_GCM inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), p->local_key64) == -1) { + ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); + return -1; + } + } else if ((taglen & 0x0300) && !(taglen & 0x0080)) { + if (ast_asprintf(&p->a_crypto, "%d AES_%d_CM_HMAC_SHA1_%d inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64) == -1) { + ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); + return -1; + } + } else { + if (ast_asprintf(&p->a_crypto, "%d AES_CM_%d_HMAC_SHA1_%d inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64) == -1) { + ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); + return -1; + } } ast_debug(1, "Crypto line: a=crypto:%s\n", p->a_crypto); @@ -388,7 +552,7 @@ int ast_sdp_crypto_build_offer(struct ast_sdp_crypto *p, int taglen) const char *ast_sdp_srtp_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32) { - int taglen = default_taglen_32 ? 32 : 80; + int taglen; if (!srtp) { return NULL; @@ -396,7 +560,72 @@ const char *ast_sdp_srtp_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, /* Set encryption properties */ if (!srtp->crypto) { - srtp->crypto = ast_sdp_crypto_alloc(); + + if (AST_LIST_NEXT(srtp, sdp_srtp_list)) { + srtp->crypto = ast_sdp_crypto_alloc(); + ast_log(LOG_ERROR, "SRTP SDP list was not empty\n"); + } else { + const int len = default_taglen_32 ? AST_SRTP_CRYPTO_TAG_32 : AST_SRTP_CRYPTO_TAG_80; + const int attr[][3] = { + /* This array creates the following list: + * a=crypto:1 AES_CM_128_HMAC_SHA1_ ... + * a=crypto:2 AEAD_AES_128_GCM ... + * a=crypto:3 AES_256_CM_HMAC_SHA1_ ... + * a=crypto:4 AEAD_AES_256_GCM ... + * a=crypto:5 AES_192_CM_HMAC_SHA1_ ... + * something like 'AEAD_AES_192_GCM' is not specified by the RFCs + * + * If you want to prefer another crypto suite or you want to + * exclude a suite, change this array and recompile Asterisk. + * This list cannot be changed from rtp.conf because you should + * know what you are doing. Especially AES-192 and AES-GCM are + * broken in many VoIP clients, see + * https://github.com/cisco/libsrtp/pull/170 + * https://github.com/cisco/libsrtp/pull/184 + * Furthermore, AES-GCM uses a shorter crypto-suite string which + * causes Nokia phones based on Symbian/S60 to reject the whole + * INVITE with status 500, even if a matching suite was offered. + * AES-256 might just waste your processor cycles, especially if + * your TLS transport is not secured with equivalent grade, see + * https://security.stackexchange.com/q/61361 + * Therefore, AES-128 was preferred here. + * + * If you want to enable one of those defines, please, go for + * CFLAGS='-DENABLE_SRTP_AES_GCM' ./configure && sudo make install + */ + { len, 0, 30 }, +#if defined(HAVE_SRTP_GCM) && defined(ENABLE_SRTP_AES_GCM) + { AST_SRTP_CRYPTO_TAG_16, 0, AES_128_GCM_KEYSIZE_WSALT }, +#endif +#if defined(HAVE_SRTP_256) && defined(ENABLE_SRTP_AES_256) + { len, AST_SRTP_CRYPTO_AES_256, 46 }, +#endif +#if defined(HAVE_SRTP_GCM) && defined(ENABLE_SRTP_AES_GCM) && defined(ENABLE_SRTP_AES_256) + { AST_SRTP_CRYPTO_TAG_16, AST_SRTP_CRYPTO_AES_256, AES_256_GCM_KEYSIZE_WSALT }, +#endif +#if defined(HAVE_SRTP_192) && defined(ENABLE_SRTP_AES_192) + { len, AST_SRTP_CRYPTO_AES_192, 38 }, +#endif + }; + struct ast_sdp_srtp *tmp = srtp; + int i; + + for (i = 0; i < ARRAY_LEN(attr); i++) { + if (attr[i][0]) { + ast_set_flag(tmp, attr[i][0]); + } + if (attr[i][1]) { + ast_set_flag(tmp, attr[i][1]); + } + tmp->crypto = sdp_crypto_alloc(attr[i][2]); /* key_len */ + tmp->crypto->tag = (i + 1); /* tag starts at 1 */ + + if (i < ARRAY_LEN(attr) - 1) { + AST_LIST_NEXT(tmp, sdp_srtp_list) = ast_sdp_srtp_alloc(); + tmp = AST_LIST_NEXT(tmp, sdp_srtp_list); + } + } + } } if (dtls_enabled) { @@ -409,6 +638,20 @@ const char *ast_sdp_srtp_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, taglen = 80; } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_32)) { taglen = 32; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_16)) { + taglen = 16; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_8)) { + taglen = 8; + } else { + taglen = default_taglen_32 ? 32 : 80; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_256)) { + taglen |= 0x0200; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_192)) { + taglen |= 0x0100; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME)) { + taglen |= 0x0080; } if (srtp->crypto && (ast_sdp_crypto_build_offer(srtp->crypto, taglen) >= 0)) { |