diff options
Diffstat (limited to 'tinyRTP/src/trtp_srtp.c')
-rw-r--r-- | tinyRTP/src/trtp_srtp.c | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/tinyRTP/src/trtp_srtp.c b/tinyRTP/src/trtp_srtp.c new file mode 100644 index 0000000..5e2d033 --- /dev/null +++ b/tinyRTP/src/trtp_srtp.c @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2012 Mamadou Diop + * Copyright (C) 2012-2013 Doubango Telecom <http://www.doubango.org> + * + * This file is part of Open Source Doubango Framework. + * + * DOUBANGO is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * DOUBANGO is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DOUBANGO. + * + */ +/**@file trtp_srtp.c + */ +#include "tinyrtp/trtp_srtp.h" +#include "tinyrtp/trtp_manager.h" + +#if HAVE_SRTP + +extern err_status_t +crypto_get_random(unsigned char *buffer, unsigned int length); + +int trtp_srtp_ctx_internal_init(struct trtp_srtp_ctx_internal_xs* ctx, int32_t tag, trtp_srtp_crypto_type_t type, uint32_t ssrc) +{ + char* key_str = ctx->key_str; + err_status_t srtp_err; + tsk_size_t size; + + if (!ctx) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if (ctx->initialized) { + trtp_srtp_ctx_internal_deinit(ctx); + } + + ctx->tag = tag; + ctx->crypto_type = type; + if (!ctx->have_valid_key) { // use same key to avoid unseless SRTP re-negs (also fix interop-issues against buggy clients -reINVITEs-) + if ((srtp_err = crypto_get_random((unsigned char*)ctx->key_bin, sizeof(ctx->key_bin))) != err_status_ok) { + TSK_DEBUG_ERROR("crypto_get_random() failed"); + return -2; + } + size = tsk_base64_encode((const uint8_t*)ctx->key_bin, sizeof(ctx->key_bin), &key_str); + key_str[size] = '\0'; + ctx->have_valid_key = tsk_true; + } + + switch(ctx->crypto_type){ + case HMAC_SHA1_80: + { + crypto_policy_set_aes_cm_128_hmac_sha1_80(&ctx->policy.rtp); + crypto_policy_set_aes_cm_128_hmac_sha1_80(&ctx->policy.rtcp); + break; + } + case HMAC_SHA1_32: + default: + { + crypto_policy_set_aes_cm_128_hmac_sha1_32(&ctx->policy.rtp); + crypto_policy_set_aes_cm_128_hmac_sha1_80(&ctx->policy.rtcp); // RTCP always 80 + break; + } + } + + ctx->policy.key = (unsigned char*)ctx->key_bin; + ctx->policy.ssrc.type = ssrc_any_outbound; + ctx->policy.ssrc.value = ssrc; + ctx->policy.window_size = 2048; + ctx->policy.allow_repeat_tx = 1; + if ((srtp_err = srtp_create(&ctx->session, &ctx->policy)) != err_status_ok) { + TSK_DEBUG_ERROR("srtp_create() failed"); + return -3; + } + ctx->initialized = tsk_true; + return 0; +} + +int trtp_srtp_ctx_internal_deinit(struct trtp_srtp_ctx_internal_xs* ctx) +{ + if(!ctx){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(ctx->initialized){ + /*err_status_t srtp_err =*/ srtp_dealloc(ctx->session); + memset(&ctx->policy, 0, sizeof(ctx->policy)); + ctx->initialized = tsk_false; + } + return 0; +} + +int trtp_srtp_ctx_init(trtp_srtp_ctx_xt* ctx, int32_t tag, trtp_srtp_crypto_type_t type, uint32_t ssrc) +{ + int ret; + if(!ctx){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if((ret = trtp_srtp_ctx_internal_init(&ctx->rtp, tag, type, ssrc))){ + return ret; + } + return trtp_srtp_ctx_internal_init(&ctx->rtcp, tag, type, ssrc); +} + +int trtp_srtp_ctx_deinit(trtp_srtp_ctx_xt* ctx) +{ + int ret; + if(!ctx){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if((ret = trtp_srtp_ctx_internal_deinit(&ctx->rtp))){ + return ret; + } + return trtp_srtp_ctx_internal_deinit(&ctx->rtcp); +} + +int trtp_srtp_match_line(const char* crypto_line, int32_t* tag, int32_t* crypto_type, char* key, tsk_size_t key_size) +{ + char* copyptr = tsk_strdup(crypto_line); // "strtok_r" will insert "\0" and modify the string + char* saveptr = tsk_null; + char* v = tsk_strtok_r(copyptr, " :|;", &saveptr); + int32_t k = 0; + int ret = -0xF0; + while(v){ + switch(k){ + case 0: + { + if(tag){ + *tag = atoi(v); + } + break; + } + case 1: + { + if(tsk_striequals(v, TRTP_SRTP_AES_CM_128_HMAC_SHA1_80)){ + if(crypto_type){ + *crypto_type = HMAC_SHA1_80; + } + } + else if(tsk_striequals(v, TRTP_SRTP_AES_CM_128_HMAC_SHA1_32)){ + if(crypto_type){ + *crypto_type = HMAC_SHA1_32; + } + } + else { + ret = -0xFF; goto bail; + } + break; + } + case 2: + { + if(!tsk_striequals(v, "inline")){ + ret = -0xFF; goto bail; + } + break; + } + case 3: + { + if(key && key_size){ + memset(key, 0, key_size); + memcpy(key, v, TSK_MIN(key_size, tsk_strlen(v))); + } + ret = 0; goto bail; + } + } + ++k; + v = tsk_strtok_r(tsk_null, " :|;", &saveptr); + } +bail: + TSK_FREE(copyptr); + return ret; +} + +tsk_size_t trtp_srtp_get_local_contexts(trtp_manager_t* rtp_mgr, const struct trtp_srtp_ctx_xs ** contexts, tsk_size_t contexts_count) +{ + tsk_size_t ret = 0; + if(!rtp_mgr || !contexts){ + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + if (contexts_count > ret && rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80].rtp.initialized) { + contexts[ret++] = &rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80]; + } + if (contexts_count > ret && rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32].rtp.initialized) { + contexts[ret++] = &rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32]; + } + return ret; +} + +int trtp_srtp_set_crypto(struct trtp_manager_s* rtp_mgr, const char* crypto_line, int32_t idx) +{ + //e.g. 2 F8_128_HMAC_SHA1_80 inline:MTIzNDU2Nzg5QUJDREUwMTIzNDU2Nzg5QUJjZGVm|2^20|1:4;inline:QUJjZGVmMTIzNDU2Nzg5QUJDREUwMTIzNDU2Nzg5|2^20|2:4" + trtp_srtp_ctx_xt* srtp_ctx; + int ret; + uint8_t *key_bin; + err_status_t srtp_err; + int32_t tag, crypto_type; + char key_str[SRTP_MAX_KEY_LEN + 1]; + + memset(key_str, 0, sizeof(key_str)); + + if ((ret = trtp_srtp_match_line(crypto_line, &tag, &crypto_type, key_str, sizeof(key_str) - 1))) { + return ret; + } + + srtp_ctx = &rtp_mgr->srtp_contexts[idx][crypto_type]; + ret = trtp_srtp_ctx_deinit(srtp_ctx); + + srtp_ctx->rtp.tag = tag; + srtp_ctx->rtp.crypto_type = (trtp_srtp_crypto_type_t)crypto_type; + memcpy(srtp_ctx->rtp.key_str, key_str, sizeof(srtp_ctx->rtp.key_str)); + + switch(srtp_ctx->rtp.crypto_type){ + case HMAC_SHA1_80: + { + crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->rtp.policy.rtp); + crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->rtp.policy.rtcp); + if (idx == TRTP_SRTP_LINE_IDX_REMOTE) { + trtp_srtp_ctx_deinit(&rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32]); + rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80].rtp.tag = + rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80].rtcp.tag = srtp_ctx->rtp.tag; + } + break; + } + case HMAC_SHA1_32: + { + crypto_policy_set_aes_cm_128_hmac_sha1_32(&srtp_ctx->rtp.policy.rtp); + crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->rtp.policy.rtcp); // RTCP always 80 + if (idx == TRTP_SRTP_LINE_IDX_REMOTE) { + trtp_srtp_ctx_deinit(&rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80]); + rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32].rtp.tag = + rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32].rtcp.tag = srtp_ctx->rtp.tag; + } + break; + } + default: break; + } + + key_bin = (unsigned char*)srtp_ctx->rtp.key_bin; + tsk_base64_decode((const uint8_t*)srtp_ctx->rtp.key_str, (tsk_size_t)tsk_strlen(srtp_ctx->rtp.key_str), (char**)&key_bin); + srtp_ctx->rtp.policy.key = key_bin; + srtp_ctx->rtp.policy.ssrc.type = idx == TRTP_SRTP_LINE_IDX_REMOTE ? ssrc_any_inbound : ssrc_any_outbound; + srtp_ctx->rtp.policy.window_size = 2048; + srtp_ctx->rtp.policy.allow_repeat_tx = 1; + if ((srtp_err = srtp_create(&srtp_ctx->rtp.session, &srtp_ctx->rtp.policy)) != err_status_ok) { + TSK_DEBUG_ERROR("srtp_create() failed: %d", srtp_err); + return -3; + } + srtp_ctx->rtp.initialized = tsk_true; + return 0; +} + +int trtp_srtp_set_key_and_salt(trtp_manager_t* rtp_mgr, trtp_srtp_crypto_type_t crypto_type, const void* key, tsk_size_t key_size, const void* salt, tsk_size_t salt_size, int32_t idx, tsk_bool_t is_rtp) +{ + int ret; + trtp_srtp_ctx_internal_xt* srtp_ctx; + err_status_t srtp_err; + if (!rtp_mgr || !key || !key_size || !salt || !salt_size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + srtp_ctx = is_rtp ? &rtp_mgr->srtp_contexts[idx][crypto_type].rtp : &rtp_mgr->srtp_contexts[idx][crypto_type].rtcp; + if ((ret = trtp_srtp_ctx_internal_deinit(srtp_ctx))) { + return ret; + } + + switch ((srtp_ctx->crypto_type = crypto_type)) { + case HMAC_SHA1_80: + default: + { + crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtp); + crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtcp); + break; + } + case HMAC_SHA1_32: + { + crypto_policy_set_aes_cm_128_hmac_sha1_32(&srtp_ctx->policy.rtp); + crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtcp); // always 80 + break; + } + } + + memcpy(srtp_ctx->key_bin, key, key_size); +#if HAVE_APPEND_SALT_TO_KEY + append_salt_to_key(srtp_ctx->key_bin, key_size, (void*)salt, salt_size); +#else + memcpy(&srtp_ctx->key_bin[key_size], salt, salt_size); +#endif + + srtp_ctx->policy.key = (unsigned char *)srtp_ctx->key_bin; + srtp_ctx->policy.ssrc.type = idx == TRTP_SRTP_LINE_IDX_REMOTE ? ssrc_any_inbound : ssrc_any_outbound; + srtp_ctx->policy.window_size = 2048; + srtp_ctx->policy.allow_repeat_tx = 1; + if((srtp_err = srtp_create(&srtp_ctx->session, &srtp_ctx->policy)) != err_status_ok){ + TSK_DEBUG_ERROR("srtp_create() failed: %d", srtp_err); + return -3; + } + srtp_ctx->initialized = tsk_true; + return 0; +} + +tsk_bool_t trtp_srtp_is_initialized(trtp_manager_t* rtp_mgr) +{ + if (!rtp_mgr) { + return tsk_false; + } + return ((rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][0].rtp.initialized || rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][1].rtp.initialized) + && rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_REMOTE][0].rtp.initialized); +} + +tsk_bool_t trtp_srtp_is_started(trtp_manager_t* rtp_mgr) +{ + if (!rtp_mgr) { + TSK_DEBUG_ERROR("Invalid argument"); + return tsk_false; + } + return (rtp_mgr ->srtp_ctx_neg_remote && rtp_mgr ->srtp_ctx_neg_local); +} + +#endif /* HAVE_SRTP */
\ No newline at end of file |