mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-23 12:42:02 +00:00
Merge pull request #1 in FSA/freeswitch-advantage from ~PIOTRGREGOR/freeswitch:feature/FS-10778-srtp-mki-support to v1.8-fsa
* commit '6520827b620951b8e016cbaaa4d321261e3ea3e2': FS-10778: Add support for MKI to SRTP
This commit is contained in:
@@ -44,7 +44,6 @@ SWITCH_BEGIN_EXTERN_C
|
||||
#define SWITCH_RTP_MAX_BUF_LEN 16384
|
||||
#define SWITCH_RTCP_MAX_BUF_LEN 16384
|
||||
#define SWITCH_RTP_MAX_BUF_LEN_WORDS 4094 /* (max / 4) - 2 */
|
||||
#define SWITCH_RTP_MAX_CRYPTO_LEN 64
|
||||
//#define SWITCH_RTP_KEY_LEN 30
|
||||
//#define SWITCH_RTP_CRYPTO_KEY_32 "AES_CM_128_HMAC_SHA1_32"
|
||||
#define SWITCH_RTP_CRYPTO_KEY_80 "AES_CM_128_HMAC_SHA1_80"
|
||||
@@ -67,14 +66,16 @@ typedef enum {
|
||||
typedef struct switch_srtp_crypto_suite_s {
|
||||
char *name;
|
||||
switch_rtp_crypto_key_type_t type;
|
||||
int keylen;
|
||||
int keysalt_len;
|
||||
int salt_len;
|
||||
} switch_srtp_crypto_suite_t;
|
||||
|
||||
extern switch_srtp_crypto_suite_t SUITES[CRYPTO_INVALID];
|
||||
|
||||
struct switch_rtp_crypto_key {
|
||||
uint32_t index;
|
||||
switch_rtp_crypto_key_type_t type;
|
||||
unsigned char key[SWITCH_RTP_MAX_CRYPTO_LEN];
|
||||
unsigned char keysalt[SWITCH_RTP_MAX_CRYPTO_LEN];
|
||||
switch_size_t keylen;
|
||||
struct switch_rtp_crypto_key *next;
|
||||
};
|
||||
@@ -170,9 +171,7 @@ typedef enum { /* FMT Values for PSFB Payload Types http://www.iana.org/assignme
|
||||
|
||||
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_session,
|
||||
switch_rtp_crypto_direction_t direction,
|
||||
uint32_t index, switch_rtp_crypto_key_type_t type, unsigned char *key, switch_size_t keylen);
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_session, switch_rtp_crypto_direction_t direction, uint32_t index, switch_secure_settings_t *ssec);
|
||||
|
||||
///\defgroup rtp RTP (RealTime Transport Protocol)
|
||||
///\ingroup core1
|
||||
|
||||
@@ -779,6 +779,8 @@ typedef enum {
|
||||
SWITCH_RTP_FLAG_TEXT,
|
||||
SWITCH_RTP_FLAG_OLD_FIR,
|
||||
SWITCH_RTP_FLAG_PASSTHRU,
|
||||
SWITCH_RTP_FLAG_SECURE_SEND_MKI,
|
||||
SWITCH_RTP_FLAG_SECURE_RECV_MKI,
|
||||
SWITCH_RTP_FLAG_INVALID
|
||||
} switch_rtp_flag_t;
|
||||
|
||||
@@ -2566,6 +2568,12 @@ typedef enum {
|
||||
CRYPTO_INVALID
|
||||
} switch_rtp_crypto_key_type_t;
|
||||
|
||||
/* Keep in sync with CRYPTO_KEY_PARAM_METHOD table. */
|
||||
typedef enum {
|
||||
CRYPTO_KEY_PARAM_METHOD_INLINE, /* identified by "inline" chars in SRTP key parameter */
|
||||
CRYPTO_KEY_PARAM_METHOD_INVALID
|
||||
} switch_rtp_crypto_key_param_method_type_t;
|
||||
|
||||
typedef struct payload_map_s {
|
||||
switch_media_type_t type;
|
||||
switch_sdp_type_t sdp_type;
|
||||
@@ -2709,6 +2717,56 @@ typedef struct switch_mm_s {
|
||||
char *auth_password;
|
||||
} switch_mm_t;
|
||||
|
||||
#define SWITCH_RTP_MAX_CRYPTO_LEN 64
|
||||
|
||||
/* If MKI is used, then one or more key-materials are present in the <key-params> section of the crypto attribute.
|
||||
* This struct describes the single MKI entry (key-material) within <key-params> section of crypto attribute.
|
||||
* Key-material follows the format:
|
||||
* "inline:" <key||salt> ["|" lifetime] ["|" MKI ":" length]
|
||||
* which translates to
|
||||
* "inline: KEYSALT|MKI_ID:MKI_SZ" or "inline: KEYSALT|LIFETIME|MKI_ID:MKI_SZ" */
|
||||
typedef struct switch_crypto_key_material_s {
|
||||
switch_rtp_crypto_key_param_method_type_t method;
|
||||
unsigned char raw_key[SWITCH_RTP_MAX_CRYPTO_LEN]; /* Key-salt. Master key appended with salt. Sizes determined by crypto suite. */
|
||||
char *crypto_key; /* Complete key material string ("method:keysalt[|lifetime]|mki"). */
|
||||
uint64_t lifetime; /* OPTIONAL. The lifetime value MAY be written as a non-zero, positive decimal integer or as a power of 2. Must be less than max lifetime of RTP and RTCP packets in given crypto suite. */
|
||||
unsigned int mki_id; /* OPTIONAL. */
|
||||
unsigned int mki_size; /* OPTIONAL. Byte length of the master key field in the RTP packet. */
|
||||
struct switch_crypto_key_material_s *next; /* NULL if this is the last master key in crypto attribute set. */
|
||||
} switch_crypto_key_material_t;
|
||||
|
||||
typedef struct secure_settings_s {
|
||||
int crypto_tag;
|
||||
unsigned char local_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN];
|
||||
unsigned char remote_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN];
|
||||
switch_rtp_crypto_key_type_t crypto_type;
|
||||
char *local_crypto_key;
|
||||
char *remote_crypto_key;
|
||||
|
||||
/*
|
||||
* MKI support (as per rfc4568).
|
||||
* Normally single crypto attribute contains one key-material in a <key-params> section, e.g. "inline: KEYSALT" or "inline: KEYSALT|2^LIFETIME_BITS".
|
||||
* But if MKI is used, then one or more key-materials are present in the <key-params> section of the crypto attribute. Each key-material follows the format:
|
||||
*
|
||||
* "inline:" <key||salt> ["|" lifetime] ["|" MKI ":" length]
|
||||
*
|
||||
* "inline: KEYSALT|MKI_ID:MKI_SZ"
|
||||
* or
|
||||
* "inline: KEYSALT|2^LIFETIME_BITS|MKI_ID:MKI_SZ"
|
||||
*
|
||||
* This points to singly linked list of key-material descriptions if there is more than one key-material present in this crypto attribute (this key is inserted as the head of the list in that case), or to NULL otherwise.
|
||||
*/
|
||||
struct switch_crypto_key_material_s *local_key_material_next; /* NULL if MKI not used for crypto set on outbound SRTP. */
|
||||
unsigned long local_key_material_n; /* number of key_materials in the linked list for outbound SRTP */
|
||||
struct switch_crypto_key_material_s *remote_key_material_next; /* NULL if MKI not used for crypto set on inbound SRTP. */
|
||||
unsigned long remote_key_material_n; /* number of key_materials in the linked list for inbound SRTP */
|
||||
} switch_secure_settings_t;
|
||||
|
||||
/* Default MKI index used for packets send from FS. We always use first key if multiple master keys are present in the crypto attribute. */
|
||||
#define SWITCH_CRYPTO_MKI_INDEX 0
|
||||
|
||||
/* max number of MKI in a single crypto line supported */
|
||||
#define SWITCH_CRYPTO_MKI_MAX 20
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
#endif
|
||||
|
||||
@@ -391,7 +391,7 @@ static inline int switch_string_has_escaped_data(const char *in)
|
||||
#endif
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_b64_encode(unsigned char *in, switch_size_t ilen, unsigned char *out, switch_size_t olen);
|
||||
SWITCH_DECLARE(switch_size_t) switch_b64_decode(char *in, char *out, switch_size_t olen);
|
||||
SWITCH_DECLARE(switch_size_t) switch_b64_decode(const char *in, char *out, switch_size_t olen);
|
||||
SWITCH_DECLARE(char *) switch_amp_encode(char *s, char *buf, switch_size_t len);
|
||||
|
||||
|
||||
|
||||
+385
-81
@@ -64,16 +64,6 @@ typedef enum {
|
||||
SMF_VB_PAUSED = (1 << 3)
|
||||
} smh_flag_t;
|
||||
|
||||
|
||||
typedef struct secure_settings_s {
|
||||
int crypto_tag;
|
||||
unsigned char local_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN];
|
||||
unsigned char remote_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN];
|
||||
switch_rtp_crypto_key_type_t crypto_type;
|
||||
char *local_crypto_key;
|
||||
char *remote_crypto_key;
|
||||
} switch_secure_settings_t;
|
||||
|
||||
typedef struct core_video_globals_s {
|
||||
int cpu_count;
|
||||
int cur_cpu;
|
||||
@@ -282,16 +272,16 @@ struct switch_media_handle_s {
|
||||
|
||||
};
|
||||
|
||||
static switch_srtp_crypto_suite_t SUITES[CRYPTO_INVALID] = {
|
||||
{ "AEAD_AES_256_GCM_8", AEAD_AES_256_GCM_8, 44},
|
||||
{ "AEAD_AES_128_GCM_8", AEAD_AES_128_GCM_8, 28},
|
||||
{ "AES_CM_256_HMAC_SHA1_80", AES_CM_256_HMAC_SHA1_80, 46},
|
||||
{ "AES_CM_192_HMAC_SHA1_80", AES_CM_192_HMAC_SHA1_80, 38},
|
||||
{ "AES_CM_128_HMAC_SHA1_80", AES_CM_128_HMAC_SHA1_80, 30},
|
||||
{ "AES_CM_256_HMAC_SHA1_32", AES_CM_256_HMAC_SHA1_32, 46},
|
||||
{ "AES_CM_192_HMAC_SHA1_32", AES_CM_192_HMAC_SHA1_32, 38},
|
||||
{ "AES_CM_128_HMAC_SHA1_32", AES_CM_128_HMAC_SHA1_32, 30},
|
||||
{ "AES_CM_128_NULL_AUTH", AES_CM_128_NULL_AUTH, 30}
|
||||
switch_srtp_crypto_suite_t SUITES[CRYPTO_INVALID] = {
|
||||
{ "AEAD_AES_256_GCM_8", AEAD_AES_256_GCM_8, 44, 12},
|
||||
{ "AEAD_AES_128_GCM_8", AEAD_AES_128_GCM_8, 28, 12},
|
||||
{ "AES_CM_256_HMAC_SHA1_80", AES_CM_256_HMAC_SHA1_80, 46, 14},
|
||||
{ "AES_CM_192_HMAC_SHA1_80", AES_CM_192_HMAC_SHA1_80, 38, 14},
|
||||
{ "AES_CM_128_HMAC_SHA1_80", AES_CM_128_HMAC_SHA1_80, 30, 14},
|
||||
{ "AES_CM_256_HMAC_SHA1_32", AES_CM_256_HMAC_SHA1_32, 46, 14},
|
||||
{ "AES_CM_192_HMAC_SHA1_32", AES_CM_192_HMAC_SHA1_32, 38, 14},
|
||||
{ "AES_CM_128_HMAC_SHA1_32", AES_CM_128_HMAC_SHA1_32, 30, 14},
|
||||
{ "AES_CM_128_NULL_AUTH", AES_CM_128_NULL_AUTH, 30, 14}
|
||||
};
|
||||
|
||||
SWITCH_DECLARE(switch_rtp_crypto_key_type_t) switch_core_media_crypto_str2type(const char *str)
|
||||
@@ -315,12 +305,16 @@ SWITCH_DECLARE(const char *) switch_core_media_crypto_type2str(switch_rtp_crypto
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(int) switch_core_media_crypto_keylen(switch_rtp_crypto_key_type_t type)
|
||||
SWITCH_DECLARE(int) switch_core_media_crypto_keysalt_len(switch_rtp_crypto_key_type_t type)
|
||||
{
|
||||
switch_assert(type < CRYPTO_INVALID);
|
||||
return SUITES[type].keylen;
|
||||
return SUITES[type].keysalt_len;
|
||||
}
|
||||
|
||||
static const char* CRYPTO_KEY_PARAM_METHOD[CRYPTO_KEY_PARAM_METHOD_INVALID] = {
|
||||
[CRYPTO_KEY_PARAM_METHOD_INLINE] = "inline",
|
||||
};
|
||||
|
||||
static inline switch_media_flow_t sdp_media_flow(unsigned in)
|
||||
{
|
||||
switch(in) {
|
||||
@@ -1161,16 +1155,14 @@ static switch_status_t switch_core_media_build_crypto(switch_media_handle_t *smh
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//#define SAME_KEY
|
||||
#ifdef SAME_KEY
|
||||
if (switch_channel_test_flag(channel, CF_AVPF) && type == SWITCH_MEDIA_TYPE_VIDEO) {
|
||||
if (direction == SWITCH_RTP_CRYPTO_SEND) {
|
||||
memcpy(engine->ssec[ctype].local_raw_key, smh->engines[SWITCH_MEDIA_TYPE_AUDIO].ssec.local_raw_key, SUITES[ctype].keylen);
|
||||
memcpy(engine->ssec[ctype].local_raw_key, smh->engines[SWITCH_MEDIA_TYPE_AUDIO].ssec.local_raw_key, SUITES[ctype].keysalt_len);
|
||||
key = engine->ssec[ctype].local_raw_key;
|
||||
} else {
|
||||
memcpy(engine->ssec[ctype].remote_raw_key, smh->engines[SWITCH_MEDIA_TYPE_AUDIO].ssec.remote_raw_key, SUITES[ctype].keylen);
|
||||
memcpy(engine->ssec[ctype].remote_raw_key, smh->engines[SWITCH_MEDIA_TYPE_AUDIO].ssec.remote_raw_key, SUITES[ctype].keysalt_len);
|
||||
key = engine->ssec[ctype].remote_raw_key;
|
||||
}
|
||||
} else {
|
||||
@@ -1181,12 +1173,12 @@ static switch_status_t switch_core_media_build_crypto(switch_media_handle_t *smh
|
||||
key = engine->ssec[ctype].remote_raw_key;
|
||||
}
|
||||
|
||||
switch_rtp_get_random(key, SUITES[ctype].keylen);
|
||||
switch_rtp_get_random(key, SUITES[ctype].keysalt_len);
|
||||
#ifdef SAME_KEY
|
||||
}
|
||||
#endif
|
||||
|
||||
switch_b64_encode(key, SUITES[ctype].keylen, b64_key, sizeof(b64_key));
|
||||
switch_b64_encode(key, SUITES[ctype].keysalt_len, b64_key, sizeof(b64_key));
|
||||
if (!switch_channel_var_true(channel, "rtp_pad_srtp_keys")) {
|
||||
p = strrchr((char *) b64_key, '=');
|
||||
|
||||
@@ -1197,7 +1189,12 @@ static switch_status_t switch_core_media_build_crypto(switch_media_handle_t *smh
|
||||
|
||||
if (index == SWITCH_NO_CRYPTO_TAG) index = ctype + 1;
|
||||
|
||||
engine->ssec[ctype].local_crypto_key = switch_core_session_sprintf(smh->session, "%d %s inline:%s", index, SUITES[ctype].name, b64_key);
|
||||
if (switch_channel_get_variable(channel, "rtp_secure_media_mki")) {
|
||||
engine->ssec[ctype].local_crypto_key = switch_core_session_sprintf(smh->session, "%d %s inline:%s|2^31|1:1", index, SUITES[ctype].name, b64_key);
|
||||
} else {
|
||||
engine->ssec[ctype].local_crypto_key = switch_core_session_sprintf(smh->session, "%d %s inline:%s", index, SUITES[ctype].name, b64_key);
|
||||
}
|
||||
|
||||
switch_channel_set_variable_name_printf(smh->session->channel, engine->ssec[ctype].local_crypto_key, "rtp_last_%s_local_crypto_key", type2str(type));
|
||||
switch_channel_set_flag(smh->session->channel, CF_SECURE);
|
||||
|
||||
@@ -1216,17 +1213,180 @@ static switch_status_t switch_core_media_build_crypto(switch_media_handle_t *smh
|
||||
}
|
||||
|
||||
|
||||
#define CRYPTO_KEY_MATERIAL_LIFETIME_MKI_ERR 0x0u
|
||||
#define CRYPTO_KEY_MATERIAL_MKI 0x1u
|
||||
#define CRYPTO_KEY_MATERIAL_LIFETIME 0x2u
|
||||
|
||||
#define RAW_BITS_PER_64_ENCODED_CHAR 6
|
||||
|
||||
/* Return uint32_t which contains all the info about the field found:
|
||||
* XXXXXXXa | YYYYYYYY | YYYYYYYY | ZZZZZZZZ
|
||||
* where:
|
||||
* a - CRYPTO_KEY_MATERIAL_LIFETIME if LIFETIME, CRYPTO_KEY_MATERIAL_MKI if MKI
|
||||
* YYYYYYYY and ZZZZZZZZ - depend on 'a':
|
||||
* if a is LIFETIME then YYYYYYYY is decimal Base, ZZZZZZZZ is decimal Exponent
|
||||
* if a is MKI, then YYYYYYYY is decimal MKI_ID, ZZZZZZZZ is decimal MKI_SIZE
|
||||
*/
|
||||
static uint32_t parse_lifetime_mki(const char **p, const char *end)
|
||||
{
|
||||
const char *field_begin;
|
||||
const char *field_end;
|
||||
const char *sep, *space;
|
||||
uint32_t res = 0;
|
||||
|
||||
switch_status_t switch_core_media_add_crypto(switch_secure_settings_t *ssec, const char *key_str, switch_rtp_crypto_direction_t direction)
|
||||
uint32_t val = 0;
|
||||
int i;
|
||||
|
||||
switch_assert(*p != NULL);
|
||||
switch_assert(end != NULL);
|
||||
|
||||
field_begin = strchr(*p, '|');
|
||||
|
||||
if (field_begin && (field_begin + 1 < end)) {
|
||||
space = strchr(field_begin, ' ');
|
||||
field_end = strchr(field_begin + 2, '|');
|
||||
|
||||
if (!field_end) {
|
||||
field_end = end;
|
||||
}
|
||||
|
||||
if (space) {
|
||||
if ((field_end == NULL) || (space < field_end)) {
|
||||
field_end = space;
|
||||
}
|
||||
}
|
||||
|
||||
if (field_end) {
|
||||
/* Closing '|' found. */
|
||||
sep = strchr(field_begin, ':'); /* The lifetime field never includes a colon, whereas the third field always does. (RFC 4568) */
|
||||
if (sep && (sep + 1 < field_end) && isdigit(*(sep + 1))) {
|
||||
res |= (CRYPTO_KEY_MATERIAL_MKI << 24);
|
||||
|
||||
for (i = 1, *p = sep - 1; *p != field_begin; --(*p), i *= 10) {
|
||||
val += ((**p) - '0') * i;
|
||||
}
|
||||
|
||||
res |= ((val << 8) & 0x00ffff00); /* MKI_ID */
|
||||
|
||||
val = 0;
|
||||
for (i = 1, *p = field_end - 1; *p != sep; --(*p), i *= 10) {
|
||||
val += ((**p) - '0') * i;
|
||||
}
|
||||
res |= (val & 0x000000ff); /* MKI_SIZE */
|
||||
} else if (isdigit(*(field_begin + 1)) && (field_begin + 2) && (*(field_begin + 2) == '^') && (field_begin + 3) && isdigit(*(field_begin + 3))) {
|
||||
res |= (CRYPTO_KEY_MATERIAL_LIFETIME << 24);
|
||||
val = ((uint32_t) (*(field_begin + 1) - '0')) << 8;
|
||||
res |= val; /* LIFETIME base. */
|
||||
|
||||
val = 0;
|
||||
for (i = 1, *p = field_end - 1; *p != (field_begin + 2); --(*p), i *= 10) {
|
||||
val += ((**p) - '0') * i;
|
||||
}
|
||||
|
||||
res |= (val & 0x000000ff); /* LIFETIME exponent. */
|
||||
}
|
||||
}
|
||||
|
||||
*p = field_end;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static switch_crypto_key_material_t* switch_core_media_crypto_append_key_material(
|
||||
switch_core_session_t *session,
|
||||
switch_crypto_key_material_t *tail,
|
||||
switch_rtp_crypto_key_param_method_type_t method,
|
||||
unsigned char raw_key[SWITCH_RTP_MAX_CRYPTO_LEN],
|
||||
int raw_key_len,
|
||||
const char *key_material,
|
||||
int key_material_len,
|
||||
uint64_t lifetime,
|
||||
unsigned int mki_id,
|
||||
unsigned int mki_size)
|
||||
{
|
||||
struct switch_crypto_key_material_s *new_key_material;
|
||||
|
||||
new_key_material = switch_core_session_alloc(session, (sizeof(*new_key_material)));
|
||||
if (new_key_material == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new_key_material->method = method;
|
||||
memcpy(new_key_material->raw_key, raw_key, raw_key_len);
|
||||
new_key_material->crypto_key = switch_core_session_strdup(session, key_material);
|
||||
new_key_material->lifetime = lifetime;
|
||||
new_key_material->mki_id = mki_id;
|
||||
new_key_material->mki_size = mki_size;
|
||||
|
||||
new_key_material->next = tail;
|
||||
|
||||
return new_key_material;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip all space and return pointer to the '\0' terminator of the char string candidate to be a key-material
|
||||
* or pointer to first ' ' in the candidate string.
|
||||
*/
|
||||
static const char* switch_core_media_crypto_find_key_material_candidate_end(const char *p)
|
||||
{
|
||||
const char *end;
|
||||
|
||||
switch_assert(p != NULL);
|
||||
|
||||
if (p) {
|
||||
end = strchr(p, ' '); /* find the end of the continuous string of characters in the candidate string */
|
||||
if (end == NULL)
|
||||
end = p + strlen(p);
|
||||
}
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
switch_status_t switch_core_media_add_crypto(switch_core_session_t *session, switch_secure_settings_t *ssec, switch_rtp_crypto_direction_t direction)
|
||||
{
|
||||
unsigned char key[SWITCH_RTP_MAX_CRYPTO_LEN];
|
||||
switch_rtp_crypto_key_type_t type;
|
||||
char *p;
|
||||
|
||||
const char *p, *delimit;
|
||||
const char *key_material_begin;
|
||||
const char *key_material_end; /* begin and end of the current key material candidate */
|
||||
int method_len;
|
||||
int keysalt_len;
|
||||
|
||||
const char *opts;
|
||||
uint32_t opt_field; /* LIFETIME or MKI */
|
||||
switch_rtp_crypto_key_param_method_type_t method = CRYPTO_KEY_PARAM_METHOD_INLINE;
|
||||
uint64_t lifetime = 0;
|
||||
uint16_t lifetime_base = 0;
|
||||
uint16_t lifetime_exp = 0;
|
||||
uint16_t mki_id = 0;
|
||||
uint16_t mki_size = 0;
|
||||
switch_crypto_key_material_t *key_material = NULL;
|
||||
unsigned long *key_material_n = NULL;
|
||||
|
||||
bool multiple_keys = false;
|
||||
|
||||
const char *key_param;
|
||||
|
||||
|
||||
p = strchr(key_str, ' ');
|
||||
if (direction == SWITCH_RTP_CRYPTO_SEND || direction == SWITCH_RTP_CRYPTO_SEND_RTCP) {
|
||||
key_param = ssec->local_crypto_key;
|
||||
key_material = ssec->local_key_material_next;
|
||||
key_material_n = &ssec->local_key_material_n;
|
||||
} else {
|
||||
key_param = ssec->remote_crypto_key;
|
||||
key_material = ssec->remote_key_material_next;
|
||||
key_material_n = &ssec->remote_key_material_n;
|
||||
}
|
||||
|
||||
if (zstr(key_param)) {
|
||||
goto no_crypto_found;
|
||||
}
|
||||
|
||||
*key_material_n = 0;
|
||||
|
||||
p = strchr(key_param, ' ');
|
||||
|
||||
if (p && *p && *(p + 1)) {
|
||||
p++;
|
||||
@@ -1234,36 +1394,192 @@ switch_status_t switch_core_media_add_crypto(switch_secure_settings_t *ssec, con
|
||||
type = switch_core_media_crypto_str2type(p);
|
||||
|
||||
if (type == CRYPTO_INVALID) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error near [%s]\n", p);
|
||||
goto bad;
|
||||
goto bad_crypto;
|
||||
}
|
||||
|
||||
p = strchr(p, ' ');
|
||||
if (p && *p && *(p + 1)) {
|
||||
p++;
|
||||
if (strncasecmp(p, "inline:", 7)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error near [%s]\n", p);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
p += 7;
|
||||
switch_b64_decode(p, (char *) key, sizeof(key));
|
||||
|
||||
if (direction == SWITCH_RTP_CRYPTO_SEND) {
|
||||
memcpy(ssec->local_raw_key, key, SUITES[type].keylen);
|
||||
} else {
|
||||
memcpy(ssec->remote_raw_key, key, SUITES[type].keylen);
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
p = strchr(p, ' '); /* skip the crypto suite description */
|
||||
if (p == NULL) {
|
||||
goto bad_crypto;
|
||||
}
|
||||
|
||||
do {
|
||||
if (*key_material_n == SWITCH_CRYPTO_MKI_MAX) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Skipping excess of MKIs due to max number of suppoerted MKIs %d exceeded\n", SWITCH_CRYPTO_MKI_MAX);
|
||||
break;
|
||||
}
|
||||
|
||||
p = switch_strip_spaces((char*) p, 0);
|
||||
if (p) {
|
||||
key_material_begin = p;
|
||||
key_material_end = switch_core_media_crypto_find_key_material_candidate_end(p);
|
||||
|
||||
/* Parsing the key material candidate within [begin, end). */
|
||||
|
||||
if ((delimit = strchr(p, ':')) == NULL) {
|
||||
goto bad_error_parsing_near;
|
||||
}
|
||||
|
||||
method_len = delimit - p;
|
||||
|
||||
if (strncasecmp(p, CRYPTO_KEY_PARAM_METHOD[CRYPTO_KEY_PARAM_METHOD_INLINE], method_len)) {
|
||||
goto bad_key_param_method;
|
||||
}
|
||||
|
||||
method = CRYPTO_KEY_PARAM_METHOD_INLINE;
|
||||
|
||||
/* Valid key-material found. Save as default key in secure_settings_s. */
|
||||
|
||||
p = delimit + 1; /* skip ':' */
|
||||
if (!(p && *p && *(p + 1))) {
|
||||
goto bad_keysalt;
|
||||
}
|
||||
|
||||
/* Check if '|' is present in currently considered key-material. */
|
||||
if ((opts = strchr(p, '|')) && (opts < key_material_end)) {
|
||||
keysalt_len = opts - p;
|
||||
} else {
|
||||
keysalt_len = key_material_end - p;
|
||||
}
|
||||
|
||||
if (keysalt_len > sizeof(key)) {
|
||||
goto bad_keysalt_len;
|
||||
}
|
||||
|
||||
switch_b64_decode(p, (char *) key, keysalt_len);
|
||||
|
||||
if (!multiple_keys) { /* First key becomes default (used in case no MKI is found). */
|
||||
if (direction == SWITCH_RTP_CRYPTO_SEND) {
|
||||
memcpy(ssec->local_raw_key, key, SUITES[type].keysalt_len);
|
||||
} else {
|
||||
memcpy(ssec->remote_raw_key, key, SUITES[type].keysalt_len);
|
||||
}
|
||||
multiple_keys = true;
|
||||
}
|
||||
|
||||
p += keysalt_len;
|
||||
|
||||
if (p < key_material_end) { /* Parse LIFETIME or MKI. */
|
||||
|
||||
if (opts) { /* if opts != NULL then opts points to first '|' in current key-material cadidate */
|
||||
|
||||
lifetime = 0;
|
||||
mki_id = 0;
|
||||
mki_size = 0;
|
||||
|
||||
for (int i = 0; i < 2 && (*opts == '|'); ++i) {
|
||||
|
||||
opt_field = parse_lifetime_mki(&opts, key_material_end);
|
||||
|
||||
switch ((opt_field >> 24) & 0x3) {
|
||||
|
||||
case CRYPTO_KEY_MATERIAL_LIFETIME:
|
||||
|
||||
lifetime_base = ((opt_field & 0x00ffff00) >> 8) & 0xffff;
|
||||
lifetime_exp = (opt_field & 0x000000ff) & 0xffff;
|
||||
lifetime = pow(lifetime_base, lifetime_exp);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "LIFETIME found in %s, base %u exp %u\n", p, lifetime_base, lifetime_exp);
|
||||
break;
|
||||
|
||||
case CRYPTO_KEY_MATERIAL_MKI:
|
||||
|
||||
mki_id = ((opt_field & 0x00ffff00) >> 8) & 0xffff;
|
||||
mki_size = (opt_field & 0x000000ff) & 0xffff;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "MKI found in %s, id %u size %u\n", p, mki_id, mki_size);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto bad_key_lifetime_or_mki;
|
||||
}
|
||||
}
|
||||
|
||||
if (mki_id == 0 && lifetime == 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Bad MKI found in %s, (parsed as: id %u size %u lifetime base %u exp %u\n", p, mki_id, mki_size, lifetime_base, lifetime_exp);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
} else if (mki_id == 0 || lifetime == 0) {
|
||||
if (mki_id == 0) {
|
||||
if (key_material)
|
||||
goto bad_key_no_mki_index;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Skipping MKI due to empty index\n");
|
||||
} else {
|
||||
if (mki_size == 0)
|
||||
goto bad_key_no_mki_size;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Skipping MKI due to empty lifetime\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (key_material) {
|
||||
if (mki_id == 0) {
|
||||
goto bad_key_no_mki_index;
|
||||
}
|
||||
|
||||
if (mki_size != key_material->mki_size) {
|
||||
goto bad_key_mki_size;
|
||||
}
|
||||
}
|
||||
|
||||
key_material = switch_core_media_crypto_append_key_material(session, key_material, method, (unsigned char*) key,
|
||||
SUITES[type].keysalt_len, (char*) key_material_begin, key_material_end - key_material_begin, lifetime, mki_id, mki_size);
|
||||
*key_material_n = *key_material_n + 1;
|
||||
}
|
||||
}
|
||||
} while ((p = switch_strip_spaces((char*) key_material_end, 0)) && (*p != '\0'));
|
||||
|
||||
if (direction == SWITCH_RTP_CRYPTO_SEND || direction == SWITCH_RTP_CRYPTO_SEND_RTCP) {
|
||||
ssec->local_key_material_next = key_material;
|
||||
} else {
|
||||
ssec->remote_key_material_next = key_material;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
bad:
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error!\n");
|
||||
no_crypto_found:
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error! No crypto to parse\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
bad_error_parsing_near:
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error! Parsing near %s\n", p);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
bad_crypto:
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error! SRTP: Invalid format of crypto attribute %s\n", key_param);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
bad_keysalt:
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error! SRTP: Invalid keysalt in the crypto attribute %s\n", key_param);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error! Parsing near %s\n", p);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
bad_keysalt_len:
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error! SRTP: Invalid keysalt length in the crypto attribute %s\n", key_param);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error! Parsing near %s\n", p);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
bad_key_lifetime_or_mki:
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error! SRTP: Invalid key param MKI or LIFETIME in the crypto attribute %s\n", key_param);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error! Parsing near %s\n", p);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
bad_key_no_mki_index:
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Crypto invalid: multiple keys in a single crypto MUST all have MKI indices, %s\n", key_param);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
bad_key_no_mki_size:
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Crypto invalid: MKI index with no MKI size in %s\n", key_param);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
bad_key_mki_size:
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Crypto invalid: MKI sizes differ in %s\n", key_param);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
bad_key_param_method:
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error! SRTP: Invalid key param method type in %s\n", key_param);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error! Parsing near %s\n", p);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_core_media_set_rtp_session(switch_core_session_t *session, switch_media_type_t type, switch_rtp_t *rtp_session)
|
||||
@@ -1342,19 +1658,16 @@ static void switch_core_session_apply_crypto(switch_core_session_t *session, swi
|
||||
}
|
||||
|
||||
if (engine->ssec[engine->crypto_type].remote_crypto_key && switch_channel_test_flag(session->channel, CF_SECURE)) {
|
||||
switch_core_media_add_crypto(&engine->ssec[engine->crypto_type], engine->ssec[engine->crypto_type].remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
|
||||
|
||||
if (switch_channel_get_variable(session->channel, "rtp_secure_media_mki"))
|
||||
switch_core_media_add_crypto(session, &engine->ssec[engine->crypto_type], SWITCH_RTP_CRYPTO_SEND);
|
||||
|
||||
switch_core_media_add_crypto(session, &engine->ssec[engine->crypto_type], SWITCH_RTP_CRYPTO_RECV);
|
||||
|
||||
|
||||
switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_SEND, 1,
|
||||
engine->ssec[engine->crypto_type].crypto_type,
|
||||
engine->ssec[engine->crypto_type].local_raw_key,
|
||||
SUITES[engine->ssec[engine->crypto_type].crypto_type].keylen);
|
||||
switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_SEND, 1, &engine->ssec[engine->crypto_type]);
|
||||
|
||||
switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_RECV,
|
||||
engine->ssec[engine->crypto_type].crypto_tag,
|
||||
engine->ssec[engine->crypto_type].crypto_type,
|
||||
engine->ssec[engine->crypto_type].remote_raw_key,
|
||||
SUITES[engine->ssec[engine->crypto_type].crypto_type].keylen);
|
||||
switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_RECV, engine->ssec[engine->crypto_type].crypto_tag, &engine->ssec[engine->crypto_type]);
|
||||
|
||||
switch_channel_set_variable(session->channel, varname, "true");
|
||||
|
||||
@@ -1476,7 +1789,7 @@ SWITCH_DECLARE(int) switch_core_session_check_incoming_crypto(switch_core_sessio
|
||||
for (i = 0; smh->crypto_suite_order[i] != CRYPTO_INVALID; i++) {
|
||||
switch_rtp_crypto_key_type_t j = SUITES[smh->crypto_suite_order[i]].type;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,"looking for crypto suite [%s] in [%s]\n", SUITES[j].name, crypto);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "looking for crypto suite [%s] in [%s]\n", SUITES[j].name, crypto);
|
||||
|
||||
if (switch_stristr(SUITES[j].name, crypto)) {
|
||||
ctype = SUITES[j].type;
|
||||
@@ -1504,8 +1817,7 @@ SWITCH_DECLARE(int) switch_core_session_check_incoming_crypto(switch_core_sessio
|
||||
switch_channel_set_variable(session->channel, varname, vval);
|
||||
|
||||
switch_core_media_build_crypto(session->media_handle, type, crypto_tag, ctype, SWITCH_RTP_CRYPTO_SEND, 1);
|
||||
switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), engine->ssec[engine->crypto_type].crypto_type,
|
||||
engine->ssec[engine->crypto_type].local_raw_key, SUITES[ctype].keylen);
|
||||
switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), &engine->ssec[engine->crypto_type]);
|
||||
}
|
||||
|
||||
if (a && b && !strncasecmp(a, b, 23)) {
|
||||
@@ -1532,9 +1844,8 @@ SWITCH_DECLARE(int) switch_core_session_check_incoming_crypto(switch_core_sessio
|
||||
|
||||
|
||||
if (switch_rtp_ready(engine->rtp_session) && switch_channel_test_flag(session->channel, CF_SECURE)) {
|
||||
switch_core_media_add_crypto(&engine->ssec[engine->crypto_type], engine->ssec[engine->crypto_type].remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
|
||||
switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_RECV, engine->ssec[engine->crypto_type].crypto_tag,
|
||||
engine->ssec[engine->crypto_type].crypto_type, engine->ssec[engine->crypto_type].remote_raw_key, SUITES[engine->ssec[engine->crypto_type].crypto_type].keylen);
|
||||
switch_core_media_add_crypto(session, &engine->ssec[engine->crypto_type], SWITCH_RTP_CRYPTO_RECV);
|
||||
switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_RECV, engine->ssec[engine->crypto_type].crypto_tag, &engine->ssec[engine->crypto_type]);
|
||||
}
|
||||
got_crypto++;
|
||||
|
||||
@@ -13414,20 +13725,13 @@ SWITCH_DECLARE (void) switch_core_media_recover_session(switch_core_session_t *s
|
||||
int idx = atoi(tmp);
|
||||
|
||||
a_engine->ssec[a_engine->crypto_type].local_crypto_key = switch_core_session_strdup(session, tmp);
|
||||
switch_core_media_add_crypto(&a_engine->ssec[a_engine->crypto_type], a_engine->ssec[a_engine->crypto_type].local_crypto_key, SWITCH_RTP_CRYPTO_SEND);
|
||||
switch_core_media_add_crypto(&a_engine->ssec[a_engine->crypto_type], a_engine->ssec[a_engine->crypto_type].remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
|
||||
switch_core_media_add_crypto(session, &a_engine->ssec[a_engine->crypto_type],SWITCH_RTP_CRYPTO_SEND);
|
||||
switch_core_media_add_crypto(session, &a_engine->ssec[a_engine->crypto_type],SWITCH_RTP_CRYPTO_RECV);
|
||||
switch_channel_set_flag(smh->session->channel, CF_SECURE);
|
||||
|
||||
switch_rtp_add_crypto_key(a_engine->rtp_session, SWITCH_RTP_CRYPTO_SEND, idx,
|
||||
a_engine->crypto_type,
|
||||
a_engine->ssec[a_engine->crypto_type].local_raw_key,
|
||||
SUITES[a_engine->crypto_type].keylen);
|
||||
switch_rtp_add_crypto_key(a_engine->rtp_session, SWITCH_RTP_CRYPTO_SEND, idx, &a_engine->ssec[a_engine->crypto_type]);
|
||||
|
||||
switch_rtp_add_crypto_key(a_engine->rtp_session, SWITCH_RTP_CRYPTO_RECV,
|
||||
a_engine->ssec[a_engine->crypto_type].crypto_tag,
|
||||
a_engine->crypto_type,
|
||||
a_engine->ssec[a_engine->crypto_type].remote_raw_key,
|
||||
SUITES[a_engine->crypto_type].keylen);
|
||||
switch_rtp_add_crypto_key(a_engine->rtp_session, SWITCH_RTP_CRYPTO_RECV, a_engine->ssec[a_engine->crypto_type].crypto_tag, &a_engine->ssec[a_engine->crypto_type]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+174
-50
@@ -2321,8 +2321,14 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session)
|
||||
|
||||
#ifdef ENABLE_SRTP
|
||||
if (rtp_session->flags[SWITCH_RTP_FLAG_SECURE_SEND]) {
|
||||
int stat = 0;
|
||||
int sbytes = (int) rtcp_bytes;
|
||||
int stat = srtp_protect_rtcp(rtp_session->send_ctx[rtp_session->srtp_idx_rtcp], &rtp_session->rtcp_send_msg.header, &sbytes);
|
||||
|
||||
if (!rtp_session->flags[SWITCH_RTP_FLAG_SECURE_SEND_MKI]) {
|
||||
stat = srtp_protect_rtcp(rtp_session->send_ctx[rtp_session->srtp_idx_rtcp], &rtp_session->rtcp_send_msg.header, &sbytes);
|
||||
} else {
|
||||
stat = srtp_protect_rtcp_mki(rtp_session->send_ctx[rtp_session->srtp_idx_rtcp], &rtp_session->rtcp_send_msg.header, &sbytes, 1, SWITCH_CRYPTO_MKI_INDEX);
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "Error: SRTP RTCP protection failed with code %d\n", stat);
|
||||
@@ -3068,18 +3074,27 @@ static const char *dtls_state_names(dtls_state_t s)
|
||||
return dtls_state_names_t[s];
|
||||
}
|
||||
|
||||
|
||||
#define dtls_set_state(_dtls, _state) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_INFO, "Changing %s DTLS state from %s to %s\n", rtp_type(rtp_session), dtls_state_names(_dtls->state), dtls_state_names(_state)); _dtls->new_state = 1; _dtls->last_state = _dtls->state; _dtls->state = _state
|
||||
|
||||
#define cr_keylen 16
|
||||
#define cr_saltlen 14
|
||||
#define cr_kslen 30
|
||||
|
||||
static int dtls_state_setup(switch_rtp_t *rtp_session, switch_dtls_t *dtls)
|
||||
{
|
||||
X509 *cert;
|
||||
switch_secure_settings_t ssec; /* Used just to wrap over params in a call to switch_rtp_add_crypto_key. */
|
||||
int r = 0;
|
||||
|
||||
const switch_size_t cr_kslen = SUITES[AES_CM_128_HMAC_SHA1_80].keysalt_len;
|
||||
const switch_size_t cr_saltlen = SUITES[AES_CM_128_HMAC_SHA1_80].salt_len;
|
||||
const switch_size_t cr_keylen = cr_kslen - cr_saltlen;
|
||||
|
||||
uint8_t raw_key_data[cr_kslen * 2];
|
||||
unsigned char local_key_buf[cr_kslen];
|
||||
unsigned char remote_key_buf[cr_kslen];
|
||||
|
||||
memset(&ssec, 0, sizeof(ssec));
|
||||
memset(&raw_key_data, 0, cr_kslen * 2 * sizeof(uint8_t));
|
||||
memset(&local_key_buf, 0, cr_kslen * sizeof(unsigned char));
|
||||
memset(&remote_key_buf, 0, cr_kslen * sizeof(unsigned char));
|
||||
|
||||
if ((dtls->type & DTLS_TYPE_SERVER)) {
|
||||
r = 1;
|
||||
} else if ((cert = SSL_get_peer_certificate(dtls->ssl))) {
|
||||
@@ -3093,9 +3108,7 @@ static int dtls_state_setup(switch_rtp_t *rtp_session, switch_dtls_t *dtls)
|
||||
dtls_set_state(dtls, DS_FAIL);
|
||||
return -1;
|
||||
} else {
|
||||
uint8_t raw_key_data[cr_kslen*2] = { 0 };
|
||||
unsigned char *local_key, *remote_key, *local_salt, *remote_salt;
|
||||
unsigned char local_key_buf[cr_kslen] = {0}, remote_key_buf[cr_kslen] = {0};
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_INFO, "%s Fingerprint Verified.\n", rtp_type(rtp_session));
|
||||
|
||||
@@ -3122,18 +3135,20 @@ static int dtls_state_setup(switch_rtp_t *rtp_session, switch_dtls_t *dtls)
|
||||
local_salt = remote_salt + cr_saltlen;
|
||||
}
|
||||
|
||||
memcpy(local_key_buf, local_key, cr_keylen);
|
||||
memcpy(local_key_buf + cr_keylen, local_salt, cr_saltlen);
|
||||
memcpy(&ssec.local_raw_key, local_key, cr_keylen);
|
||||
memcpy(&ssec.local_raw_key + cr_keylen, local_salt, cr_saltlen);
|
||||
|
||||
memcpy(remote_key_buf, remote_key, cr_keylen);
|
||||
memcpy(remote_key_buf + cr_keylen, remote_salt, cr_saltlen);
|
||||
memcpy(&ssec.remote_raw_key, remote_key, cr_keylen);
|
||||
memcpy(&ssec.remote_raw_key + cr_keylen, remote_salt, cr_saltlen);
|
||||
|
||||
ssec.crypto_type = AES_CM_128_HMAC_SHA1_80;
|
||||
|
||||
if (dtls == rtp_session->rtcp_dtls && rtp_session->rtcp_dtls != rtp_session->dtls) {
|
||||
switch_rtp_add_crypto_key(rtp_session, SWITCH_RTP_CRYPTO_SEND_RTCP, 0, AES_CM_128_HMAC_SHA1_80, local_key_buf, cr_kslen);
|
||||
switch_rtp_add_crypto_key(rtp_session, SWITCH_RTP_CRYPTO_RECV_RTCP, 0, AES_CM_128_HMAC_SHA1_80, remote_key_buf, cr_kslen);
|
||||
switch_rtp_add_crypto_key(rtp_session, SWITCH_RTP_CRYPTO_SEND_RTCP, 0, &ssec);
|
||||
switch_rtp_add_crypto_key(rtp_session, SWITCH_RTP_CRYPTO_RECV_RTCP, 0, &ssec);
|
||||
} else {
|
||||
switch_rtp_add_crypto_key(rtp_session, SWITCH_RTP_CRYPTO_SEND, 0, AES_CM_128_HMAC_SHA1_80, local_key_buf, cr_kslen);
|
||||
switch_rtp_add_crypto_key(rtp_session, SWITCH_RTP_CRYPTO_RECV, 0, AES_CM_128_HMAC_SHA1_80, remote_key_buf, cr_kslen);
|
||||
switch_rtp_add_crypto_key(rtp_session, SWITCH_RTP_CRYPTO_SEND, 0, &ssec);
|
||||
switch_rtp_add_crypto_key(rtp_session, SWITCH_RTP_CRYPTO_RECV, 0, &ssec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3815,15 +3830,13 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d
|
||||
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_session,
|
||||
switch_rtp_crypto_direction_t direction,
|
||||
uint32_t index, switch_rtp_crypto_key_type_t type, unsigned char *key, switch_size_t keylen)
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_session, switch_rtp_crypto_direction_t direction, uint32_t index, switch_secure_settings_t *ssec)
|
||||
{
|
||||
#ifndef ENABLE_SRTP
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_CRIT, "SRTP NOT SUPPORTED IN THIS BUILD!\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
#else
|
||||
|
||||
switch_rtp_crypto_key_t *crypto_key;
|
||||
srtp_policy_t *policy;
|
||||
srtp_err_status_t stat;
|
||||
@@ -3834,12 +3847,43 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_sess
|
||||
int idx = 0;
|
||||
const char *var;
|
||||
unsigned char b64_key[512] = "";
|
||||
|
||||
unsigned char *keysalt = NULL;
|
||||
switch_size_t keysalt_len = 0;
|
||||
|
||||
switch_crypto_key_material_t *key_material = NULL;
|
||||
unsigned long *key_material_n = NULL;
|
||||
srtp_master_key_t **mkis = NULL;
|
||||
srtp_master_key_t *mki = NULL;
|
||||
int mki_idx = 0;
|
||||
|
||||
if (direction >= SWITCH_RTP_CRYPTO_MAX || keylen > SWITCH_RTP_MAX_CRYPTO_LEN) {
|
||||
keysalt_len = SUITES[ssec->crypto_type].keysalt_len;
|
||||
|
||||
if (direction >= SWITCH_RTP_CRYPTO_MAX || keysalt_len > SWITCH_RTP_MAX_CRYPTO_LEN) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
switch_b64_encode(key, keylen, b64_key, sizeof(b64_key));
|
||||
if (direction == SWITCH_RTP_CRYPTO_RECV_RTCP) {
|
||||
direction = SWITCH_RTP_CRYPTO_RECV;
|
||||
rtp_session->srtp_idx_rtcp = idx = 1;
|
||||
} else if (direction == SWITCH_RTP_CRYPTO_SEND_RTCP) {
|
||||
direction = SWITCH_RTP_CRYPTO_SEND;
|
||||
rtp_session->srtp_idx_rtcp = idx = 1;
|
||||
}
|
||||
|
||||
if (direction == SWITCH_RTP_CRYPTO_RECV) {
|
||||
policy = &rtp_session->recv_policy[idx];
|
||||
keysalt = ssec->remote_raw_key;
|
||||
key_material = ssec->remote_key_material_next;
|
||||
key_material_n = &ssec->remote_key_material_n;
|
||||
} else {
|
||||
policy = &rtp_session->send_policy[idx];
|
||||
keysalt = ssec->local_raw_key;
|
||||
key_material = ssec->local_key_material_next;
|
||||
key_material_n = &ssec->local_key_material_n;
|
||||
}
|
||||
|
||||
switch_b64_encode(keysalt, keysalt_len, b64_key, sizeof(b64_key));
|
||||
|
||||
if (switch_true(switch_core_get_variable("rtp_retain_crypto_keys"))) {
|
||||
switch(direction) {
|
||||
@@ -3862,23 +3906,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_sess
|
||||
|
||||
crypto_key = switch_core_alloc(rtp_session->pool, sizeof(*crypto_key));
|
||||
|
||||
if (direction == SWITCH_RTP_CRYPTO_RECV_RTCP) {
|
||||
direction = SWITCH_RTP_CRYPTO_RECV;
|
||||
rtp_session->srtp_idx_rtcp = idx = 1;
|
||||
} else if (direction == SWITCH_RTP_CRYPTO_SEND_RTCP) {
|
||||
direction = SWITCH_RTP_CRYPTO_SEND;
|
||||
rtp_session->srtp_idx_rtcp = idx = 1;
|
||||
}
|
||||
|
||||
if (direction == SWITCH_RTP_CRYPTO_RECV) {
|
||||
policy = &rtp_session->recv_policy[idx];
|
||||
} else {
|
||||
policy = &rtp_session->send_policy[idx];
|
||||
}
|
||||
|
||||
crypto_key->type = type;
|
||||
crypto_key->type = ssec->crypto_type;
|
||||
crypto_key->index = index;
|
||||
memcpy(crypto_key->key, key, keylen);
|
||||
memcpy(crypto_key->keysalt, keysalt, keysalt_len);
|
||||
crypto_key->next = rtp_session->crypto_keys[direction];
|
||||
rtp_session->crypto_keys[direction] = crypto_key;
|
||||
|
||||
@@ -3948,7 +3978,68 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_sess
|
||||
break;
|
||||
}
|
||||
|
||||
policy->key = (uint8_t *) crypto_key->key;
|
||||
/* Setup the policy with MKI if they are used. Number of key materials must be positive to use MKI. */
|
||||
if (key_material && (*key_material_n > 0)) {
|
||||
|
||||
if (direction == SWITCH_RTP_CRYPTO_RECV) {
|
||||
rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV_MKI] = 1;
|
||||
} else {
|
||||
rtp_session->flags[SWITCH_RTP_FLAG_SECURE_SEND_MKI] = 1;
|
||||
}
|
||||
|
||||
/* key must be NULL for libsrtp to work correctly with MKI. */
|
||||
policy->key = NULL;
|
||||
|
||||
/* Allocate array for MKIs. */
|
||||
mkis = switch_core_alloc(rtp_session->pool, *key_material_n * sizeof(srtp_master_key_t*));
|
||||
if (!mkis) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
/* Build array of MKIs. */
|
||||
mki_idx = 0;
|
||||
|
||||
while (key_material && (mki_idx < *key_material_n)) {
|
||||
|
||||
if (key_material->mki_size < 1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "MKI bad key size at MKI %d\n", mki_idx);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
mki = switch_core_alloc(rtp_session->pool, sizeof(srtp_master_key_t));
|
||||
if (!mki) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
/* Setup MKI. */
|
||||
mki->mki_id = switch_core_alloc(rtp_session->pool, sizeof(key_material->mki_size));
|
||||
if (!mki->mki_id) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
mki->key = switch_core_alloc(rtp_session->pool, keysalt_len);
|
||||
if (!mki->key) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
memcpy(mki->mki_id, &key_material->mki_id, key_material->mki_size);
|
||||
mki->mki_size = key_material->mki_size;
|
||||
memcpy(mki->key, key_material->raw_key, keysalt_len);
|
||||
|
||||
mkis[mki_idx] = mki;
|
||||
|
||||
key_material = key_material->next;
|
||||
++mki_idx;
|
||||
}
|
||||
|
||||
/* And pass the array of MKIs to libsrtp. */
|
||||
policy->keys = mkis;
|
||||
policy->num_master_keys = mki_idx;
|
||||
|
||||
} else {
|
||||
policy->key = (uint8_t *) crypto_key->keysalt;
|
||||
}
|
||||
|
||||
policy->next = NULL;
|
||||
|
||||
policy->window_size = 1024;
|
||||
@@ -3969,8 +4060,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_sess
|
||||
}
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_INFO, "Activating %s Secure %s RECV\n",
|
||||
rtp_type(rtp_session), idx ? "RTCP" : "RTP");
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_INFO, "Activating %s Secure %s RECV%s\n",
|
||||
rtp_type(rtp_session), idx ? "RTCP" : "RTP", rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV_MKI] ? " (with MKI)" : "");
|
||||
rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV] = 1;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "Error allocating srtp [%d]\n", stat);
|
||||
@@ -3991,8 +4082,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_sess
|
||||
}
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_INFO, "Activating %s Secure %s SEND\n",
|
||||
rtp_type(rtp_session), idx ? "RTCP" : "RTP");
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_INFO, "Activating %s Secure %s SEND%s\n",
|
||||
rtp_type(rtp_session), idx ? "RTCP" : "RTP", rtp_session->flags[SWITCH_RTP_FLAG_SECURE_SEND_MKI] ? " (with MKI)" : "");
|
||||
rtp_session->flags[SWITCH_RTP_FLAG_SECURE_SEND] = 1;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "Error allocating SRTP [%d]\n", stat);
|
||||
@@ -5780,8 +5871,13 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
|
||||
int sbytes = (int) *bytes;
|
||||
srtp_err_status_t stat = 0;
|
||||
|
||||
if (!rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV_MKI]) {
|
||||
stat = srtp_unprotect_rtcp(rtp_session->recv_ctx[rtp_session->srtp_idx_rtcp], &rtp_session->rtcp_recv_msg_p->header, &sbytes);
|
||||
} else {
|
||||
stat = srtp_unprotect_rtcp_mki(rtp_session->recv_ctx[rtp_session->srtp_idx_rtcp], &rtp_session->rtcp_recv_msg_p->header, &sbytes, 1);
|
||||
}
|
||||
|
||||
if ((stat = srtp_unprotect_rtcp(rtp_session->recv_ctx[rtp_session->srtp_idx_rtcp], &rtp_session->rtcp_recv_msg_p->header, &sbytes))) {
|
||||
if (stat) {
|
||||
//++rtp_session->srtp_errs[rtp_session->srtp_idx_rtp]++;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "RTCP UNPROTECT ERR\n");
|
||||
} else {
|
||||
@@ -5975,7 +6071,14 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
|
||||
}
|
||||
|
||||
if (!(*flags & SFF_PLC) && rtp_session->recv_ctx[rtp_session->srtp_idx_rtp]) {
|
||||
stat = srtp_unprotect(rtp_session->recv_ctx[rtp_session->srtp_idx_rtp], &rtp_session->recv_msg.header, &sbytes);
|
||||
stat = 0;
|
||||
|
||||
if (!rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV_MKI]) {
|
||||
stat = srtp_unprotect(rtp_session->recv_ctx[rtp_session->srtp_idx_rtp], &rtp_session->recv_msg.header, &sbytes);
|
||||
} else {
|
||||
stat = srtp_unprotect_mki(rtp_session->recv_ctx[rtp_session->srtp_idx_rtp], &rtp_session->recv_msg.header, &sbytes, 1);
|
||||
}
|
||||
|
||||
if (rtp_session->flags[SWITCH_RTP_FLAG_NACK] && stat == srtp_err_status_replay_fail) {
|
||||
/* false alarm nack */
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "REPLAY ERR, FALSE NACK\n");
|
||||
@@ -6743,7 +6846,13 @@ static switch_status_t read_rtcp_packet(switch_rtp_t *rtp_session, switch_size_t
|
||||
srtp_err_status_t stat = 0;
|
||||
|
||||
|
||||
if ((stat = srtp_unprotect_rtcp(rtp_session->recv_ctx[rtp_session->srtp_idx_rtcp], &rtp_session->rtcp_recv_msg_p->header, &sbytes))) {
|
||||
if (!rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV_MKI]) {
|
||||
stat = srtp_unprotect_rtcp(rtp_session->recv_ctx[rtp_session->srtp_idx_rtcp], &rtp_session->rtcp_recv_msg_p->header, &sbytes);
|
||||
} else {
|
||||
stat = srtp_unprotect_rtcp_mki(rtp_session->recv_ctx[rtp_session->srtp_idx_rtcp], &rtp_session->rtcp_recv_msg_p->header, &sbytes, 1);
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
//++rtp_session->srtp_errs[rtp_session->srtp_idx_rtp]++;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "RTCP UNPROTECT ERR\n");
|
||||
} else {
|
||||
@@ -7192,8 +7301,15 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
|
||||
|
||||
#ifdef ENABLE_SRTP
|
||||
if (switch_rtp_test_flag(other_rtp_session, SWITCH_RTP_FLAG_SECURE_SEND)) {
|
||||
int stat = 0;
|
||||
int sbytes = (int) rtcp_bytes;
|
||||
int stat = srtp_protect_rtcp(other_rtp_session->send_ctx[rtp_session->srtp_idx_rtcp], &other_rtp_session->rtcp_send_msg.header, &sbytes);
|
||||
|
||||
if (!other_rtp_session->flags[SWITCH_RTP_FLAG_SECURE_SEND_MKI]) {
|
||||
stat = srtp_protect_rtcp(other_rtp_session->send_ctx[rtp_session->srtp_idx_rtcp], &other_rtp_session->rtcp_send_msg.header, &sbytes);
|
||||
} else {
|
||||
stat = srtp_protect_rtcp_mki(other_rtp_session->send_ctx[other_rtp_session->srtp_idx_rtcp], &other_rtp_session->rtcp_send_msg.header, &sbytes, 1, SWITCH_CRYPTO_MKI_INDEX);
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "Error: SRTP RTCP protection failed with code %d\n", stat);
|
||||
}
|
||||
@@ -8235,8 +8351,11 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
stat = srtp_protect(rtp_session->send_ctx[rtp_session->srtp_idx_rtp], &send_msg->header, &sbytes);
|
||||
if (!rtp_session->flags[SWITCH_RTP_FLAG_SECURE_SEND_MKI]) {
|
||||
stat = srtp_protect(rtp_session->send_ctx[rtp_session->srtp_idx_rtp], &send_msg->header, &sbytes);
|
||||
} else {
|
||||
stat = srtp_protect_mki(rtp_session->send_ctx[rtp_session->srtp_idx_rtp], &send_msg->header, &sbytes, 1, SWITCH_CRYPTO_MKI_INDEX);
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR,
|
||||
@@ -8820,7 +8939,12 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_write_raw(switch_rtp_t *rtp_session,
|
||||
}
|
||||
}
|
||||
|
||||
stat = srtp_protect(rtp_session->send_ctx[rtp_session->srtp_idx_rtp], &rtp_session->write_msg.header, &sbytes);
|
||||
if (!rtp_session->flags[SWITCH_RTP_FLAG_SECURE_SEND_MKI]) {
|
||||
stat = srtp_protect(rtp_session->send_ctx[rtp_session->srtp_idx_rtp], &rtp_session->write_msg.header, &sbytes);
|
||||
} else {
|
||||
stat = srtp_protect_mki(rtp_session->send_ctx[rtp_session->srtp_idx_rtp], &rtp_session->write_msg.header, &sbytes, 1, SWITCH_CRYPTO_MKI_INDEX);
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "Error: SRTP protection failed with code %d\n", stat);
|
||||
}
|
||||
|
||||
+3
-2
@@ -955,12 +955,13 @@ SWITCH_DECLARE(switch_status_t) switch_b64_encode(unsigned char *in, switch_size
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_size_t) switch_b64_decode(char *in, char *out, switch_size_t olen)
|
||||
SWITCH_DECLARE(switch_size_t) switch_b64_decode(const char *in, char *out, switch_size_t olen)
|
||||
{
|
||||
|
||||
char l64[256];
|
||||
int b = 0, c, l = 0, i;
|
||||
char *ip, *op = out;
|
||||
const char *ip;
|
||||
char *op = out;
|
||||
size_t ol = 0;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
|
||||
Reference in New Issue
Block a user