mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-02-05 18:44:54 +00:00
d2edcad66e
Thanks to Phil Zimmermann for the code and for the license exception we needed to include it. There remains some build system integration work to be done before this code will build properly in the FreeSWITCH tree.
448 lines
13 KiB
C
448 lines
13 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>
|
|
*/
|
|
|
|
#include "zrtp.h"
|
|
|
|
#define _ZTU_ "libzrtp_test"
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static void cipher_test(zrtp_global_t *zrtp)
|
|
{
|
|
zrtp_cipher_t *cipher = zrtp_comp_find(ZRTP_CC_CIPHER, ZRTP_CIPHER_AES128, zrtp);
|
|
if (NULL == cipher) {
|
|
ZRTP_LOG(1, (_ZTU_,"ERROR! can't find ZRTP_CIPHER_AES128 cipher component\n"));
|
|
} else {
|
|
cipher->self_test(cipher, ZRTP_CIPHER_MODE_CFB);
|
|
cipher->self_test(cipher, ZRTP_CIPHER_MODE_CTR);
|
|
}
|
|
|
|
cipher = zrtp_comp_find(ZRTP_CC_CIPHER, ZRTP_CIPHER_AES256, zrtp);
|
|
if (NULL == cipher) {
|
|
ZRTP_LOG(1, (_ZTU_,"ERROR! can't find ZRTP_CIPHER_AES256 cipher component\n"));
|
|
} else {
|
|
cipher->self_test(cipher, ZRTP_CIPHER_MODE_CFB);
|
|
cipher->self_test(cipher, ZRTP_CIPHER_MODE_CTR);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static zrtp_status_t hash_test(zrtp_global_t *zrtp)
|
|
{
|
|
zrtp_hash_t *hash = zrtp_comp_find(ZRTP_CC_HASH, ZRTP_SRTP_HASH_HMAC_SHA1, zrtp);
|
|
if (NULL == hash) {
|
|
ZRTP_LOG(1, (_ZTU_,"ERROR! can't find ZRTP_SRTP_HASH_HMAC_SHA1 component\n"));
|
|
} else {
|
|
hash->hash_self_test(hash);
|
|
hash->hmac_self_test(hash);
|
|
}
|
|
|
|
hash = zrtp_comp_find(ZRTP_CC_HASH, ZRTP_HASH_SHA256, zrtp);
|
|
if (NULL == hash) {
|
|
ZRTP_LOG(1, (_ZTU_,"ERROR! can't find ZRTP_HASH_SHA256 component\n"));
|
|
} else {
|
|
hash->hash_self_test(hash);
|
|
hash->hmac_self_test(hash);
|
|
}
|
|
|
|
hash = zrtp_comp_find(ZRTP_CC_HASH, ZRTP_HASH_SHA384, zrtp);
|
|
if (NULL == hash) {
|
|
ZRTP_LOG(1, (_ZTU_,"ERROR! can't find ZRTP_HASH_SHA384 component\n"));
|
|
} else {
|
|
hash->hash_self_test(hash);
|
|
hash->hmac_self_test(hash);
|
|
}
|
|
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static zrtp_status_t dh_test(zrtp_global_t *zrtp)
|
|
{
|
|
zrtp_pk_scheme_t *pks = zrtp_comp_find(ZRTP_CC_PKT, ZRTP_PKTYPE_DH2048, zrtp);
|
|
if (!pks) {
|
|
ZRTP_LOG(1, (_ZTU_,"ERROR! can't find ZRTP_PKTYPE_DH2048 component\n"));
|
|
} else {
|
|
pks->self_test(pks);
|
|
}
|
|
|
|
pks = zrtp_comp_find(ZRTP_CC_PKT, ZRTP_PKTYPE_DH3072, zrtp);
|
|
if (!pks) {
|
|
ZRTP_LOG(1, (_ZTU_,"ERROR! can't find ZRTP_PKTYPE_DH3072 component\n"));
|
|
} else {
|
|
pks->self_test(pks);
|
|
}
|
|
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static zrtp_status_t ecdh_test(zrtp_global_t *zrtp)
|
|
{
|
|
zrtp_pk_scheme_t *pks = zrtp_comp_find(ZRTP_CC_PKT, ZRTP_PKTYPE_EC256P, zrtp);
|
|
if (!pks) {
|
|
ZRTP_LOG(1, (_ZTU_,"ERROR! can't find ZRTP_PKTYPE_EC256P component\n"));
|
|
} else {
|
|
pks->self_test(pks);
|
|
}
|
|
|
|
pks = zrtp_comp_find(ZRTP_CC_PKT, ZRTP_PKTYPE_EC384P, zrtp);
|
|
if (!pks) {
|
|
ZRTP_LOG(1, (_ZTU_,"ERROR! can't find ZRTP_PKTYPE_EC384P component\n"));
|
|
} else {
|
|
pks->self_test(pks);
|
|
}
|
|
|
|
pks = zrtp_comp_find(ZRTP_CC_PKT, ZRTP_PKTYPE_EC521P, zrtp);
|
|
if (!pks) {
|
|
ZRTP_LOG(1, (_ZTU_,"ERROR! can't find ZRTP_PKTYPE_EC521P component\n"));
|
|
} else {
|
|
pks->self_test(pks);
|
|
}
|
|
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
#if (defined(ZRTP_USE_EXTERN_SRTP) && (ZRTP_USE_EXTERN_SRTP == 1))
|
|
#else
|
|
|
|
static uint8_t dk_master_key[16] = {
|
|
0xE1, 0xF9, 0x7A, 0x0D, 0x3E, 0x01, 0x8B, 0xE0,
|
|
0xD6, 0x4F, 0xA3, 0x2C, 0x06, 0xDE, 0x41, 0x39
|
|
};
|
|
|
|
static uint8_t dk_master_salt[14] = {
|
|
0x0E, 0xC6, 0x75, 0xAD, 0x49, 0x8A, 0xFE, 0xEB,
|
|
0xB6, 0x96, 0x0B, 0x3A, 0xAB, 0xE6
|
|
};
|
|
|
|
|
|
static uint8_t dk_cipher_key[16] = {
|
|
0xC6, 0x1E, 0x7A, 0x93, 0x74, 0x4F, 0x39, 0xEE,
|
|
0x10, 0x73, 0x4A, 0xFE, 0x3F, 0xF7, 0xA0, 0x87
|
|
};
|
|
|
|
static uint8_t dk_cipher_salt[14] = {
|
|
0x30, 0xCB, 0xBC, 0x08, 0x86, 0x3D, 0x8C, 0x85,
|
|
0xD4, 0x9D, 0xB3, 0x4A, 0x9A, 0xE1
|
|
};
|
|
|
|
static uint8_t dk_auth_key[94] = {
|
|
0xCE, 0xBE, 0x32, 0x1F, 0x6F, 0xF7, 0x71, 0x6B,
|
|
0x6F, 0xD4, 0xAB, 0x49, 0xAF, 0x25, 0x6A, 0x15,
|
|
0x6D, 0x38, 0xBA, 0xA4, 0x8F, 0x0A, 0x0A, 0xCF,
|
|
0x3C, 0x34, 0xE2, 0x35, 0x9E, 0x6C, 0xDB, 0xCE,
|
|
0xE0, 0x49, 0x64, 0x6C, 0x43, 0xD9, 0x32, 0x7A,
|
|
0xD1, 0x75, 0x57, 0x8E, 0xF7, 0x22, 0x70, 0x98,
|
|
0x63, 0x71, 0xC1, 0x0C, 0x9A, 0x36, 0x9A, 0xC2,
|
|
0xF9, 0x4A, 0x8C, 0x5F, 0xBC, 0xDD, 0xDC, 0x25,
|
|
0x6D, 0x6E, 0x91, 0x9A, 0x48, 0xB6, 0x10, 0xEF,
|
|
0x17, 0xC2, 0x04, 0x1E, 0x47, 0x40, 0x35, 0x76,
|
|
0x6B, 0x68, 0x64, 0x2C, 0x59, 0xBB, 0xFC, 0x2F,
|
|
0x34, 0xDB, 0x60, 0xDB, 0xDF, 0xB2
|
|
};
|
|
|
|
extern zrtp_dk_ctx *zrtp_dk_init(zrtp_cipher_t *cipher, zrtp_stringn_t *key, zrtp_stringn_t *salt);
|
|
extern zrtp_status_t zrtp_derive_key(zrtp_dk_ctx *ctx, zrtp_srtp_prf_label label, zrtp_stringn_t *result_key);
|
|
extern void zrtp_dk_deinit(zrtp_dk_ctx *ctx);
|
|
|
|
zrtp_status_t hex_cmp(uint8_t *a, uint8_t *b, uint32_t len)
|
|
{
|
|
uint32_t i;
|
|
zrtp_status_t res = zrtp_status_ok;
|
|
for (i = 0; i<len; i++) {
|
|
if (a[i] != b[i]) {
|
|
res = zrtp_status_fail;
|
|
break;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
zrtp_status_t dk_test(zrtp_global_t *zrtp)
|
|
{
|
|
zrtp_status_t res;
|
|
zrtp_string16_t master_key, master_salt, cipher_key, cipher_salt;
|
|
zrtp_string128_t auth_key;
|
|
zrtp_dk_ctx *ctx;
|
|
|
|
zrtp_cipher_t *cipher = zrtp_comp_find(ZRTP_CC_CIPHER, ZRTP_CIPHER_AES128, zrtp);
|
|
|
|
if(NULL == cipher){
|
|
return zrtp_status_fail;
|
|
}
|
|
|
|
master_key.length = master_key.max_length = 16;
|
|
zrtp_memcpy(master_key.buffer, dk_master_key, 16);
|
|
|
|
master_salt.length = 14;
|
|
master_salt.max_length = 16;
|
|
zrtp_memcpy(master_salt.buffer, dk_master_salt, 14);
|
|
|
|
|
|
ctx = zrtp_dk_init(cipher, (zrtp_stringn_t*)&master_key, (zrtp_stringn_t*)&master_salt);
|
|
if(NULL == ctx){
|
|
return zrtp_status_fail;
|
|
}
|
|
|
|
cipher_key.length = 16;
|
|
cipher_key.max_length = 16;
|
|
|
|
zrtp_derive_key(ctx, label_rtp_encryption, (zrtp_stringn_t*)&cipher_key);
|
|
res = hex_cmp((uint8_t*)cipher_key.buffer, dk_cipher_key, cipher_key.length);
|
|
ZRTP_LOG(3, (_ZTU_,"cipher key check...%s\n", zrtp_status_ok==res?"OK":"FAIL"));
|
|
|
|
|
|
cipher_salt.length = 14;
|
|
cipher_salt.max_length = 16;
|
|
|
|
zrtp_derive_key(ctx, label_rtp_salt, (zrtp_stringn_t*)&cipher_salt);
|
|
res = hex_cmp((uint8_t*)cipher_salt.buffer, dk_cipher_salt, cipher_salt.length);
|
|
ZRTP_LOG(3, (_ZTU_,"cipher salt check...%s\n", zrtp_status_ok==res?"OK":"FAIL"));
|
|
|
|
|
|
auth_key.length = 94;
|
|
auth_key.max_length = 128;
|
|
|
|
zrtp_derive_key(ctx, label_rtp_msg_auth, (zrtp_stringn_t*)&auth_key);
|
|
res = hex_cmp((uint8_t*)auth_key.buffer, dk_auth_key, auth_key.length);
|
|
ZRTP_LOG(3, (_ZTU_,"auth key check...%s\n", zrtp_status_ok==res?"OK":"FAIL"));
|
|
|
|
zrtp_dk_deinit(ctx);
|
|
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
#define TEST_MAP_WIDTH 64
|
|
#if TEST_MAP_WIDTH%8
|
|
# define TEST_MAP_WIDTH_BYTES TEST_MAP_WIDTH/8+1
|
|
#else
|
|
# define TEST_MAP_WIDTH_BYTES TEST_MAP_WIDTH/8
|
|
#endif
|
|
|
|
#define FIRST_TEST_MAP_INIT_WIDTH 24
|
|
|
|
extern zrtp_rp_node_t *get_rp_node_non_lock(zrtp_rp_ctx_t *ctx, uint8_t direction, uint32_t ssrc);
|
|
extern zrtp_rp_node_t *add_rp_node(zrtp_srtp_ctx_t *srtp_ctx, zrtp_rp_ctx_t *ctx, uint8_t direction, uint32_t ssrc);
|
|
extern zrtp_status_t zrtp_srtp_rp_check(zrtp_srtp_rp_t *srtp_rp, zrtp_rtp_info_t *packet);
|
|
extern zrtp_status_t zrtp_srtp_rp_add(zrtp_srtp_rp_t *srtp_rp, zrtp_rtp_info_t *packet);
|
|
|
|
void print_map(uint8_t *map, int width_bytes)
|
|
{
|
|
int i;
|
|
for(i=width_bytes-1; i >= 0; i--) {
|
|
ZRTP_LOGC(3, ("%i%i%i%i%i%i%i%i",
|
|
zrtp_bitmap_get_bit(map, 8*i+7),
|
|
zrtp_bitmap_get_bit(map, 8*i+6),
|
|
zrtp_bitmap_get_bit(map, 8*i+5),
|
|
zrtp_bitmap_get_bit(map, 8*i+4),
|
|
zrtp_bitmap_get_bit(map, 8*i+3),
|
|
zrtp_bitmap_get_bit(map, 8*i+2),
|
|
zrtp_bitmap_get_bit(map, 8*i+1),
|
|
zrtp_bitmap_get_bit(map, 8*i+0)));
|
|
}
|
|
ZRTP_LOG(3, (_ZTU_, "\n"));
|
|
}
|
|
|
|
void init_random_map(uint8_t *map, int width, zrtp_global_t *zrtp)
|
|
{
|
|
int i;
|
|
for(i=0; i<width; i++) {
|
|
uint32_t rnd = 0;
|
|
zrtp_randstr(zrtp, (uint8_t*)&rnd, sizeof(rnd));
|
|
if(rnd%10 < 5) {
|
|
zrtp_bitmap_set_bit(map, i);
|
|
} else {
|
|
zrtp_bitmap_clear_bit(map, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void inject_from_map( zrtp_srtp_global_t *srtp_global,
|
|
uint32_t ssrc,
|
|
uint8_t *src_map, uint8_t *dst_map, int width)
|
|
{
|
|
zrtp_rp_node_t *rp_node;
|
|
int i;
|
|
zrtp_rtp_info_t pkt;
|
|
|
|
rp_node = get_rp_node_non_lock(srtp_global->rp_ctx, RP_INCOMING_DIRECTION, ssrc);
|
|
if (NULL == rp_node) {
|
|
return;
|
|
}
|
|
|
|
for (i=0; i< width; i++) {
|
|
if (1 == zrtp_bitmap_get_bit(src_map, i)) {
|
|
pkt.seq = i;
|
|
if (zrtp_status_ok == zrtp_srtp_rp_check(&rp_node->rtp_rp, &pkt)) {
|
|
zrtp_bitmap_set_bit(dst_map, i);
|
|
zrtp_srtp_rp_add(&rp_node->rtp_rp, &pkt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int srtp_replay_protection_test(zrtp_global_t *zrtp)
|
|
{
|
|
int res = 0;
|
|
uint32_t ssrc = 1;
|
|
int i = 0;
|
|
uint8_t test_map[TEST_MAP_WIDTH_BYTES];
|
|
uint8_t result_map[TEST_MAP_WIDTH_BYTES];
|
|
uint8_t tmp_window[ZRTP_SRTP_WINDOW_WIDTH_BYTES];
|
|
uint32_t tmp_seq;
|
|
int delta, shift;
|
|
|
|
zrtp_rp_node_t *rp_node;
|
|
zrtp_srtp_global_t *srtp = zrtp->srtp_global;
|
|
|
|
rp_node = add_rp_node(NULL, srtp->rp_ctx, RP_INCOMING_DIRECTION, ssrc);
|
|
if (NULL == rp_node) {
|
|
return -1;
|
|
}
|
|
|
|
for (i=0; i< TEST_MAP_WIDTH_BYTES; i++) {
|
|
test_map[i] = 0;
|
|
result_map[i] = 0;
|
|
}
|
|
/*
|
|
* 1st test
|
|
* ----------------------------------------------------------------------
|
|
*/
|
|
init_random_map(test_map, FIRST_TEST_MAP_INIT_WIDTH, zrtp);
|
|
inject_from_map(srtp, ssrc, test_map, result_map, TEST_MAP_WIDTH);
|
|
|
|
ZRTP_LOG(3, (_ZTU_,"1st test. Wnd[%i]...\n", ZRTP_SRTP_WINDOW_WIDTH));
|
|
|
|
tmp_seq = rp_node->rtp_rp.seq;
|
|
for (i=0; i<ZRTP_SRTP_WINDOW_WIDTH_BYTES; i++) {
|
|
tmp_window[i] = rp_node->rtp_rp.window[i];
|
|
}
|
|
|
|
delta = tmp_seq-ZRTP_SRTP_WINDOW_WIDTH + 1;
|
|
if (delta > 0) {
|
|
ZRTP_LOG(3, (_ZTU_,"after wnd: (%i;0]\n", delta));
|
|
ZRTP_LOG(3, (_ZTU_,"inside wnd: [%i;%i]\n", tmp_seq, delta));
|
|
} else {
|
|
ZRTP_LOG(3, (_ZTU_,"after wnd: (0;0)\n"));
|
|
ZRTP_LOG(3, (_ZTU_,"inside wnd: [%i;0]\n", tmp_seq));
|
|
}
|
|
|
|
ZRTP_LOG(3, (_ZTU_,"before wnd: [%i;%i)\n", TEST_MAP_WIDTH-1, tmp_seq));
|
|
|
|
ZRTP_LOG(3, (_ZTU_,"Test map: "));
|
|
print_map(test_map, TEST_MAP_WIDTH_BYTES);
|
|
|
|
ZRTP_LOG(3, (_ZTU_,"Res map: "));
|
|
print_map(result_map, TEST_MAP_WIDTH_BYTES);
|
|
|
|
shift = TEST_MAP_WIDTH;
|
|
shift -= rp_node->rtp_rp.seq + 1;
|
|
|
|
ZRTP_LOG(3, (_ZTU_,"Window : "));
|
|
for(i=shift; i > 0; i--){
|
|
ZRTP_LOGC(3, (" "));
|
|
}
|
|
print_map(rp_node->rtp_rp.window, ZRTP_SRTP_WINDOW_WIDTH_BYTES);
|
|
|
|
/*
|
|
* 2nd test
|
|
* ----------------------------------------------------------------------
|
|
*/
|
|
for(i=0; i< TEST_MAP_WIDTH_BYTES; i++){
|
|
test_map[i] = 0;
|
|
result_map[i] = 0;
|
|
}
|
|
|
|
init_random_map(test_map, TEST_MAP_WIDTH, zrtp);
|
|
inject_from_map(srtp, ssrc, test_map, result_map, TEST_MAP_WIDTH);
|
|
|
|
ZRTP_LOG(3, (_ZTU_,"2nd test. Wnd[%i]...\n", ZRTP_SRTP_WINDOW_WIDTH));
|
|
ZRTP_LOG(3, (_ZTU_,"Test map: "));
|
|
print_map(test_map, TEST_MAP_WIDTH_BYTES);
|
|
|
|
ZRTP_LOG(3, (_ZTU_,"Res map: "));
|
|
print_map(result_map, TEST_MAP_WIDTH_BYTES);
|
|
|
|
shift = TEST_MAP_WIDTH;
|
|
shift -= rp_node->rtp_rp.seq + 1;
|
|
|
|
ZRTP_LOG(3, (_ZTU_,"Window : "));
|
|
for (i=shift; i > 0; i--) {
|
|
//zrtp_print_log(ZRTP_LOG_DEBUG, " ");
|
|
}
|
|
print_map(rp_node->rtp_rp.window, ZRTP_SRTP_WINDOW_WIDTH_BYTES);
|
|
|
|
|
|
/*
|
|
in result map:
|
|
- after window we should to have all zeroes
|
|
- into the window we should have ones only if window have zero at appropriate position
|
|
- before window we should have equal values of test map and result map bits
|
|
*/
|
|
for (i=0; i < TEST_MAP_WIDTH; i++) {
|
|
if (delta > 0 && i < delta) {
|
|
/* After window */
|
|
if (0 != zrtp_bitmap_get_bit(result_map, i)) {
|
|
ZRTP_LOG(3, (_ZTU_,"After window. %i bit should be 0\n", i));
|
|
res = -1;
|
|
}
|
|
} else if (i <= (int)tmp_seq && i >= delta) {
|
|
/* inside window */
|
|
|
|
/* check window filtering */
|
|
if(1 == zrtp_bitmap_get_bit(result_map, i)) {
|
|
if (1 == zrtp_bitmap_get_bit(tmp_window, i - (tmp_seq-ZRTP_SRTP_WINDOW_WIDTH) - 1)) {
|
|
ZRTP_LOG(3, (_ZTU_,"Inside window. Window filtering fail. %i bit should be 0\n", i));
|
|
res = -1;
|
|
}
|
|
}
|
|
/* check test vs result maps */
|
|
if ( zrtp_bitmap_get_bit(result_map, i) != zrtp_bitmap_get_bit(test_map, i) &&
|
|
!zrtp_bitmap_get_bit(tmp_window, i - (tmp_seq-ZRTP_SRTP_WINDOW_WIDTH) - 1)) {
|
|
ZRTP_LOG(3, (_ZTU_, "Inside window. Test map isn't equal to result at bit %i\n", i));
|
|
res = -1;
|
|
}
|
|
|
|
} else {
|
|
/* after window */
|
|
if (zrtp_bitmap_get_bit(result_map, i) != zrtp_bitmap_get_bit(test_map, i)) {
|
|
ZRTP_LOG(3, (_ZTU_,"Before window. Test map isn't equal to result at bit %i\n", i));
|
|
res = -1;
|
|
}
|
|
}
|
|
}
|
|
if (0 == res) {
|
|
ZRTP_LOG(3, (_ZTU_,"Test passed successfully\n"));
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
void zrtp_test_crypto(zrtp_global_t* zrtp)
|
|
{
|
|
ZRTP_LOG(3, (_ZTU_,"====================CIPHERS TESTS====================\n"));
|
|
cipher_test(zrtp);
|
|
ZRTP_LOG(3, (_ZTU_,"=====================HASHES TESTS====================\n"));
|
|
hash_test(zrtp);
|
|
ZRTP_LOG(3, (_ZTU_,"================PUBLIC KEY SCHEMES TESTS==============\n"));
|
|
dh_test(zrtp);
|
|
ecdh_test(zrtp);
|
|
ZRTP_LOG(3, (_ZTU_,"===============SRTP Key derivation TESTS==============\n"));
|
|
dk_test(zrtp);
|
|
ZRTP_LOG(3, (_ZTU_,"==============SRTP Replay protection TESTS============\n")) ;
|
|
srtp_replay_protection_test(zrtp);
|
|
}
|