freeswitch/libs/libzrtp/src/zrtp_srtp_dm.c

233 lines
6.2 KiB
C

/*
* libZRTP SDK library, implements the ZRTP secure VoIP protocol.
* Copyright (c) 2006-2009 Philip R. Zimmermann. All rights reserved.
* Contact: http://philzimmermann.com
* For licensing and other legal details, see the file zrtp_legal.c.
*
* Viktor Krykun <v.krikun at zfoneproject.com>
*/
#if (defined(ZRTP_USE_EXTERN_SRTP) && (ZRTP_USE_EXTERN_SRTP == 1))
/* exactly in this order (for winsock) */
#include <srtp.h>
#include "zrtp.h"
struct zrtp_srtp_ctx
{
srtp_t outgoing_srtp;
srtp_t incoming_srtp;
};
/*---------------------------------------------------------------------------*/
void init_policy(crypto_policy_t *sp, zrtp_srtp_policy_t *zp)
{
//TODO: make incoming policy crypto algorithm check for David A. McGrew's implementation support
/* there are no another appropriate ciphers in the David A. McGrew's implementation yet */
sp->cipher_type = AES_128_ICM;
sp->cipher_key_len = zp->cipher_key_len;
sp->auth_type = HMAC_SHA1;
sp->auth_key_len = zp->auth_key_len;
sp->auth_tag_len = zp->auth_tag_len->tag_length ? zp->auth_tag_len->tag_length : 10;
sp->sec_serv = sec_serv_conf_and_auth;
}
/*---------------------------------------------------------------------------*/
zrtp_status_t create_srtp_stream( srtp_t *srtp_stream,
zrtp_srtp_profile_t *profile,
ssrc_type_t ssrc_type )
{
srtp_policy_t policy;
uint8_t *tmp_key;
init_policy(&policy.rtp, &profile->rtp_policy);
init_policy(&policy.rtcp, &profile->rtcp_policy);
policy.ssrc.type = ssrc_type;
policy.ssrc.value = 0;
/* David A. McGrew's implementation uses key and salt as whole buffer, so let's make it */
tmp_key = (uint8_t*)zrtp_sys_alloc(profile->key.length + profile->salt.length);
if(NULL == tmp_key){
return zrtp_status_fail;
}
zrtp_memcpy(tmp_key, profile->key.buffer, profile->key.length);
zrtp_memcpy(tmp_key+profile->key.length, profile->salt.buffer, profile->salt.length);
policy.key = tmp_key;
policy.next = NULL;
/* add salt length to the key length of each policy */
policy.rtp.cipher_key_len += 14;
policy.rtcp.cipher_key_len += 14;
if(err_status_ok != srtp_create(srtp_stream, &policy)){
zrtp_sys_free(tmp_key);
return zrtp_status_fail;
}
zrtp_sys_free(tmp_key);
return zrtp_status_ok;
}
/*===========================================================================*/
/* Public interface */
/*===========================================================================*/
/*---------------------------------------------------------------------------*/
zrtp_status_t zrtp_srtp_init(zrtp_global_ctx_t *zrtp_global)
{
err_status_t s = srtp_init();
return (err_status_ok == s) ? zrtp_status_ok : s;
}
zrtp_status_t zrtp_srtp_down( zrtp_global_ctx_t *zrtp_global )
{
return zrtp_status_ok;
}
/*---------------------------------------------------------------------------*/
zrtp_srtp_ctx_t * zrtp_srtp_create( zrtp_srtp_global_t *srtp_global,
zrtp_srtp_profile_t *inc_profile,
zrtp_srtp_profile_t *out_profile)
{
zrtp_status_t res = zrtp_status_ok;
zrtp_srtp_ctx_t *srtp_ctx = NULL;
if(NULL == inc_profile || NULL == out_profile){
return NULL;
}
do{
srtp_policy_t *policy_head, *policy_next;
srtp_ctx = zrtp_sys_alloc(sizeof(zrtp_srtp_ctx_t));
if(NULL == srtp_ctx){
break;
}
res = create_srtp_stream(&srtp_ctx->incoming_srtp, inc_profile, ssrc_any_inbound);
if(zrtp_status_ok != res){
zrtp_sys_free(srtp_ctx);
srtp_ctx = NULL;
break;
}
res = create_srtp_stream(&srtp_ctx->outgoing_srtp, out_profile, ssrc_any_outbound);
if(zrtp_status_ok != res){
srtp_dealloc(srtp_ctx->incoming_srtp);
zrtp_sys_free(srtp_ctx);
srtp_ctx = NULL;
break;
}
}while(0);
return srtp_ctx;
}
/*---------------------------------------------------------------------------*/
zrtp_status_t zrtp_srtp_destroy( zrtp_srtp_global_t *zrtp_srtp_global,
zrtp_srtp_ctx_t *srtp_ctx )
{
srtp_dealloc(srtp_ctx->incoming_srtp);
srtp_dealloc(srtp_ctx->outgoing_srtp);
zrtp_sys_free(srtp_ctx);
return zrtp_status_ok;
}
/*---------------------------------------------------------------------------*/
zrtp_status_t zrtp_srtp_protect( zrtp_srtp_global_t *srtp_global,
zrtp_srtp_ctx_t *srtp_ctx,
zrtp_rtp_info_t *packet)
{
err_status_t res;
res = srtp_protect(srtp_ctx->outgoing_srtp, packet->packet, packet->length);
if(err_status_ok != res){
return zrtp_status_fail;
}else{
return zrtp_status_ok;
}
}
/*---------------------------------------------------------------------------*/
zrtp_status_t zrtp_srtp_unprotect( zrtp_srtp_global_t *srtp_global,
zrtp_srtp_ctx_t *srtp_ctx,
zrtp_rtp_info_t *packet)
{
err_status_t res;
res = srtp_unprotect(srtp_ctx->incoming_srtp, packet->packet, packet->length);
if(err_status_ok != res){
return zrtp_status_fail;
}else{
return zrtp_status_ok;
}
}
/*---------------------------------------------------------------------------*/
zrtp_status_t zrtp_srtp_protect_rtcp( zrtp_srtp_global_t *srtp_global,
zrtp_srtp_ctx_t *srtp_ctx,
zrtp_rtp_info_t *packet)
{
err_status_t res;
res = srtp_protect_rtcp(srtp_ctx->outgoing_srtp, packet->packet, packet->length);
if(err_status_ok != res){
return zrtp_status_fail;
}else{
return zrtp_status_ok;
}
}
/*---------------------------------------------------------------------------*/
zrtp_status_t zrtp_srtp_unprotect_rtcp( zrtp_srtp_global_t *srtp_global,
zrtp_srtp_ctx_t *srtp_ctx,
zrtp_rtp_info_t *packet)
{
err_status_t res;
res = srtp_unprotect_rtcp(srtp_ctx->incoming_srtp, packet->packet, packet->length);
if(err_status_ok != res){
return zrtp_status_fail;
}else{
return zrtp_status_ok;
}
}
/*----------------------------------------------------------------------------*/
uint64_t make64(uint32_t high, uint32_t low)
{
uint64_t_ res;
uint32_t *p = (uint32_t*)&res;
#if ZRTP_BYTE_ORDER == ZBO_LITTLE_ENDIAN
*p++ = low;
*p = high;
#else
*p++ = high;
*p = low;
#endif
return res;
}
uint32_t high32(uint64_t x)
{
uint32_t *p = &x;
#if ZRTP_BYTE_ORDER == ZBO_LITTLE_ENDIAN
p++;
#endif
return *p;
}
uint32_t low32(uint64_t x)
{
uint32_t *p = &x;
#if ZRTP_BYTE_ORDER == ZBO_BIG_ENDIAN
p++;
#endif
return *p;
}
#endif /*ZRTP_USE_EXTERN_SRTP*/