c732d49e |
#if HAVE_CRT
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif //HAVE_CRT
/*
* Copyright (C) 2017, University of the Basque Country (UPV/EHU)
* Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
*
* The original file was part of Open Source Doubango Framework
* Copyright (C) 2010-2011 Mamadou Diop.
* Copyright (C) 2012 Doubango Telecom <http://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((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';
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* saveptr;
char* v = tsk_strtok_r((char*)crypto_line, " :|;", &saveptr);
int32_t k = 0;
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 {
return -0xFF;
}
break;
}
case 2:
{
if(!tsk_striequals(v, "inline")){
return -0xFF;
}
break;
}
case 3:
{
if(key && key_size){
memset(key, 0, key_size);
memcpy(key, v, TSK_MIN(key_size, tsk_strlen(v)));
}
return 0;
}
}
++k;
v = tsk_strtok_r(tsk_null, " :|;", &saveptr);
}
return -0xF0;
}
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;
}
}
key_bin = (unsigned char*)srtp_ctx->rtp.key_bin;
tsk_base64_decode((const uint8_t*)srtp_ctx->rtp.key_str, 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);
}
tsk_bool_t trtp_srtp_process_mikey_message(struct trtp_manager_s* rtp_mgr, const char* mikey_message)
{
return tsk_true;
}
#endif /* HAVE_SRTP */ |